Fragment(一)--Fragment用法常见问题

fragment notes

fragment相关内容包括

基本定义与使用
回退栈内部实现
fragment通信(与activity 与fragment)
DialogFragment
VP + Fragment
嵌套Fragment
懒加载

基本定义与使用(5个)

fragment依赖于Activity,不能独立存在

一个Activity可以有多个Fragment

一个Fragment可以被多个Activity复用

Fragment有自己的生命周期,并能接受输入事件

能在Activity运行时动态添加或删除Fragment

Fragment优势:(3个)

1.模块化Modularity

从此不用在一个Activity写所有的代码。而是把代码写在各自的Fragment中。

2.可重用Resuability
多个Activity可复用同一个Fragment

3.可适配Adaptability
根据硬件的屏幕尺寸和方向选择不同的布局

Fragment核心类:(3个)

Fragment:任何Fragment的基类

FragmentManager:管理Fragment。FM是抽象类,实现类是FragmentManagerImpl

FragmentTransaction:对Fragment操作,包括添加,删除登需要通过事务处理。FT是抽象类,实现类是BackStackRecord.

Nested Fragment(Fragment内部嵌套Fragment的能力)是Android 4.2提出的.support-fragment库可以兼容到1.6。通过getChildFragmentManager()能够获得管理子Fragment的FragmentManager,在子Fragment中可以通过getParentFragment()获得父Fragment。

    public class Fragment1 extends Fragment{

private static String ARG_PARAM = "param_key";

private String mParam;
private Activity mActivity;

public void onAttach(Context context) {
    mActivity = (Activity) context;
    mParam = getArguments().getString(ARG_PARAM);  //获取参数
}

public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View root = inflater.inflate(R.layout.fragment_1, container, false);
    TextView view = root.findViewById(R.id.text);
    view.setText(mParam);
    return root;
}

public static Fragment1 newInstance(String str) {
    Fragment1 frag = new Fragment1();
    Bundle bundle = new Bundle();
    bundle.putString(ARG_PARAM, str);
    fragment.setArguments(bundle);   //设置参数
    return fragment;
}
}

Fragment有很多可以复写的方法,其中最常用的就是onCreateView(),该方法返回Fragment的UI布局,需要注意的是inflate()的第三个参数是false,因为在Fragment内部实现中,会把该布局添加到container中,如果设为true,那么就会重复做两次添加,则会抛如下异常

Caused by: java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.

创建Fragment时传参必须使用setArguments(Bundle b)

如果在创建Fragment时要传入参数,必须要通过setArguments(Bundle bundle)方式添加,而不建议通过为Fragment添加带参数的构造函数,

原因:

因为通过setArguments()方式添加,在由于内存紧张导致Fragment被系统杀掉并恢复(re-instantiate)时能保留这些数据。

这点很重要。否则可能导致严重后果!!!

取参数在onAttached()中取,context上下文也要在该处取

我们可以在Fragment的onAttach()中通过getArguments()获得传进来的参数,并在之后使用这些参数。如果要获取Activity对象,不建议调用getActivity(),而是在onAttach()中将Context对象强转为Activity对象。

在Activity中添加Fragment的方式有两种:

静态添加:在xml中通过的方式添加,缺点是一旦添加就不能在运行时删除。
动态添加:运行时添加,这种方式比较灵活,因此建议使用这种方式。

虽然Fragment能在XML中添加,但是这只是一个语法糖而已,Fragment并不是一个View,而是和Activity同一层次的

1.Activity提供容器
首先Activity需要有一个容器存放Fragment,一般是FrameLayout,因此在Activity的布局文件中加入FrameLayout:

然后在onCreate()中,通过以下代码将Fragment添加进Activity中。

if (bundle == null) {
getSupportFragmentManager().beginTransaction()
    .add(R.id.container, Fragment1.newInstance("hello world"), "f1")
    //.addToBackStack("fname")
    .commit();
}

需要注意的有如下几点:

因为我们使用了support库的Fragment,因此需要使用getSupportFragmentManager()获取FragmentManager。

add()是对Fragment众多操作中的一种,还有remove(), replace()等,第一个参数是根容器的id(FrameLayout的id,即”@id/container”),第二个参数是Fragment对象,第三个参数是fragment的tag名,指定tag的好处是后续我们可以通过Fragment1 frag = getSupportFragmentManager().findFragmentByTag("f1")从FragmentManager中查找Fragment对象。

在一次事务中,可以做多个操作,比如同时做add().remove().replace()。

commit()操作是异步的。内部通过mManager.enqueueAction()加入处理队列。

对应的同步方法为commitNow(),commit()内部会有checkStateLoss()操作,如果开发人员使用不当(比如commit()操作在onSaveInstanceState()之后),可能会抛出异常解决方案和产生分析

commitAllowingStateLoss()方法则是不会抛出异常版本的commit()方法,但是尽量使用commit(),而不要使用commitAllowingStateLoss()。

addToBackStack("fname")是可选的。FragmentManager拥有回退栈(BackStack),类似于Activity的任务栈,如果添加了该语句,就把该事务加入回退栈,当用户点击返回按钮,会回退该事务(回退指的是如果事务是add(frag1),那么回退操作就是remove(frag1));如果没添加该语句,用户点击返回按钮会直接销毁Activity。

Fragment有一个常见的问题,即Fragment重叠问题,这是由于Fragment被系统杀掉,并重新初始化时再次将fragment加入activity,因此通过在外围加if语句能判断此时是否是被系统杀掉并重新初始化的情况。

Fragment有个常见的异常:

java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
at android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1341)
at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1352)
at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:595)
at android.support.v4.app.BackStackRecord.commit(BackStackRecord.java:574)

从上面看到,先从mAdded中查找是否有该Fragment,如果没找到,再从mActive中查找是否有该Fragment。mAdded是已经添加到Activity的Fragment的集合,mActive不仅包含mAdded,还包含虽然不在Activity中,但还在回退栈中的Fragment。

该异常出现的原因是:commit()在onSaveInstanceState()后调用。首先,onSaveInstanceState()在onPause()之后,onStop()之前调用。onRestoreInstanceState()在onStart()之后,onResume()之前。

因此避免出现该异常的方案有:

不要把Fragment事务放在异步线程的回调中,比如不要把Fragment事务放在AsyncTask的onPostExecute(),因此onPostExecute()可能会在onSaveInstanceState()之后执行。
逼不得已时(即一定会出现事务丢失时)使用commitAllowingStateLoss()。

FragmentTransaction有一些基本方法,下面给出调用这些方法时,Fragment生命周期的变化:

add(): onAttach()->…->onResume()。

remove(): onPause()->…->onDetach()。

replace(): 相当于旧Fragment调用remove(),新Fragment调用add()。

show(): 不调用任何生命周期方法,调用该方法的前提是要显示的Fragment已经被添加到容器,只是纯粹把Fragment UI的setVisibility为true。

hide(): 不调用任何生命周期方法,调用该方法的前提是要显示的Fragment已经被添加到容器,只是纯粹把Fragment UI的setVisibility为false。

detach(): onPause()->onStop()->onDestroyView()。UI从布局中移除,但是仍然被FragmentManager管理。

attach(): onCreateView()->onStart()->onResume()。

Fragment实现原理与BackStack

Fragment向Activity传递数据

首先,在Fragment中定义接口,并让Activity实现该接口

在Fragment的onAttach()中,将参数Context强转为OnFragmentInteractionListener对象:

FABridge

由于通过接口的方式从Fragment向Activity进行数据传递比较麻烦,需要在Fragment中定义interface,并让Activity实现该interface,FABridge通过注解的形式免去了这些定义。

Activity向Fragment传递数据

Activity向Fragment传递数据比较简单,获取Fragment对象,并调用Fragment的方法即可,比如要将一个字符串传递给Fragment,则在Fragment中定义方法

Fragment之间通信

由于Fragment之间是没有任何依赖关系的,因此如果要进行Fragment之间的通信,建议通过Activity作为中介,不要Fragment之间直接通信。

DialogFragment

DialogFragment是Android 3.0提出的,代替了Dialog,用于实现对话框。他的优点是:即使旋转屏幕,也能保留对话框状态。

转载于:https://www.cnblogs.com/zharma/p/8345963.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 在Fragment中使用ListView需要先在布局文件中添加ListView控件,然后在Fragment类中通过findViewById方法获取该控件的实例。接着,需要创建一个Adapter来绑定数据源和ListView,最后调用ListView的setAdapter方法将Adapter绑定到ListView上。 ### 回答2: Fragment 是 Android 中的一个重要组件,它能够在 Activity 中嵌套展示 UI 界面。在 Fragment 中使用 ListView 是非常常见的需求,也是很容易完成的任务。 要使用 ListView,在 Fragment 的布局文件中,我们需要在 Fragment 的根布局中加入一个 ListView 控件。例如: ``` <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <ListView android:id="@+id/listview" android:layout_width="match_parent" android:layout_height="match_parent" android:dividerHeight="1dp" android:divider="@android:color/darker_gray" /> </RelativeLayout> ``` 其中,ListView 控件的 ID 可以根据实际情况命名,这里的 ID 为 “listview”。列表中的每一项可以通过自定义的布局文件来实现,这里不再赘述。 在 Fragment 的 Java 代码中,我们需要通过 ListView 控件的 ID 来获取它的实例,并且为 ListView 设置适配器。 ``` public class MyFragment extends Fragment { private ListView listView; private MyAdapter myAdapter; ... @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_my, container, false); listView = view.findViewById(R.id.listview); myAdapter = new MyAdapter(getActivity(), getData()); listView.setAdapter(myAdapter); ... return view; } private List<String> getData() { ... return data; } } ``` 其中,MyAdapter 是集成 BaseAdapter 的自定义适配器,用于将数据填充到 ListView 中。getData 方法返回数据,这里只使用了一个字符串列表作为数据源,实际开发中,可以根据需求灵活添加、处理数据。 ListView 是 Android 中常用的列表控件,使用起来方便,在 Fragment 中使用也同样简单。需要注意的是,Fragment 中的 ListView 和 Activity 中的 ListView 并没有本质上的区别,只需要在获取 Fragment 中的 ListView 时,使用相应的方法即可。同时,为 ListView 设置适配器和处理数据的方法也与 Activity 中的 ListView 相同。 ### 回答3: 为了在Fragment中使用ListView,我们需要进行以下步骤: 1. 创建Fragment布局文件并添加ListView 首先,我们需要在Fragment的布局文件中添加一个ListView。例如,我们可以在layout文件夹中创建一个名为“fragment_list.xml”的文件,并在此文件中添加ListView。 2. 在Fragment的Java代码中创建ListView 接下来,我们需要在Fragment的Java代码中创建ListView对象。我们可以在onCreateView()方法中使用LayoutInflater来加载布局文件,并使用findViewById()方法获取ListView对象。例如: public class MyFragment extends Fragment { private ListView listView; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_list, container, false); listView = (ListView) view.findViewById(R.id.listView); return view; } } 3. 创建Adapter并设置到ListView 接下来,我们需要创建一个Adapter,用于为ListView提供数据。我们可以创建一个自定义的Adapter,或使用Android原生的Adapter(如ArrayAdapter、SimpleAdapter、CursorAdapter等)。我们需要在Fragment的Java代码中创建Adapter对象,并将其设置到ListView中。例如: public class MyFragment extends Fragment { private ListView listView; private ArrayAdapter<String> adapter; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_list, container, false); listView = (ListView) view.findViewById(R.id.listView); // 创建Adapter并设置到ListView ArrayList<String> dataList = new ArrayList<>(); dataList.add("Item 1"); dataList.add("Item 2"); dataList.add("Item 3"); adapter = new ArrayAdapter<String>(getContext(), android.R.layout.simple_list_item_1, dataList); listView.setAdapter(adapter); return view; } } 4. 处理ListView的点击事件 最后,我们可以在ListView中添加一个点击事件的监听器,以响应用户的操作。我们可以在onCreateView()方法中为ListView设置一个OnItemClickListener,如下所示: public class MyFragment extends Fragment { private ListView listView; private ArrayAdapter<String> adapter; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_list, container, false); listView = (ListView) view.findViewById(R.id.listView); // 创建Adapter并设置到ListView ArrayList<String> dataList = new ArrayList<>(); dataList.add("Item 1"); dataList.add("Item 2"); dataList.add("Item 3"); adapter = new ArrayAdapter<String>(getContext(), android.R.layout.simple_list_item_1, dataList); listView.setAdapter(adapter); // 处理ListView的点击事件 listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { String item = adapter.getItem(position); Toast.makeText(getContext(), "Clicked item: " + item, Toast.LENGTH_SHORT).show(); } }); return view; } } 以上就是在Fragment中使用ListView的基本步骤。通过以上步骤,我们可以在Fragment中轻松地创建一个带有ListView的列表,并为用户提供良好的操作体验。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值