Fragment的基本使用

来源:互联网 发布:数据的一致性是指 编辑:程序博客网 时间:2024/06/06 08:56

Fragment的基本使用

一、Fragment的静态使用

Fragment可以在布局中直接使用<fragment>标签,使用android:name属性或者使用class属性来指定对应的Fragment实现。

activity_fragment_static.xml布局文件

<?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">    <!--静态添加fragment到xml布局中-->    <!--使用android:name属性指定Fragment-->    <fragment        android:id="@+id/content_static_fragment"        android:name="com.yundoku.demo201706.fragment.StaticFragment"        android:layout_width="match_parent"        android:layout_height="200dp" />    <!--使用class属性指定Fragment-->    <fragment        android:id="@+id/content_static_fragment"        android:layout_width="match_parent"        class="com.yundoku.demo201706.fragment.StaticFragment"        android:layout_height="200dp" /></LinearLayout>

Activity中就直接使用布局就可以。

public class FragmentTestActivity extends Activity {    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_fragment_static);//直接使用布局就好    }}

二、Fragment的动态使用

Fragment除了在xml中使用<fragment>标签来指定Fragment外,还可以直接通过代码的形式来动态添加Fragment到xml布局中。

动态添加Fragment到xml中,需要借助FrameLayout布局,具体实现方式,看下面代码。

activity_fragment_dynamic.xml布局文件

<?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">    <!--动态添加fragment到xml中,先使用FrameLayout来占位,然后采用add或replace的方式添加或替换-->    <FrameLayout        android:id="@+id/content_dynamic_fragment"        android:layout_width="match_parent"        android:layout_height="200dp" /></LinearLayout>

FragmentTestActivity中动态使用Fragment替换FrameLayout

public class FragmentTestActivity extends Activity {    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_fragment_dynamic);        dynamicAddFragment();    }    /**     * 动态的使用Fragment     */    private void dynamicAddFragment() {        FragmentManager fragmentManager = getFragmentManager();        FragmentTransaction transaction = fragmentManager.beginTransaction();        // 使用LiftCycleFragment替换指定的 id 的 View        transaction.replace(R.id.content_dynamic_fragment, new DynamicFragment());        transaction.commit();    }}

三、Fragment的生命周期

Fragment是依附于Activity的,所以生命周期和Activity很多是保持一致的。当然也有一些不同的地方,让我们来看看吧。

Fragment的生命周期图:

image

Fragment的生命周期和Activity的生命周期对比图

image

对于对象的创建和销毁问题,最好保持在2个相对应的生命周期中


四、Fragment && FragmentManager && FragmentTransaction 常用API介绍

Fragment的API介绍:

//  通过bundle传递数据,后面会将用法setArguments(Bundle bundle);getArguments();// 判断Fragment状态isAdded();isDetached();isVisible();isHidden();isInLayout();isResumed();isRemoving();// 获取Fragment的标记和idgetId();getTag();//API 15getUserVisibleHint();setUserVisibleHint(true);// API 17getChildFragmentManager();getParentFragment();除了上述方法,还有Activity中的一些方法的封装和动画相关的方法。例如关于MenuItem,Permission,动画等,这里列举几个。如:MenuItem相关:setHasOptionsMenu(boolean b);onCreateOptionsMenu(Menu menu, MenuInflater inflater);onOptionsItemSelected(MenuItem item);Permission相关:requestPermissions(String[] permissions, int requestCode);onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults);shouldShowRequestPermissionRationale(String permission);动画相关:API 21setEnterTransition(Transition transition);setExitTransition(Transition transition);setAllowEnterTransitionOverlap(boolean allow);setAllowReturnTransitionOverlap(boolean allow);

FragmentManager介绍:

getFragmentManager();// 获取FragmentManager方法findFragmentById();// 通过id获取对应的FragmentfindFragmentByTag();// 通过Tag获取对应的FragmentbeginTransaction();// 开启事务,返回FragmentTransaction对象popBackStack();// 退出栈顶的Fragment//退出指定id的FragmentpopBackStack(int id , int flag);// flag: 0 or FragmentManager.POP_BACK_STACK_INCLUSIVEpopBackStack(String tag , int flag);//退出指定Tag的FragmentpopBackStackImmediate();// 返回一个boolean值popBackStackImmediate(int id , int flag);popBackStackImmediate(String tag , int flag);getBackStackEntryCount();// 获取返回栈中的数量addOnBackStackChangedListener(); // 添加返回栈改变的监听removeOnBackStackChangedListener();// 移除返回栈的监听isDestroyed();// API 17  是否Activity走了OnDestory()生命周期方法

FragmentTransaction介绍:

FragmentTransaction是一个抽象类,具体的是现实类是
BackStackRecord

常用API:

// 添加add(Fragment fragment, String tag);add(int containerViewId, Fragment fragment);add(int containerViewId, Fragment fragment,String tag);// 替换,相当于remove之后再addreplace(int containerViewId, Fragment fragment);replace(int containerViewId, Fragment fragment,String tag);// 移除remove(Fragment fragment);// 显示show(Fragment fragment);//隐藏hide(Fragment fragment);//依附attach(Fragment fragment);//分离detach(Fragment fragment);isEmpty();addToBackStack(String name);// 添加到任务栈,参name:null或者一个标记tag// 提交事务 API的具体差异,看源码解释commit();commitAllowingStateLoss();// 这是危险的,因为如果活动需要稍后从其状态恢复,则提交可能丢失commitNow();commitNowAllowingStateLoss();

五、Fragment的通信

Fragment常常会和ActivityFragment会有数据传递,那么如何实现呢

实现方式肯定有多种,就举例说下setArguments(Bundle bundle)的方式传递消息:

public class ArgumentFragment extends Fragment {    private String message;    /**     * 这种写法就是为了Activity或Fragment等向当前的Fragment传递消息     */    public static ArgumentFragment getInstance(String message) {        //通过Bundle传递消息        Bundle bundle = new Bundle();        bundle.putString("message", message);        ArgumentFragment fragment = new ArgumentFragment();        fragment.setArguments(bundle);        return fragment;    }    @Override    public void onAttach(Context context) {        super.onAttach(context);        //获取bundle传递的消息        Bundle bundle = getArguments();        if (bundle != null) {            message = bundle.getString("message");        }    }    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);    }    @Override    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {        return inflater.inflate(R.layout.fragment_lift_cycle, container, false);    }    @Override    public void onViewCreated(View view, Bundle savedInstanceState) {        super.onViewCreated(view, savedInstanceState);        TextView textView = (TextView) view.findViewById(R.id.fragmnet_content_text);        if (!TextUtils.isEmpty(message)) {            textView.setText("ArgumentFragment message: "+message);        } else {            textView.setText("ArgumentFragment message is none");        }    }}

Activity中的调用:

public class FragmentTestActivity extends Activity {    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_fragment);        FragmentManager fragmentManager = getFragmentManager();        FragmentTransaction transaction = fragmentManager.beginTransaction();        // 建议使用(不要直接new对象),这样可以传递信息给Fragment        transaction.replace(R.id.content_dynamic_fragment, ArgumentFragment.getInstance("Argument"));        transaction.commit();    }}

六、Fragment的回退栈

添加到Fragment返回栈是通过transaction.addToBackStack(String name)方法,按返回键是,会从栈中一个个的退出。如果需要主动退出栈,可以调用fragmentManager.popBackStack()退出返回栈。具体我们看代码:

public class FragmentTestActivity extends Activity {    String[] tags = {"One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten"};    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_fragment);        createFragment(0, false);    }    private void createFragment(final int i, boolean addBackStace) {        if (i >= tags.length) {            return;        }        FragmentManager fragmentManager = getFragmentManager();        FragmentTransaction transaction = fragmentManager.beginTransaction();        BackStackFragment fragment = BackStackFragment.getInstance(tags[i]);        fragment.setFragmentClickListener(new FragmentClickListener() {            @Override            public void onFragmentClick() {                createFragment(i + 1, true);            }        });        transaction.replace(R.id.content_dynamic_fragment, fragment, tags[i]);        if (addBackStace) {            transaction.addToBackStack(tags[i]);        }        transaction.commit();    }    @Override    protected void onResume() {        super.onResume();        computeClearBackStack(false);    }    @Override    protected void onPause() {        super.onPause();        computeClearBackStack(true);    }    private void computeClearBackStack(boolean clean) {        FragmentManager fragmentManager = getFragmentManager();        int backStackEntryCount = fragmentManager.getBackStackEntryCount();        Log.e("FragmentTestActivity", "onPause--> backStackEntryCount: " + backStackEntryCount);        for (int i = 0; i < backStackEntryCount; i++) {            FragmentManager.BackStackEntry backStackEntryAt = fragmentManager.getBackStackEntryAt(i);            String name = backStackEntryAt.getName();            Log.e("FragmentTestActivity", "onPause--> name: " + name);            if (clean) {                fragmentManager.popBackStack(name, FragmentManager.POP_BACK_STACK_INCLUSIVE);            }        }    }}

BackStackFragment

public class BackStackFragment extends Fragment {    private String message;    private FragmentClickListener listener;    public void setFragmentClickListener(FragmentClickListener listener) {        this.listener = listener;    }    public static BackStackFragment getInstance(String message) {        //通过Bundle传递消息        Bundle bundle = new Bundle();        bundle.putString("message", message);        BackStackFragment fragment = new BackStackFragment();        fragment.setArguments(bundle);        return fragment;    }    @Override    public void onAttach(Context context) {        super.onAttach(context);        //获取bundle传递的消息        Bundle bundle = getArguments();        if (bundle != null) {            message = bundle.getString("message");        }        if (message == null) {            message = "";        }    }    @Override    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {        return inflater.inflate(R.layout.fragment_content, container, false);    }    @Override    public void onViewCreated(View view, Bundle savedInstanceState) {        super.onViewCreated(view, savedInstanceState);        TextView textView = (TextView) view.findViewById(R.id.fragmnet_content_text);        if (!TextUtils.isEmpty(message)) {            textView.setText(message + " Fragment");        } else {            textView.setText("Fragment");        }        textView.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                if (listener != null) {                    listener.onFragmentClick();                }            }        });    }}

具体效果如图:

image


七、Fragment懒加载方案

FragmentViewPager结合使用时,ViewPager会预加载下一页的内容,导致浪费用户的流量,所以需要通过懒加载的方式优化。当Fragment的界面显示是,再去加载数据,具体实现如下:

LazyFragment

public abstract class LazyFragment extends Fragment {    protected boolean isVisible;    /**     * 在这里实现Fragment数据的缓加载.     */    @Override    public void setUserVisibleHint(boolean isVisibleToUser) {        super.setUserVisibleHint(isVisibleToUser);        if (getUserVisibleHint()) {            isVisible = true;            onVisible();        } else {            isVisible = false;            onInvisible();        }    }    protected void onVisible() {        lazyLoad();    }    protected abstract void lazyLoad();    protected void onInvisible() {    }} 

MyLazyFragment实现

public class MyLazyFragment extends LazyFragment {    private String message;    // 标志位,标志已经初始化完成。    private boolean isPrepared;    public static MyLazyFragment getInstance(String message) {        Bundle bundle = new Bundle();        bundle.putString("message", message);        MyLazyFragment firstFragment = new MyLazyFragment();        firstFragment.setArguments(bundle);        return firstFragment;    }    @Override    public void onAttach(Context context) {        super.onAttach(context);        Bundle bundle = getArguments();        if (bundle != null) {            message = bundle.getString("message");        }        if (message == null) {            message = "";        }    }    @Override    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {        View view = inflater.inflate(R.layout.fragment_content, container, false);        // view.findViewById() 操作获取布局中的View对象        isPrepared = true;        lazyLoad();        return view;    }    @Override    protected void lazyLoad() {        if (!isPrepared || !isVisible) {            return;        }        //获取数据,填充控件    }}

八、Fragment常见的异常和解决方案

前面讲的内容都是比较基础的知识,关于Fragment常见的异常和解决方案,可以参考下面的博客,总结的很好。

Fragment全解析系列(一):那些年踩过的坑


九、DialogFragment创建视图介绍

DialogFragmentFragment的子类,同时具有Dialog的特性,Google官方推荐使用,替代AlertDialog

DialogFragment的使用和Fragment是一样的,这里不做解释。这里讲讲DialogFragment 创建一个视图的2种方式。

  • 通过onCreateDialog()方法,创建Dialog的视图
public class AlertDiaolgFragment extends DialogFragment {     public static void showDialog(FragmentManager manager) {        FragmentTransaction transaction = manager.beginTransaction();        transaction.addToBackStack("Alert");        AlertDiaolgFragment diaolgFragment = new AlertDiaolgFragment();        diaolgFragment.show(transaction, "Alert");    }    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);    }    @Override    public Dialog onCreateDialog(Bundle savedInstanceState) {        View view = LayoutInflater.from(getActivity()).inflate(R.layout.dialog, null);        return new AlertDialog.Builder(getActivity())                .setTitle("Dialog")                .setMessage("今天星期五")                .setView(view)                .setPositiveButton("OK", null)                .setNegativeButton("Cancel", null)                .create();    }}
  • 通过onCreateView()方法,直接加载视图,这里的用法就完全是Fragment的用法
public class MyDialogFragment extends DialogFragment {    public static void showDialog(FragmentManager manager) {        FragmentTransaction transaction = manager.beginTransaction();        transaction.addToBackStack("My");        AlertDiaolgFragment diaolgFragment = new AlertDiaolgFragment();        diaolgFragment.show(transaction, "My");    }    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);    }    @Override    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {        return LayoutInflater.from(getActivity()).inflate(R.layout.dialog, container,false);    }}

十、DialogFragment调用show()方法导致Can not perform this action after onSaveInstanceState异常的解决方案

在使用DialogFragment的时候,偶尔会遇到如下异常,在Activity的生命周期方法走了onSaveInstanceState()方法后,在调用DialogFragmentshow()方法,导致异常:Can not perform this action after onSaveInstanceState

关于Can not perform this action after onSaveInstanceState异常问题,我们的处理方式是:确保是在ActivityFragment的处于onResume()状态调用。在Fragment中有isResume()方法,通过判断该方法,是否显示Fragment。在Activity中,通过在onResume()onPause()设置变量量控制。

以上面的MyDialogFragment为例,如:

在Fragment中,需要显示MyDialogFragment的视图调用if(isResume()){    MyDialogFragment.showDialog(getFragmentManager);}在Activity中,需要显示MyDialogFragment的视图调用private boolean mState;if(mState){     MyDialogFragment.showDialog(getFragmentManager);}@Overrideprotected void onResume() {    super.onResume();    mState = true;}@Overrideprotected void onPause() {    super.onPause();    mState = false;}

原创粉丝点击