大厂Android面试秘籍:Activity 与 Fragment 交互(九)

454 阅读16分钟

Android 的 Activity 与 Fragment 交互模块深度剖析

本人掘金号,欢迎点击关注:掘金号地址

本人公众号,欢迎点击关注:公众号地址

一、引言

在 Android 开发中,Activity 和 Fragment 是两个至关重要的组件。Activity 作为 Android 应用的可视化界面容器,为用户提供了与应用交互的窗口;而 Fragment 则是 Activity 中的模块化组件,能够实现界面的灵活组合和复用。Activity 与 Fragment 之间的交互机制是 Android 开发中不可或缺的一部分,它使得开发者可以构建出更加复杂、灵活且富有交互性的应用界面。

本博客将从源码级别深入分析 Android 的 Activity 与 Fragment 交互模块,详细探讨它们之间各种交互方式的实现原理,帮助开发者更好地理解和运用这一重要机制。

二、Activity 与 Fragment 基础概念回顾

2.1 Activity 概述

Activity 是 Android 应用中最基本的组件之一,它代表了一个具有用户界面的单屏。每个 Activity 都有自己的生命周期,从创建、启动、暂停、恢复到销毁,开发者可以通过重写相应的生命周期方法来实现特定的逻辑。

以下是一个简单的 Activity 示例:

java

import android.app.Activity;
import android.os.Bundle;

// 自定义 Activity 类,继承自 Activity
public class MainActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // 调用父类的 onCreate 方法
        super.onCreate(savedInstanceState);
        // 设置 Activity 的布局文件
        setContentView(R.layout.activity_main);
    }
}

在上述代码中,onCreate 方法是 Activity 生命周期中的一个重要方法,它在 Activity 首次创建时被调用。在该方法中,我们调用了 setContentView 方法来设置 Activity 的布局文件。

2.2 Fragment 概述

Fragment 是 Android 3.0(API 级别 11)引入的一个概念,它可以被看作是 Activity 中的一个子模块,有自己的生命周期和布局。Fragment 可以动态地添加、替换和移除,使得界面的管理更加灵活。

以下是一个简单的 Fragment 示例:

java

import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.fragment.app.Fragment;

// 自定义 Fragment 类,继承自 Fragment
public class MyFragment extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // 加载 Fragment 的布局文件
        return inflater.inflate(R.layout.fragment_my, container, false);
    }
}

在上述代码中,onCreateView 方法是 Fragment 生命周期中的一个重要方法,它在 Fragment 创建视图时被调用。在该方法中,我们使用 LayoutInflater 来加载 Fragment 的布局文件。

2.3 Activity 与 Fragment 的关系

Fragment 必须依赖于 Activity 而存在,它的生命周期受到 Activity 生命周期的影响。一个 Activity 可以包含多个 Fragment,通过 FragmentManager 来管理这些 Fragment。Fragment 可以与 Activity 进行交互,实现数据的传递和界面的更新。

三、Activity 向 Fragment 传递数据

3.1 使用 Bundle 传递数据

在 Activity 中创建 Fragment 时,可以通过 Bundle 对象来传递数据。Bundle 是一个键值对的集合,类似于 Map,可以存储各种基本数据类型和可序列化的对象。

以下是一个 Activity 向 Fragment 传递数据的示例:

java

import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.fragment.app.Fragment;

// 自定义 Fragment 类,继承自 Fragment
public class DataReceiverFragment extends Fragment {
    private static final String ARG_DATA = "data";
    private String mData;

    // 静态工厂方法,用于创建 Fragment 实例并传递数据
    public static DataReceiverFragment newInstance(String data) {
        DataReceiverFragment fragment = new DataReceiverFragment();
        Bundle args = new Bundle();
        // 将数据存入 Bundle 中
        args.putString(ARG_DATA, data);
        // 将 Bundle 设置为 Fragment 的参数
        fragment.setArguments(args);
        return fragment;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (getArguments() != null) {
            // 从 Bundle 中获取数据
            mData = getArguments().getString(ARG_DATA);
        }
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // 加载 Fragment 的布局文件
        View view = inflater.inflate(R.layout.fragment_data_receiver, container, false);
        TextView textView = view.findViewById(R.id.textView);
        // 将获取到的数据显示在 TextView 上
        textView.setText(mData);
        return view;
    }
}

在 Activity 中使用该 Fragment 并传递数据:

java

import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.FragmentTransaction;

// 自定义 Activity 类,继承自 AppCompatActivity
public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // 创建要传递的数据
        String data = "Hello from Activity!";
        // 创建 Fragment 实例并传递数据
        DataReceiverFragment fragment = DataReceiverFragment.newInstance(data);
        // 获取 FragmentManager
        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
        // 将 Fragment 添加到布局中
        transaction.add(R.id.fragment_container, fragment);
        // 提交事务
        transaction.commit();
    }
}
3.1.1 源码分析

在 DataReceiverFragment 中,newInstance 方法是一个静态工厂方法,用于创建 DataReceiverFragment 的实例并传递数据。在该方法中,我们创建了一个 Bundle 对象,并将数据存入其中,然后调用 setArguments 方法将 Bundle 设置为 Fragment 的参数。

在 onCreate 方法中,我们通过 getArguments 方法获取之前设置的 Bundle,并从中取出数据。

在 MainActivity 中,我们创建了要传递的数据,并调用 DataReceiverFragment 的 newInstance 方法创建 Fragment 实例。然后,我们获取 FragmentManager 并开始一个事务,将 Fragment 添加到布局中,最后提交事务。

3.2 通过接口回调传递数据

Activity 可以通过接口回调的方式向 Fragment 传递数据。具体步骤如下:

  1. 在 Fragment 中定义一个接口。

  2. 在 Activity 中实现该接口。

  3. 在 Fragment 中设置接口的实现对象。

  4. 在 Activity 中调用接口的方法传递数据。

以下是一个示例:

java

import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.fragment.app.Fragment;

// 自定义 Fragment 类,继承自 Fragment
public class CallbackReceiverFragment extends Fragment {
    private OnDataReceivedListener mListener;
    private TextView mTextView;

    // 定义接口
    public interface OnDataReceivedListener {
        void onDataReceived(String data);
    }

    // 设置接口的实现对象
    public void setOnDataReceivedListener(OnDataReceivedListener listener) {
        mListener = listener;
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // 加载 Fragment 的布局文件
        View view = inflater.inflate(R.layout.fragment_callback_receiver, container, false);
        mTextView = view.findViewById(R.id.textView);
        return view;
    }

    // 处理接收到的数据
    public void handleData(String data) {
        if (mTextView != null) {
            mTextView.setText(data);
        }
    }
}

在 Activity 中实现该接口并传递数据:

java

import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;

// 自定义 Activity 类,继承自 AppCompatActivity
public class MainActivity extends AppCompatActivity implements CallbackReceiverFragment.OnDataReceivedListener {
    private CallbackReceiverFragment mFragment;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // 创建 Fragment 实例
        mFragment = new CallbackReceiverFragment();
        // 设置接口的实现对象
        mFragment.setOnDataReceivedListener(this);
        // 获取 FragmentManager
        getSupportFragmentManager().beginTransaction()
               .add(R.id.fragment_container, mFragment)
               .commit();

        // 传递数据
        sendDataToFragment();
    }

    private void sendDataToFragment() {
        String data = "Hello from Activity via callback!";
        // 调用接口的方法传递数据
        onDataReceived(data);
    }

    @Override
    public void onDataReceived(String data) {
        // 调用 Fragment 的方法处理数据
        mFragment.handleData(data);
    }
}
3.2.1 源码分析

在 CallbackReceiverFragment 中,我们定义了一个 OnDataReceivedListener 接口,该接口包含一个 onDataReceived 方法,用于接收数据。

setOnDataReceivedListener 方法用于设置接口的实现对象。

handleData 方法用于处理接收到的数据,将数据显示在 TextView 上。

在 MainActivity 中,我们实现了 OnDataReceivedListener 接口,并在 onCreate 方法中创建了 CallbackReceiverFragment 实例,设置了接口的实现对象。

sendDataToFragment 方法用于创建要传递的数据,并调用 onDataReceived 方法传递数据。

onDataReceived 方法中,我们调用 CallbackReceiverFragment 的 handleData 方法处理数据。

四、Fragment 向 Activity 传递数据

4.1 使用接口回调传递数据

Fragment 向 Activity 传递数据最常用的方式也是接口回调。具体步骤如下:

  1. 在 Fragment 中定义一个接口。

  2. 在 Activity 中实现该接口。

  3. 在 Fragment 中设置接口的实现对象。

  4. 在 Fragment 中调用接口的方法传递数据。

以下是一个示例:

java

import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import androidx.fragment.app.Fragment;

// 自定义 Fragment 类,继承自 Fragment
public class DataSenderFragment extends Fragment {
    private OnDataSendListener mListener;
    private Button mSendButton;

    // 定义接口
    public interface OnDataSendListener {
        void onDataSent(String data);
    }

    // 设置接口的实现对象
    public void setOnDataSendListener(OnDataSendListener listener) {
        mListener = listener;
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // 加载 Fragment 的布局文件
        View view = inflater.inflate(R.layout.fragment_data_sender, container, false);
        mSendButton = view.findViewById(R.id.sendButton);
        // 为按钮设置点击事件监听器
        mSendButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 传递数据
                sendDataToActivity();
            }
        });
        return view;
    }

    private void sendDataToActivity() {
        String data = "Hello from Fragment!";
        if (mListener != null) {
            // 调用接口的方法传递数据
            mListener.onDataSent(data);
        }
    }
}

在 Activity 中实现该接口并处理数据:

java

import android.os.Bundle;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;

// 自定义 Activity 类,继承自 AppCompatActivity
public class MainActivity extends AppCompatActivity implements DataSenderFragment.OnDataSendListener {
    private TextView mTextView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mTextView = findViewById(R.id.textView);
        // 创建 Fragment 实例
        DataSenderFragment fragment = new DataSenderFragment();
        // 设置接口的实现对象
        fragment.setOnDataSendListener(this);
        // 获取 FragmentManager
        getSupportFragmentManager().beginTransaction()
               .add(R.id.fragment_container, fragment)
               .commit();
    }

    @Override
    public void onDataSent(String data) {
        // 处理接收到的数据
        mTextView.setText(data);
    }
}
4.1.1 源码分析

在 DataSenderFragment 中,我们定义了一个 OnDataSendListener 接口,该接口包含一个 onDataSent 方法,用于传递数据。

setOnDataSendListener 方法用于设置接口的实现对象。

sendDataToActivity 方法用于创建要传递的数据,并调用接口的 onDataSent 方法传递数据。

在 MainActivity 中,我们实现了 OnDataSendListener 接口,并在 onCreate 方法中创建了 DataSenderFragment 实例,设置了接口的实现对象。

onDataSent 方法用于处理接收到的数据,将数据显示在 TextView 上。

4.2 通过 Activity 的公共方法传递数据

Fragment 还可以通过调用 Activity 的公共方法来传递数据。具体步骤如下:

  1. 在 Activity 中定义公共方法。

  2. 在 Fragment 中获取 Activity 的实例。

  3. 调用 Activity 的公共方法传递数据。

以下是一个示例:

java

import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import androidx.fragment.app.Fragment;

// 自定义 Fragment 类,继承自 Fragment
public class MethodCallSenderFragment extends Fragment {
    private Button mSendButton;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // 加载 Fragment 的布局文件
        View view = inflater.inflate(R.layout.fragment_method_call_sender, container, false);
        mSendButton = view.findViewById(R.id.sendButton);
        // 为按钮设置点击事件监听器
        mSendButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 传递数据
                sendDataToActivity();
            }
        });
        return view;
    }

    private void sendDataToActivity() {
        String data = "Hello from Fragment via method call!";
        // 获取 Activity 的实例
        MainActivity activity = (MainActivity) getActivity();
        if (activity != null) {
            // 调用 Activity 的公共方法传递数据
            activity.receiveData(data);
        }
    }
}

在 Activity 中定义公共方法并处理数据:

java

import android.os.Bundle;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;

// 自定义 Activity 类,继承自 AppCompatActivity
public class MainActivity extends AppCompatActivity {
    private TextView mTextView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mTextView = findViewById(R.id.textView);
        // 创建 Fragment 实例
        MethodCallSenderFragment fragment = new MethodCallSenderFragment();
        // 获取 FragmentManager
        getSupportFragmentManager().beginTransaction()
               .add(R.id.fragment_container, fragment)
               .commit();
    }

    // 公共方法,用于接收数据
    public void receiveData(String data) {
        // 处理接收到的数据
        mTextView.setText(data);
    }
}
4.2.1 源码分析

在 MethodCallSenderFragment 中,sendDataToActivity 方法用于创建要传递的数据,并通过 getActivity 方法获取 Activity 的实例。

然后,我们将获取到的 Activity 实例强制转换为 MainActivity 类型,并调用其 receiveData 方法传递数据。

在 MainActivity 中,我们定义了一个公共方法 receiveData,用于接收数据并将其显示在 TextView 上。

五、Activity 与 Fragment 之间的事件交互

5.1 Activity 监听 Fragment 的事件

Activity 可以监听 Fragment 中的事件,例如按钮点击事件。通过接口回调的方式,Fragment 可以将事件传递给 Activity。

以下是一个示例:

java

import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import androidx.fragment.app.Fragment;

// 自定义 Fragment 类,继承自 Fragment
public class EventSenderFragment extends Fragment {
    private OnButtonClickListener mListener;
    private Button mButton;

    // 定义接口
    public interface OnButtonClickListener {
        void onButtonClicked();
    }

    // 设置接口的实现对象
    public void setOnButtonClickListener(OnButtonClickListener listener) {
        mListener = listener;
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // 加载 Fragment 的布局文件
        View view = inflater.inflate(R.layout.fragment_event_sender, container, false);
        mButton = view.findViewById(R.id.button);
        // 为按钮设置点击事件监听器
        mButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 触发事件
                if (mListener != null) {
                    mListener.onButtonClicked();
                }
            }
        });
        return view;
    }
}

在 Activity 中实现该接口并处理事件:

java

import android.os.Bundle;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;

// 自定义 Activity 类,继承自 AppCompatActivity
public class MainActivity extends AppCompatActivity implements EventSenderFragment.OnButtonClickListener {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // 创建 Fragment 实例
        EventSenderFragment fragment = new EventSenderFragment();
        // 设置接口的实现对象
        fragment.setOnButtonClickListener(this);
        // 获取 FragmentManager
        getSupportFragmentManager().beginTransaction()
               .add(R.id.fragment_container, fragment)
               .commit();
    }

    @Override
    public void onButtonClicked() {
        // 处理事件
        Toast.makeText(this, "Button in Fragment is clicked!", Toast.LENGTH_SHORT).show();
    }
}
5.1.1 源码分析

在 EventSenderFragment 中,我们定义了一个 OnButtonClickListener 接口,该接口包含一个 onButtonClicked 方法,用于处理按钮点击事件。

setOnButtonClickListener 方法用于设置接口的实现对象。

在按钮的点击事件监听器中,我们调用接口的 onButtonClicked 方法触发事件。

在 MainActivity 中,我们实现了 OnButtonClickListener 接口,并在 onCreate 方法中创建了 EventSenderFragment 实例,设置了接口的实现对象。

onButtonClicked 方法用于处理按钮点击事件,显示一个 Toast 消息。

5.2 Fragment 监听 Activity 的事件

Fragment 也可以监听 Activity 中的事件,例如 Activity 的菜单点击事件。通过在 Fragment 中重写 onActivityCreated 方法,获取 Activity 的菜单,并为菜单项设置点击事件监听器。

以下是一个示例:

java

import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
import androidx.fragment.app.Fragment;

// 自定义 Fragment 类,继承自 Fragment
public class EventReceiverFragment extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // 加载 Fragment 的布局文件
        return inflater.inflate(R.layout.fragment_event_receiver, container, false);
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        // 获取 Activity 的菜单
        Menu menu = getActivity().getMenuInflater().inflate(R.menu.main_menu, null);
        // 为菜单项设置点击事件监听器
        MenuItem item = menu.findItem(R.id.menu_item);
        item.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
            @Override
            public boolean onMenuItemClick(MenuItem item) {
                // 处理事件
                Toast.makeText(getActivity(), "Menu item in Activity is clicked!", Toast.LENGTH_SHORT).show();
                return true;
            }
        });
    }
}

在 Activity 中加载菜单:

java

import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.FragmentTransaction;

// 自定义 Activity 类,继承自 AppCompatActivity
public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // 创建 Fragment 实例
        EventReceiverFragment fragment = new EventReceiverFragment();
        // 获取 FragmentManager
        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
        // 将 Fragment 添加到布局中
        transaction.add(R.id.fragment_container, fragment);
        // 提交事务
        transaction.commit();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // 加载菜单资源
        getMenuInflater().inflate(R.menu.main_menu, menu);
        return true;
    }
}
5.2.1 源码分析

在 EventReceiverFragment 中,onActivityCreated 方法在 Activity 创建完成后被调用。在该方法中,我们获取 Activity 的菜单,并为菜单项设置点击事件监听器。

在点击事件监听器中,我们处理菜单项的点击事件,显示一个 Toast 消息。

在 MainActivity 中,onCreateOptionsMenu 方法用于加载菜单资源。

六、使用 ViewModel 进行 Activity 与 Fragment 之间的数据共享

6.1 ViewModel 概述

ViewModel 是 Android Architecture Components 中的一个组件,它用于存储和管理与 UI 相关的数据,并且在配置更改(如屏幕旋转)时保持数据的一致性。ViewModel 可以在 Activity 和 Fragment 之间共享数据,避免了数据在 Activity 和 Fragment 之间的重复传递。

6.2 使用 ViewModel 共享数据的示例

以下是一个使用 ViewModel 进行 Activity 与 Fragment 之间数据共享的示例:

java

import androidx.lifecycle.ViewModel;

// 自定义 ViewModel 类,继承自 ViewModel
public class SharedViewModel extends ViewModel {
    private String mData;

    // 获取数据
    public String getData() {
        return mData;
    }

    // 设置数据
    public void setData(String data) {
        mData = data;
    }
}

在 Activity 中使用 ViewModel 并设置数据:

java

import android.os.Bundle;
import android.widget.Button;
import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.ViewModelProvider;

// 自定义 Activity 类,继承自 AppCompatActivity
public class MainActivity extends AppCompatActivity {
    private SharedViewModel mViewModel;
    private Button mSetDataButton;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // 获取 ViewModel 实例
        mViewModel = new ViewModelProvider(this).get(SharedViewModel.class);
        mSetDataButton = findViewById(R.id.setDataButton);
        // 为按钮设置点击事件监听器
        mSetDataButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 设置数据
                mViewModel.setData("Hello from Activity via ViewModel!");
            }
        });
    }
}

在 Fragment 中使用 ViewModel 并获取数据:

java

import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;

// 自定义 Fragment 类,继承自 Fragment
public class DataReceiverViewModelFragment extends Fragment {
    private SharedViewModel mViewModel;
    private TextView mTextView;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // 加载 Fragment 的布局文件
        View view = inflater.inflate(R.layout.fragment_data_receiver_viewmodel, container, false);
        mTextView = view.findViewById(R.id.textView);
        // 获取 ViewModel 实例
        mViewModel = new ViewModelProvider(requireActivity()).get(SharedViewModel.class);
        // 观察数据的变化
        mViewModel.getData().observe(getViewLifecycleOwner(), new Observer<String>() {
            @Override
            public void onChanged(String data) {
                // 处理数据的变化
                mTextView.setText(data);
            }
        });
        return view;
    }
}
6.2.1 源码分析

在 SharedViewModel 中,我们定义了一个 mData 变量,并提供了 getData 和 setData 方法来获取和设置数据。

在 MainActivity 中,我们通过 ViewModelProvider 获取 SharedViewModel 的实例,并在按钮的点击事件监听器中调用 setData 方法设置数据。

在 DataReceiverViewModelFragment 中,我们同样通过 ViewModelProvider 获取 SharedViewModel 的实例,并使用 observe 方法观察数据的变化。当数据发生变化时,onChanged 方法会被调用,我们在该方法中更新 TextView 的文本。

七、Activity 与 Fragment 交互的生命周期影响

7.1 Activity 生命周期对 Fragment 的影响

Activity 的生命周期会直接影响 Fragment 的生命周期。当 Activity 进入不同的生命周期状态时,Fragment 也会相应地进入不同的生命周期状态。

例如,当 Activity 的 onCreate 方法被调用时,Fragment 的 onAttachonCreate 和 onCreateView 方法会依次被调用。

以下是 Activity 和 Fragment 生命周期方法的调用顺序示例:

java

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;

// 自定义 Activity 类,继承自 FragmentActivity
public class LifecycleActivity extends FragmentActivity {
    private static final String TAG = "LifecycleActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_lifecycle);
        Log.d(TAG, "Activity onCreate");

        // 创建 Fragment 实例
        LifecycleFragment fragment = new LifecycleFragment();
        // 获取 FragmentManager
        FragmentManager manager = getSupportFragmentManager();
        // 开始事务
        FragmentTransaction transaction = manager.beginTransaction();
        // 添加 Fragment
        transaction.add(R.id.fragment_container, fragment);
        // 提交事务
        transaction.commit();
    }

    @Override
    protected void onStart() {
        super.onStart();
        Log.d(TAG, "Activity onStart");
    }

    @Override
    protected void onResume() {
        super.onResume();
        Log.d(TAG, "Activity onResume");
    }

    @Override
    protected void onPause() {
        super.onPause();
        Log.d(TAG, "Activity onPause");
    }

    @Override
    protected void onStop() {
        super.onStop();
        Log.d(TAG, "Activity onStop");
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "Activity onDestroy");
    }
}

// 自定义 Fragment 类,继承自 Fragment
public class LifecycleFragment extends Fragment {
    private static final String TAG = "LifecycleFragment";

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        Log.d(TAG, "Fragment onAttach");
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d(TAG, "Fragment onCreate");
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        Log.d(TAG, "Fragment onCreateView");
        return inflater.inflate(R.layout.fragment_lifecycle, container, false);
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        Log.d(TAG, "Fragment onActivityCreated");
    }

    @Override
    public void onStart() {
        super.onStart();
        Log.d(TAG, "Fragment onStart");
    }

    @Override
    public void onResume() {
        super.onResume();
        Log.d(TAG, "Fragment onResume");
    }

    @Override
    public void onPause() {
        super.onPause();
        Log.d(TAG, "Fragment onPause");
    }

    @Override
    public void onStop() {
        super.onStop();
        Log.d(TAG, "Fragment onStop");
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        Log.d(TAG, "Fragment onDestroyView");
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "Fragment onDestroy");
    }

    @Override
    public void onDetach() {
        super.onDetach();
        Log.d(TAG, "Fragment onDetach");
    }
}
7.1.1 源码分析

在 LifecycleActivity 中,我们重写了 Activity 的生命周期方法,并在每个方法中打印日志。

在 onCreate 方法中,我们创建了 LifecycleFragment 实例,并将其添加到布局中。

在 LifecycleFragment 中,我们重写了 Fragment 的生命周期方法,并在每个方法中打印日志。

通过运行该示例,我们可以观察到 Activity 和 Fragment 生命周期方法的调用顺序。

7.2 Fragment 生命周期对 Activity 交互的影响

Fragment 的生命周期也会影响 Activity 与 Fragment 之间的交互。例如,在 Fragment 的 onDestroyView 方法中,视图已经被销毁,如果此时 Activity 尝试访问 Fragment 的视图,会导致空指针异常。

因此,在进行 Activity 与 Fragment 交互时,需要注意 Fragment 的生命周期状态,确保在合适的时机进行交互。

八、总结与展望

8.1 总结

通过对 Android 的 Activity 与 Fragment 交互模块的深入分析,我们了解了多种 Activity 与 Fragment 之间的交互方式,包括使用 Bundle 传递数据、接口回调、公共方法调用、ViewModel 数据共享等。

每种交互方式都有其适用场景和优缺点。使用 Bundle 传递数据简单直接,适用于在创建 Fragment 时传递静态数据;接口回调方式灵活,适用于传递事件和动态数据;公共方法调用方式直观,适用于 Fragment 直接调用 Activity 的方法;ViewModel 数据共享方式适用于在 Activity 和 Fragment 之间共享动态数据,并且可以在配置更改时保持数据的一致性。

同时,我们还分析了 Activity 和 Fragment 的生命周期对交互的影响,了解到在进行交互时需要注意生命周期状态,避免出现空指针异常等问题。

8.2 展望

随着 Android 开发技术的不断发展,Activity 与 Fragment 交互模块可能会有更多的优化和改进。例如,可能会出现更简洁、更高效的交互方式,或者对现有交互方式进行进一步的封装和简化。

在性能方面,可能会对交互过程中的数据传递和事件处理进行优化,减少不必要的内存开销和性能损耗。

在兼容性方面,会更好地支持不同版本的 Android 系统,确保开发者在不同的设备上都能稳定地使用 Activity 与 Fragment 交互功能。

此外,随着 Android 应用的复杂度不断增加,Activity 与 Fragment 交互模块可能会与其他组件和技术进行更深入的融合,为开发者提供更强大的开发工具和功能。

总之,Activity 与 Fragment 交互模块是 Android 开发中非常重要的一部分,深入理解和掌握其原理和使用方法,对于开发高质量的 Android 应用具有重要意义。开发者需要不断关注技术的发展,灵活运用各种交互方式,以满足不同的开发需求。