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中的onBtnClick()方法 
        }  
    }  
}  

这样任何Activity均可实现OnFragmentClickListener接口来处理Fragment1中的按钮逻辑,实现了FragmentActivity之间的解耦。

当然也可以设置一个set接口的方法,在Activity中使用该方法将自己传入。Activity当然也要实现了该方法。这是比较经典的回调。

以下即为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(Bitmap 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 KeepDataFragment dataFragment; 
    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 =(KeepDataFragment) fm.findFragmentByTag("data");//获取被保存Fragment 
        if (dataFragment == null)  { //如果没有就新建一个
            dataFragment = new KeepDataFragment(); 
            fm.beginTransaction().add(dataFragment, "data").commit(); 
        } 
        mBitmap = dataFragment.getData();//直接获得数据
        if (mBitmap ==null) { 
           //下载任务并设置给ImageView
        } else{ 
           mImageView.setImageBitmap(mBitmap); 
        } 
    }    
    @Override 
    public voido nDestroy()  { 
       super.onDestroy(); 
       dataFragment.setData(mBitmap); //Activity销毁时保存数据
    }
}  

MainActivityonCreate()首先获取指定TAG的Fragment,如果为空则创建,此时获取内部维护的数据也为空,则进行下载并显示的逻辑。

Activity在销毁时在onDestroy()中保存了数据。这样Activity重建时就能找到指定TAG的Fragment,并直接获取到缓存数据。

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值