zoukankan      html  css  js  c++  java
  • Android开发——Fragment知识整理(二)

    0.  前言

    Android开发中的Fragment的应用非常广泛,在Android开发——Fragment知识整理(一)中简单介绍了关于Fragment的生命周期,常用API,回退栈的应用等知识。这篇将着重于介绍Fragment和Activity之间的通信以及使用Fragment保存Activity数据销毁时数据的一些知识。


    1.  FragmentActivity的通信

    Fragment是依附于Activity存在的,因此两者之间的通信在所难免。比如Fragment不能响应Intent打开,但是Activity可以,Activity通过Intent中的参数即可决定显示哪个Fragment。Activity应该承担一个Fragment管理者的作用。

    我们可以使用getFragmentManager.findFragmentByTag()或者findFragmentById()Activity中获得Fragment实例,如果在Fragment中需要Context,可以通过getActivity得到当前绑定的Activity的实例。如果该Context需要在Activity被销毁后还存在,则使用getActivity().getApplicationContext()

     Android开发——Fragment知识整理(一)中我们介绍了点击Fragment1中的按钮实现到Fragment2的跳转,考虑Fragment的重复使用,所以必须降低FragmentActivity的耦合不应该在Fragment中直接操作别的Fragment。因此点击按钮的逻辑考虑在Activity中调用。Fragment1重构如下:

    public class FragmentOne extends Fragment implements OnClickListener  {  
        private Button mBtn; 
        public interface OnFragmentClickListener {  
            void onBtnClick();  
        }  
        @Override  
        public View onCreateView(LayoutInflater inflater, ViewGroup container,  Bundle savedInstanceState)  {  
            View view = inflater.inflate(R.layout.fragment_one, container, false);  
            mBtn = (Button) view.findViewById(R.id.id_fragment_one_btn);  
            mBtn.setOnClickListener(this);  
            return view;  
        }  
        @Override  
        public void onClick(View v) {  
            if (getActivity() instanceof OnFragmentClickListener ) {  
                ((OnFragmentClickListener ) getActivity()).onBtnClick();  
            }  
        }  
    }  
    

    这样任何Activity均可实现OnFragmentClickListener 来处理Fragment1中的按钮逻辑,实现了FragmentActivity之间的解耦。以下即为Activity中的按钮逻辑,实现Fragment1Fragment2的跳转。onCreate中添加Fragment1的逻辑不变。

    private FragmentTwo two;  
    @Override  
     public void onBtnClick()  {  
            if (two == null)  {  
                two = new FragmentTwo();  
            }  
           FragmentTransaction ft= getFragmentManager().beginTransaction();  
            ft.replace(R.id.id_content, two, "TWO");  
            ft.addToBackStack(null);  
            ft.commit();  
    }  
    

    2.  Activity的异常销毁

    Android开发——Activity生命周期中我们知道,诸如屏幕旋转等操作会导致Activity的销毁重建,当然Fragment也不能幸免于难。解决方式就是使用savedInstanceState。在ActivityonCreate方法中,Fragment的实例创建需要进行特殊处理,如下所示:

    if(savedInstanceState == null)  {  
         one = new FragmentOne();  
         FragmentTransaction ft= getFragmentManager().beginTransaction();  
         ft.add(R.id.id_content, one, "ONE");  
         ft.commit();  
    }  

    这样即可实现无论Activity如何被销毁重建,都可以保证Fragment的实例不会被重复创建,数据的恢复和Activity数据恢复的机制类似,Fragment也有onSaveInstanceState()用于保存数据,然后在onCreate()onCreateView()onActivityCreated()中进行数据恢复即可。


    3.  使用Fragment保存Activity销毁之前的数据

    如果Activity在旋转屏幕时异常销毁重建时需要恢复大量的数据,比如包含bitmap,这时在onSaveIntanceState()中使用Bundle来完全恢复你Activity的状态可能是不现实的,因为Bundle中的数据需要能够被序列化和反序列化,并且Bundle不适宜携带大量数据,因此onSaveIntanceState的使用可能会因为开销过大而造成较差的用户体验。这时便可以通过维护一个Fragment(内部维护你想保持的对象引用)来优化Activity重启时的负担

    这时可能有同学会问,Activity都重建了,Fragment不会被重建吗?那是因为Activity中被标识保持的Fragments不会被销毁,因此可以使用Fragment来保存大量的数据。


    3.1  继承Fragment并在其中声明引用

    public class KeepDataFragment extends Fragment {
        //保存一个Bitmap模拟大量数据
        private Bitmap data;
    
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setRetainInstance(true);
        }
    
        public void setData(MyAsyncTask data) {
            this.data = data;
        }
    
        public Bitmap getData() {
            return data;
        }
    }
    

    这里我们创建KeepDataFragment并继承Fragment,并在其中声明需要保存的数据对象,这里是保存了一个Bitmap,然后提供gettersetter。最后一定要在onCreate调用setRetainInstance(true)


    3.2  MainActivity中的实现

    public class MainActivity extends Activity  { 
        private KeepDataFragmentdataFragment; 
        private ImageViewmImageView; 
        private BitmapmBitmap; 
     
        @Override  
        public void onCreate(BundlesavedInstanceState)  { 
           super.onCreate(savedInstanceState); 
            setContentView(R.layout.activity_main); 
    mImageView = (ImageView) findViewById(R.id.id_imageView); 
     
            FragmentManager fm= getFragmentManager(); 
            dataFragment =(RetainedFragment) fm.findFragmentByTag("data"); 
            if (dataFragment == null)  { 
                dataFragment =new RetainedFragment(); 
               fm.beginTransaction().add(dataFragment, "data").commit(); 
            } 
            mBitmap = dataFragment.getData();
            if (mBitmap ==null) { 
               //下载任务并设置给ImageView
            } else{ 
               mImageView.setImageBitmap(mBitmap); 
            } 
        }    
        @Override 
        public voidonDestroy()  { 
           super.onDestroy(); 
           dataFragment.setData(mBitmap); 
        }
    }  
    

    MainActivityonCreate()中使用Fragment中的bitmap引用,如果为空则下载并显示,如果不为空,说明是Activity在销毁时在onDestroy()中保存了数据。

    但是如果为了更好的用户体验,加入了对话框来达到ProcessDialog的效果,则会在异步任务进行时旋转屏幕出现较多问题,详情可以参考Android开发——异步任务中Activity销毁时的问题


  • 相关阅读:
    oracle 数据库服务名怎么查
    vmware vsphere 6.5
    vSphere虚拟化之ESXi的安装及部署
    ArcMap中无法添加ArcGIS Online底图的诊断方法
    ArcGIS中字段计算器(高级计算VBScript、Python)
    Bad habits : Putting NOLOCK everywhere
    Understanding the Impact of NOLOCK and WITH NOLOCK Table Hints in SQL Server
    with(nolock) or (nolock)
    What is “with (nolock)” in SQL Server?
    Changing SQL Server Collation After Installation
  • 原文地址:https://www.cnblogs.com/qitian1/p/6461455.html
Copyright © 2011-2022 走看看