美文网首页
Android基础组件之Fragment

Android基础组件之Fragment

作者: 小白象码农 | 来源:发表于2018-09-06 10:32 被阅读10次

    本篇主要复习Fragment的清单如下:

    • Fragment的生命周期

    • Fragment加载的两种方式

    • Fragment之DialogFragment使用

    • Fragment通信

    • 使用Fragment时的注意事项

    一.Fragment的生命周期

    a. 官方生命周期图


    b.Fragment生命周期方法调用场景

    方法 解释
    onAttach() Fragment和Activity建立联系时调用(获取Activity传递的值)
    onCreateView() Fragment创建View(加载布局)时调用
    onActivityCreated() ActivityonCreate()方法执行完毕后调用
    onDestoryView() Fragment布局被移除时调用
    onDetach() FargmentActivity解除关联时调用

    c.Fragment和Activity生命周期对比图


    1.创建流程:先执行Activity的生命周期回调,在执行Fragment方法
    2.销毁流程:先执行Fragment的生命周期,在执行Acstivity的方法

    二.Fragment加载方式

    a.静态加载
    Fragment的静态添加 :

    //BlankFragment.java
    public class BlankFragment extends Fragment {
    
        public BlankFragment() {
        }
    
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                                 Bundle savedInstanceState) {
            // 1. 加载布局,第三个参数必须为`false`,否则会加载两次布局并且抛出异常!!
            return inflater.inflate(R.layout.fragment_blank, container, false);
        }
    }
    
    //fragment的布局
    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context="com.example.a6005001819.androiddeveloper.Fragment.BlankFragment">
    
        <!-- TODO: Update blank fragment layout -->
        <TextView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:text="@string/hello_blank_fragment" />
    
    </FrameLayout>
    

    在Activity的布局文件中添加:

    //如一般Activity代码-直接省略
    如果Fragment使用的是support-v4中的, Activity需要继承自FragmentActivity

    Activity的布局

    //用fragment标签加载fragment
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context="com.example.a6005001819.androiddeveloper.MainActivity">
    
        <fragment
          android:id="@+id/example_fragment"
            android:name="com.example.a6005001819.androiddeveloper.Fragment.BlankFragment"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>
    
    </LinearLayout>
    

    1 如果Fragment属于android.support.v4.app.Fragment包,所用Activity必须继承FragmentActivity
    2 如果Fragment属于android.app.Fragment,直接使用Activity即可

    b 动态加载

    • Fragment代码不变
    • Activity中进行动态添加
    public class MainJavaActivity extends Activity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main_java);
    
            //1. 获取FragmentManager
            FragmentManager fragmentManager = getFragmentManager();
            //2. 获取FragmentTransaction
            FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
            //3. 创建Fragment
            BlankFragment blankFragment = new BlankFragment();
            //4. 将Fragment替换到Activity的布局中(Framelayout)
            fragmentTransaction.add(R.id.main_java_activity_container, blankFragment);
            fragmentTransaction.commit();
        }
    }
    
    <?xml version="1.0" encoding="utf-8"?>
    <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context="com.example.a6005001819.androiddeveloper.MainJavaActivity">
    
        <FrameLayout
            android:id="@+id/main_java_activity_container"
            android:layout_width="match_parent"
            android:layout_height="match_parent"></FrameLayout>
    
    </android.support.constraint.ConstraintLayout>
    

    重复添加

    问题:Fragment的动态添加是在onCreate()中,当手机横竖屏切换,会导致多次调用onCreate()最终导致创建多个Fragment
    解决办法:在onCreate()检查参数savedInstanceState来确定是第一次运行还是恢复后运行

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main_java);
    
        if(savedInstanceState == null){
            //1. 获取FragmentManager(support-v4中用`getSupportFragmentManager`)
            FragmentManager fragmentManager = getFragmentManager();
            //2. 获取FragmentTransaction
            FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
            //3. 创建Fragment
            BlankFragment blankFragment = new BlankFragment();
            //4. 将Fragment替换到Activity的布局中(Framelayout)
            fragmentTransaction.add(R.id.main_java_activity_container, blankFragment);
            fragmentTransaction.commit();
    
            Log.i("feather", "创建新的Fragment");
        }
    }
    

    三 DialogFragment 使用

    a DialogFragment的作用与优缺点

    DialogFragment在Android 3.0提出,用于替代Dialog
    优点:旋转屏幕也能保留对话框状态
    自定义对话框样式: 继承DialogFragment并重写onCreateView(),该方法返回对话框UI

    //自定义DialogFragment
    public class CustomDialogFragment extends DialogFragment{
    
        public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
            //1. 消除标题
            getDialog().requestWindowFeature(Window.FEATURE_NO_TITLE);
            //2. 自定义样式
            View root = inflater.inflate(R.layout.fragment_blank, container);
            return root;
        }
    }
    //使用DialogFragment
    CustomDialogFragment dialogFragment = new CustomDialogFragment();
    dialogFragment.show(getFragmentManager(), "dialog");
    

    四 Fragment的通信

    a EventBus是解决Fragment通信的终极解决方案

    1.Fragment通信涉及:Fragment向Activity传递数据、Activity向Fragment传递数据、Fragment之间床底数据

    1. EventBus: 一个Android事件发布/订阅轻量级框架—能够便捷、高效解决Fragment所有通信问题

    b Fragment和Activity

    • Fragment调用Activity中的方法

    1.getActivity()或者onAttach()中Context转为Activity(不推荐使用getActivity获取,容易空指针)
    2.用该Activity对象,调用Activity的对象方法。

    • Activity调用Fragment中的方法

    1.Activity中直接用该Fragment对象去调用方法。
    2.用过接口回调

    • Activity向Fragment传递数据

    1.通过构造函数传递数据(不推荐)
    2.通过参数传递数据,在Fragment中onAttach()中getArguments()
    3.在Activity中获取Fragment对象,直接调用Fragment的方法,通过参数传递数据

    • Fragment之间的通信

    1.需要借助Activity进行数据通信
    2.Activity中通过FragmentManager的findFragmentById去获取Fragment

    五 使用Fragment时的注意事项

    • Fragment的常见问题,以及如何处理?

    1.getActivity()空指针:常见于进行异步操作的时候,此时如果Fragment已经onDetach(),就会遇到。解决办法:在Fragment里面使用一个全局变量mActivity,可能会导致内存泄露。但是比崩溃更好。
    2.视图重叠:主要是因为Fragment的onCreate()中没有判断saveInstanceSate == null,导致重复加载了同一个Fragment

    • Fragment的切换方式有多少种?

    1.add()、replace()、remove(): 会将Fragment进行移除(就是回收了实例),每次都会新建一个实例。
    2.hide()、show()
    3.detach()、attach()

    • add和replace的区别

    1.replace会将栈中的fragment全部remove,再add进行添加。
    2.add是在原有基础上进行添加。

    • Fragment中onCreateView()

    1.内部加载布局的inflate()的第三个参数必须是false,否则会导致重复添加,抛出异常

    • Fragment需要传入参数该怎么做?

    1.应该通过setArguments(Bundle bundle)方法添加
    2.之后通过onAttach()中的getArguments()获得传进来的参数。
    3.不建议通过给Fragment添加带参数的构造函数来传参数,这样内存紧张时被系统杀掉会导致无法恢复数据

    • Fragment中获取Activity对象

    1.不应该!使用getActivity()获取
    2.应该在onAttach()中将Context对象强转为Activity对象

    • 不能在onSaveInstanceState()后调用commit()

    1.onSaveInstanceState()在onPause()和onStop()之间调用。
    2.onRestoreInstanceState()在onStart()和onResume()之间调用。
    避免异常方法:
    3.不要把Fragment事务放在异步线程的回调中,比如不要把Fragment事务放在AsyncTask的onPostExecute()—onPostExecute()可能会在onSaveInstanceState()之后执行。
    4.无可奈何时使用commitAllowingStateLoss()-一般不推荐。

    希望这篇文章对你有帮助~
    推荐大神最全面的Fragment解析
    YoKey之Fragment全解析系列

    相关文章

      网友评论

          本文标题:Android基础组件之Fragment

          本文链接:https://www.haomeiwen.com/subject/xfoowftx.html