android fragment ,fragment中的控件操作 通信

本文详细介绍了Android中Fragment的生命周期方法及其应用场景,包括Activity与Fragment之间的数据传递方式、Fragment的创建与使用方法,并深入探讨了Fragment懒加载的概念及其实现方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 生命流程图:

onStart():Fragment无焦点但可见时,调用此方法.

onResume(): Fragment获取焦点且可见时,调用此方法.

onPause(): Fragment失去焦点但可见时,调用此方法.

onStop(): Fragment不可见时,调用此方法.

Activity1和Fragment1对应的生命启动关系:

Activity向Fragment传值:

  • 接口回调
  • bundle(setArguments(bundle))
  • 通过 ViewModel 共享数据
//定义viewmodel
public class SharedViewModel extends ViewModel {
    private MutableLiveData<String> data = new MutableLiveData<>();
    public LiveData<String> getData() {
        return data;
    }
    public void setData(String newData) {
        data.setValue(newData);
    }
}


//在 Activity 中使用 ViewModel:
public class MainActivity extends AppCompatActivity {
    private SharedViewModel viewModel;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        viewModel = new ViewModelProvider(this).get(SharedViewModel.class);
        // 设置数据
        viewModel.setData("这是Activity设置的数据");
    }
}

//在 Fragment 中使用 ViewModel:
public class MyFragment extends Fragment {
    private SharedViewModel viewModel;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        viewModel = new ViewModelProvider(requireActivity()).get(SharedViewModel.class);
        viewModel.getData().observe(getViewLifecycleOwner(), new Observer<String>() {
            @Override
            public void onChanged(String s) {
                // 在这里处理接收到的数据变化
            }
        });
    }
}

Fragment和Fragment之间传值:

  • 接口回调

  • 使用 ViewModel 共享数据:ViewModel 的生命周期是和 Activity 相关联的,多个 Fragment 如果属于同一个 Activity,那么可以共享同一个 ViewModel 实例来实现数据的共享与通信。比如有一个记录用户登录状态的 ViewModel,Fragment A 用于登录操作改变登录状态值,Fragment B 可以通过观察这个 ViewModel 里的状态值来实时更新界面显示等,从而实现两者之间基于数据变化的通信。

  • 利用 FragmentManager 和 Tag:可以通过 FragmentManager 来获取已经添加到 Activity 中的 Fragment 实例,进而直接调用对方的公开方法来传递数据等进行通信。例如,在 Activity 中通过 FragmentManager和tag(findFragmentByTag) 找到 Fragment B 实例,然后让 Fragment A 去调用 Fragment B 的相应方法传递一些必要信息。不过这种方式要注意 Fragment 的生命周期以及是否已经添加等情况,避免空指针等问题出现。

  • 通过 Activity 中转:因为 Fragment 都是依附于 Activity 存在的,所以可以先让一个 Fragment 通过接口回调等方式将数据传递给所属的 Activity,然后 Activity 再把数据传递给另一个 Fragment。例如,Fragment A 有个按钮点击事件,点击后想把相关信息传递给 Fragment B,Fragment A 可以定义接口并让 Activity 实现该接口,点击时调用接口方法通知 Activity,Activity 再去获取 Fragment B 实例并传递数据过去。

Fragment 不能重写构造方法并往里面传参数的原因

系统恢复机制相关

当系统配置发生变化(比如屏幕旋转)等情况时,Android 系统会自动尝试恢复 Fragment 的实例。系统在恢复时是通过默认的无参构造方法来创建 Fragment 实例的,它并不知道你自定义的带参数构造方法。如果重写了构造方法并传参,系统恢复时按默认方式创建就无法正确传递那些自定义参数,很可能导致 Fragment 状态异常、数据丢失或者出现运行时错误。

如何解决这个传参问题:

1. 使用 setArguments() 传递参数

核心原理
  • Fragment 重建时,系统会自动恢复 Bundle 中的参数。

  • 通过 getArguments() 获取参数,而非构造函数。

// 创建 Fragment 并传递参数
public static MyFragment newInstance(String param1, int param2) {
    MyFragment fragment = new MyFragment(); // 使用无参构造
    Bundle args = new Bundle();
    args.putString("key1", param1);
    args.putInt("key2", param2);
    fragment.setArguments(args);
    return fragment;
}

// 在 Fragment 中获取参数
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    if (getArguments() != null) {
        String param1 = getArguments().getString("key1");
        int param2 = getArguments().getInt("key2");
    }
}

2. 使用 ViewModel 保存数据(推荐结合使用)

核心原理
  • ViewModel 的生命周期长于 Fragment,重建时数据不会丢失。

  • 适合保存动态数据或复杂对象。

// 在 Fragment 中初始化 ViewModel
private MyViewModel viewModel;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    viewModel = new ViewModelProvider(this).get(MyViewModel.class);
    // 从 ViewModel 获取数据
    String data = viewModel.getData();
}

// ViewModel 类
public class MyViewModel extends ViewModel {
    private String data;

    public String getData() { return data; }
    public void setData(String data) { this.data = data; }
}

3. 通过 onSaveInstanceState() 临时保存状态

适用场景
  • 保存简单的临时状态(如滚动位置、临时标记)。

@Override
public void onSaveInstanceState(@NonNull Bundle outState) {
    super.onSaveInstanceState(outState);
    outState.putString("temp_key", "value");
}

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    if (savedInstanceState != null) {
        String tempValue = savedInstanceState.getString("temp_key");
    }
}

创建fragment的两种方式:

1.静态创建(直接在xml说明fragment<>,且不能被删除)

2.动态创建(可进行多项操作);

使用fragment的方法:(注意最后要commit一下)

1.add即把fragment添加进去(注意fragment栈不能包含两个相同的fragment)

 2.replace即只有一层fragment,每次都是替换操作;

Fragment事务

ViewPager和fragment使用:

初始化adapter时候,传入fragment集合以及记得传入fragmentmanager;

FragmentPageAdapter和FragmentPageStateAdapter区别:

 

getFragmentManager和getSupportFragmentManager区别:

Android3.0以上用getFragmentManager  3.0以下用getSupportFragmentManager;

v4包的fragment兼容Android3.0以下,获取fragmentmanager只能通过getSupportFragmentManager;而 app包的fragment只支持3.0以上,通过获取getFragmentManager获取manager;

fragment中控件的实例化以及点击事件的注册:

1.通过实例化view对象来获取控件,进而注册控件的点击事件

2.直接获取通过getActivity获取context:

 注意要在onActivityCreated中进行这两个操作,而不是onCreateView中,因为activity的onCreate可能还没有执行,那么getActivity得到的是null;

fragment懒加载

1、为什么Fragment要懒加载

    这个原因有点简单,就是想在用户可见的情况下Fragment才进行一系列的逻辑操作,这样减少了手机的内存开销

2、那种场景需要Fragment要懒加载

ViewPager+Fragment联合使用的时候。有时候在ViewPager的第一页有很多网络请求,第二页也还是有很多网络请求。而ViewPager默认情况是进行预加载前后两页(共管理三个页面)的,意思就是ViewPager的第一页和第二页的网络请求都是同时发起的,这种情况下我们手机的内存消耗也多,而网络不好的时候用户体验也不要,于是就想到了Fragment懒加载;

public abstract class BaseFragment extends Fragment implements View.OnClickListener {

    protected View mContentView;
    /**
     * 控件是否初始化完成
     */
    private boolean isViewCreated;
    /**
     * 数据是否已加载完毕
     */
    private boolean isLoadDataCompleted;

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        this.mContentView = inflater.inflate(loadLayoutId(), null);
        initViews();
        bindListener();
        isViewCreated = true;
        return mContentView;
    }


    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        if (isVisibleToUser && isViewCreated)//只有在用户可见以及初始化之后才加载数据
            lazyLoad();
    }

    /**
     * Framgnet重组时候也会跳过onCreate,而onAttach和onActivityCreated还是会被调用
     */
    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        if (getUserVisibleHint())
            lazyLoad();
    }


    /**
     * 懒加载的方法
     */
    protected void lazyLoad() {
        if (!isLoadDataCompleted) {
            initData();
            processLogic();
            isLoadDataCompleted = true;
        }
    }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值