zoukankan      html  css  js  c++  java
  • Fragment以及懒加载

    1、Fragments

     Fragment是Activity中用户界面的一个行为或者是一部分,你可以在一个单独的Activity上把多个Fragment组合成为一个多区域的UI,并且可以在多个Activity中再次使用。可以认为Fragment是Activity的一个模块零件,他有自己的生命周期,接受他自己的输入事件,并且可以在Activity运行时添加或者删除。

    两个概念:

    Fragment、宿主

    fragment的生命周期只接受其宿主activity的生命周期的影响。例如,一旦activity被暂停,它里面所有的fragment也会被暂停,一旦activity被销毁,它里面的所有fragment也会被销毁。

    2、创建Fragment

    要创建一个fragment,必须创建一个fragment的子类(或是继承自他的子类),fragment类的代码看起来很像activity,他与activity一样都有回调函数,例如onCreate,onStart,onPause和onStop,事实上,如果你正在讲一个现成的Android应用转而使用Fragment来实现,可以将代码从activity的回调函数移植到各自的fragment中。

    除了基类fragment,还有几个可能会继承的子类:

    DialogFragment、ListFragment、PreferenceFragment

    3、添加用户界面

    fragment常被用作activity用户界面的一部分,并且将本身的布局够见到activity中去。

    将fragment添加到activity有两种方式:

    1)在activity的布局文件里声明fragment

    activity_main.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="horizontal">
    
        <fragment
            android:id="@+id/fragTitle"
            android:name="com.wzh.pushdemo.fragment.TitleFragment"
            android:layout_width="0dip"
            android:layout_height="match_parent"
            android:layout_weight="1" />
    
        <fragment
            android:id="@+id/fragContent"
            android:name="com.wzh.pushdemo.fragment.ContentFragment"
            android:layout_width="0dip"
            android:layout_height="match_parent"
            android:layout_weight="3" />
    
    </LinearLayout>

    2)通过编码将fragment添加到已存在的ViewGroup中

    <?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="horizontal">
    
        <fragment
            android:id="@+id/fragTitle"
            android:name="com.wzh.pushdemo.fragment.TitleFragment"
            android:layout_width="0dip"
            android:layout_height="match_parent"
            android:layout_weight="1" />
    
        <FrameLayout
            android:id="@+id/framLayout"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="3">
        </FrameLayout>
    
    </LinearLayout>
    public class MainActivity extends Activity {
    
        TitleFragment titleFragment;
        ContentFragment contentFragment;
        FrameLayout framLayout;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            //通过fragmentManager(Fragment管理器)获取fragment实例
    //        titleFragment = (TitleFragment) getFragmentManager().findFragmentById(R.id.fragTitle);
    //        contentFragment = (ContentFragment) getFragmentManager().findFragmentById(R.id.fragContent);
    
            framLayout = (FrameLayout) findViewById(R.id.framLayout);
            /**
             * 通过代码添加Fragment
             */
            FragmentManager fm = getFragmentManager();
            //开启一个事务
            FragmentTransaction ft = fm.beginTransaction();
    
            contentFragment = new ContentFragment();
    
            //添加Fragment
            ft.add(R.id.framLayout, contentFragment);
    //        ft.remove(); //删除
    //        ft.replace();//替换
    
            //提交事务
            ft.commit();
        }
    }
    Fragment家族常用的API Fragment常用的三个类:
    android.app.Fragment    主要用于定义Fragment
    android.app.FragmentManager 主要用于在Activity中操作
    Fragment android.app.FragmentTransaction 保证一些列Fragment操作的原子性,熟悉事务这个词,一定能明白~
    a、获取FragmentManage的方式: getFragmentManager() // v4中,getSupportFragmentManager
    b、主要的操作都是FragmentTransaction的方法 FragmentTransaction transaction = fm.benginTransatcion();//开启一个事务
    • transaction.add()   往Activity中添加一个
    • Fragment transaction.remove()  从Activity中移除一个Fragment,如果被移除的Fragment没有添加到回退栈,这个Fragment实例将会被销毁。
    • transaction.replace()  使用另一个Fragment替换当前的,实际上就是remove()然后add()的合体
    • transaction.hide()  隐藏当前的Fragment,仅仅是设为不可见,并不会销毁,
    • transaction.show() 显示之前隐藏的Fragment
    • detach()
      会将view从UI中移除,和remove()不同,此时fragment的状态依然由FragmentManager维护。
    • attach()
      重建view视图,附加到UI上并显示。
    • transatcion.commit()
      提交一个事务
    commit方法一定要在Activity.onSaveInstance()之前调用。

    4、管理Fragments

    想要管理activity中的fragment,可以使用FragmentManager,可以通过在activity中调用getFragmentManager()获得。

    使用FragmentManger可以做如下事情,包括:

    (1)使用findFragmentById()(用于在activity不居中提供有界面的fragment)或者findFragmentByTag()获取activity中存在的fragment(用于有界面或者没有界面的fragment)

    (2)使用popBackStack()(模仿用户的back命令)从后台栈弹出fragment

    (3)使用addOnBackStackChangedListener()注册一个监听后台栈变化的监听器

    public class PopBackActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_pop_back);
        }
    
        public void oneClick(View view) {
            PopBackFragment p1 = new PopBackFragment("one");
            FragmentTransaction ft = getFragmentManager().beginTransaction();
            ft.replace(R.id.content, p1);
            //把当前fragment添加到Activity栈
            ft.addToBackStack(null);
            ft.commit();
    
        }
    
        public void twoClick(View view) {
            //用构造方法传值,有问题
            PopBackFragment p1 = new PopBackFragment("two");
            FragmentTransaction ft = getFragmentManager().beginTransaction();
            ft.replace(R.id.content, p1);
            //把当前fragment添加到Activity栈
            ft.addToBackStack(null);
            ft.commit();
        }
    
        @Override
        public boolean onKeyDown(int keyCode, KeyEvent event) {
            if (keyCode == KeyEvent.KEYCODE_BACK) {
                if (getFragmentManager().getBackStackEntryCount() == 0) {
                    finish();
                } else {
                    getFragmentManager().popBackStack();
                }
            }
            return true;
        }
    }
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout 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"
        android:orientation="vertical">
    
        <Button
            android:id="@+id/button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="oneClick"
            android:text="one" />
    
        <Button
            android:id="@+id/button2"
            android:layout_width="88dp"
            android:layout_height="48dp"
            android:onClick="twoClick"
            android:text="two" />
    
        <FrameLayout
            android:id="@+id/content"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            tools:layout_editor_absoluteX="8dp"
            tools:layout_editor_absoluteY="72dp">
    
        </FrameLayout>
    </LinearLayout>
    public class PopBackFragment extends Fragment {
        private String title;
    
        public PopBackFragment() {
            super();
        }
    
        public PopBackFragment(String title) {
            this.title = title;
        }
    
        @Nullable
        @Override
        public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
            View view = inflater.inflate(R.layout.frag_pop_back, null);
            TextView textView = (TextView) view.findViewById(R.id.text);
            textView.setText(title);
            return view;
        }
    }

    5.Fragment的传参方式:

        public static Fragment newInstance(String arg) {
            TitleFragment titleFragment1 = new TitleFragment();
            Bundle bundle = new Bundle();
            bundle.putString("info", arg);
            titleFragment1.setArguments(bundle);
            return titleFragment1;
        }

     例如:

        public void twoClick(View view) {
            //用构造方法传值,有问题,在横竖屏切换时数据会丢失,不建议使用
    //        PopBackFragment p1 = new PopBackFragment("two");
            //建议使用
            PopBackFragment p1 = PopBackFragment.getInstance("two");
            FragmentTransaction ft = getFragmentManager().beginTransaction();
            ft.replace(R.id.content, p1);
            //把当前fragment添加到Activity栈
            ft.addToBackStack(null);
            ft.commit();
        }
    PopBackFragment
        /**
         * Fragmen的传参方法
         * @param title
         * @return
         */
        public static PopBackFragment getInstance(String title) {
            PopBackFragment p = new PopBackFragment();
            Bundle bundle = new Bundle();
            bundle.putString("title", title);
            p.setArguments(bundle);
            return p;
        }
    
        @Nullable
        @Override
        public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
            View view = inflater.inflate(R.layout.frag_pop_back, null);
            TextView textView = (TextView) view.findViewById(R.id.text);
            textView.setText(getArguments().getString("title"));
            return view;
        }

    Fragment与Activity交互

    fragment可以通过getActivity()函数访问Activity,并且很容易的执行类似于查找activity布局中的视图任务:

    View listView = getActivity().findViewById(R.id.list);

    activity能够调用fragment的函数findFragmentById()或者findFragmentByTag(),从FragmentManager中获取Fragment

       TitleFragment fragment = (TitleFragment) getFragmentManager().findFragmentById(R.id.fragTitle);

    fragment与activity共享事件
    一个好方法是fragment内部定义一个回调接口,并需要宿主activity实现它。
    当activity通过接口接收到回调时,可以在必要时与布局中的其他fragment共享信息。

    宿主Activity:

    public class MainActivity extends Activity implements TitleFragment.TitleListener {
    
        private TitleFragment titleFragment;
        private ContentFragment contentFragment;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            titleFragment = (TitleFragment) getFragmentManager().findFragmentById(R.id.fragTitle);
            contentFragment = (ContentFragment) getFragmentManager().findFragmentById(R.id.fragContent);
        }
    
        @Override
        public void changeValue(String value) {
            contentFragment.change(value);
        }
    }

    activity_main.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="horizontal">
    
        <fragment
            android:id="@+id/fragTitle"
            android:name="com.wzh.pushdemo.fragment.TitleFragment"
            android:layout_width="0dip"
            android:layout_height="match_parent"
            android:layout_weight="1" />
    
        <fragment
            android:id="@+id/fragContent"
            android:name="com.wzh.pushdemo.fragment.ContentFragment"
            android:layout_width="0dip"
            android:layout_height="match_parent"
            android:layout_weight="3" />
    </LinearLayout>

    触发事件的frag

    public class TitleFragment extends Fragment implements View.OnClickListener {
    
        private TitleListener titleListener;
        private Button btnTime;
        private Button btnSpace;
    
        @Override
        public void onAttach(Activity activity) {
            super.onAttach(activity);
            titleListener = (TitleListener) activity;
        }
    
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
            View view = inflater.inflate(R.layout.frag_title, container, false);
            btnTime = (Button) view.findViewById(R.id.btnTime);
            btnSpace = (Button) view.findViewById(R.id.btnSpace);
            btnTime.setOnClickListener(this);
            btnSpace.setOnClickListener(this);
            return view;
        }
    
        @Override
        public void onClick(View view) {
            switch (view.getId()) {
                case R.id.btnTime:
                    titleListener.changeValue("时间");
                    break;
                case R.id.btnSpace:
                    titleListener.changeValue("地点");
                    break;
            }
    
        }
    
        //定义一个回调接口,宿主要实现这个接口
        public static interface TitleListener {
            public void changeValue(String value);
        }
    }
    frag_title.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:background="#00ff00"
        android:orientation="vertical"
        android:padding="10dp">
    
        <Button
            android:id="@+id/btnTime"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="时间" />
    
        <Button
            android:id="@+id/btnSpace"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="地点" />
    
    </LinearLayout>

    要改变值的frag

    public class ContentFragment extends Fragment {
        private TextView tvValue;
    
        @Nullable
        @Override
        public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
            View view = inflater.inflate(R.layout.frag_content, container, false);
            tvValue = (TextView) view.findViewById(R.id.tvValue);
            return view;
        }
    
        public void change(String value) {
            tvValue.setText(value);
        }
    }

    frag_content.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:background="#00ddff"
        android:orientation="vertical">
    
        <TextView
            android:id="@+id/tvValue"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:gravity="center"
            android:textSize="30dp"
            android:text="Hello" />
    
    </LinearLayout>

    6、PreferenceFragment

    有时候,我们的程序需要提供一些选项功能,能让用户去定制化自己的是用风格。例如,允许用户是否自动保存登录信息,允许用户设定某个页面的刷新时间等等,我们可以使用PreferenceActivity基类去显示给用户一个选项设置的界面,在Android3.0或更高版本上,可以使用PreferenceFragment类去实现这个功能。
    下面将展示如何常见和使用PreferenceFragment:
    (1)在res文件夹下新疆一个xml文件夹,在xml文件夹下面新建一个文件:preference.xml
    (2)在包路径下面新建一个类:Fragment继承PreferenceFragment
    (3)从xml文件加载选项addPreferencesFromResource(R.xml.preferences);

     7、Fragment懒加载

    如果ViewPager的每个Fragment都会拉取网络数据加载,而Fragment默认是加载前两个界面的,这样有可能会出现网络丢包或者网络堵塞情况,所以事先懒加载就有必要了。

    实现懒加载的重点是public void setUserVisibleHint(boolean isVisibleToUser)方法,这个方法会优先于onCreate()方法的,即在调用onCreate前,isVisibleToUser已经获取到了,isVisibleToUser为true时表示页面用户能看到,false时看不到,之后可以在用户能看到页面时进行数据加载,不提前进行加载就可以了

    @Override
    public void onStart() {
        super.onStart();
        Log.d("TAG", mTagName + " onStart()");
    
        ...
    
        if(getUserVisibleHint()) {
            pullData();
        }
    
    }
  • 相关阅读:
    Firefly AIO-3399ProC开发板安装RKNN Toolkit 1.6.0开发环境
    用1kΩ电阻可以组合出多少个阻值?
    电气元件与电气控制的保护(PPT)
    MASM汇编DOS
    可免费解锁PDF的网站
    org.springframework.web.filter.CharacterEncodingFilter cannot be cast to javax.servlet.Filter和java.lang.LinkageError: loader constraint violation: loader (instance of org/apache/jasper/servlet/JasperL
    访问联合类型中某个类型特有的属性或方法
    防止攻击者篡改外部脚本
    对 state 中的数组使用 v-model
    TS 定义一个最简单的字符串数组类型
  • 原文地址:https://www.cnblogs.com/chhom/p/4726428.html
Copyright © 2011-2022 走看看