viewpager+3个Fragment通过activity来刷新界面

一、遇到的问题

使用了viewpager + 3个fragment 来加载显示界面,但是呢,当我使用FragmentStatePagerAdapter的时候

/**ViewPager的适配器
     * FragmentStatePagerAdapter
     * 只保留当前页面
     * 当页面离开视线后,就会被消除,释放其资源
     * 而在页面需要显示时,生成新的页面(这和 ListView 的实现一样)
     * 这种方式的好处就是当拥有大量的页面时,不必在内存中占用大量的内存
     */

实际上,并不会刷新,而且会预加载,当我滑动到第二页fragment的时候,会加载第三页的内容,当我滑动到第三页时加载已缓存内容,往回滑动到第二页时预加载第一页内容,只有滑动到第三页再往回滑动到第一页时更改的内容才会刷新显示在fragment上,但是问题来了,第二个不加载数据,也就意味着第二页怎么都不刷新内容。

顺着这个思路其实可以发现,那么新建一个fragment也是可以解决第二个的刷新问题,但是,需求就是只要三个fragment,而且,我们必须依次滑动才可能达到刷新界面的效果(e.g. 1->2->3->4 , 4->3->2->1),显然这种方法不行。

二、解决方法

Reference

1、了解问题

viewpager中fragment数据刷新

这里就是我遇到的情况,值得开心的是这个情况是存在的,对于我这个菜鸟来说,不知道问题是普遍的还是自己做错是最痛苦的(T^T)

正常情况下,ViewPager会默认加载当前页和当前页的左右两页。一开始当前页是下标0,所以一开始默认加载第0页(指下标,下同)和第1页。当你向右滑动,当前页为第1页时,ViewPager会加载第2页,这时一共有3页存在(第0,1,2页)。再向右滑动,当前页为第2页时,会移除第0页,加载第3页,同理向左滑动当前页为第1页时,会移除第3页。因此fragmentB触发点击事件时并不能实时改变相关控件状态和实现数据刷新。(因为fragmentB内容是listview,且每个listview的item都有一个Button,如果使用notifydatasetchanged(),那么点击一个Button,所有的Button状态都会改变)

2、找到方法解决问题–广播

如何跨Fragment使用notifyDataSetChanged()方法?

看了这个解决方法,去了解了一下eventbus,如果使用的话对目前代码变动太大,于是没有采取这种解决方法,这个问题困扰了我很久,尝试了很多的方法,但是最后使用了广播,因为简单;

分场合吧。

  1. Fragment多,采用事件总线Otto或者EventBus
  2. Fragment少,还要耦合轻点的,用Activity作为媒介接口
  3. 不在乎耦合的,自订接口或者getTargetFragment() and setTargetFragment()

博客园-作者是江北小乔:安卓任意两个或多个fragment之间的交互与刷新界面
大大写的超级好了!!!去原文看~

大大这段话太睿智了!

经过上网查阅,目前网上还没有比较靠谱全面有效的方式来实现,基本都是通过activity作为中间媒介进行传值,但是这会遇到一个问题,就是activity—>fragment传值时fragment是都新加的(add或者repalce),并不是之前就存在的fragment,所以与我所讲的不是一回事。这里讲的是所有的fragment都是加载完毕的,存在回退栈中,来实时刷新回退栈中的fragment。话不多说,上代码,主要实现原理是通过安卓的广播机制来实现的。

我的Activity

	private LocalBroadcastManager broadcastManager;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        //注册广播
        registerReceiver();
    }

    private void registerReceiver(){
        broadcastManager = LocalBroadcastManager.getInstance(this);
        IntentFilter intentFilter=new IntentFilter();
        intentFilter.addAction("jerry");
        broadcastManager.registerReceiver(mRefreshReceiver, intentFilter);
    }

    private BroadcastReceiver mRefreshReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String change = intent.getStringExtra("change");
            if ("yes".equals(change)) {
                // 这地方只能在主线程中刷新UI,子线程中无效,因此用Handler来实现
                new Handler().post(new Runnable() {
                    public void run() {
                        //在这里来写你需要刷新的地方
                        //例如:testView.setText("恭喜你成功了");
                        refresh();                    //自定义的方法
                        Toast.makeText(AlbumActivity.this,"ok",Toast.LENGTH_SHORT).show();
                        Log.d("cchh", "ok: All!!!!????");

                    }
                });
            }
        }
    };
    
    //记得广播注销哦,不然会导致堵塞的
    protected void onDestroy() {
        super.onDestroy();
        //注销广播
        broadcastManager.unregisterReceiver(mRefreshReceiver);
    }

在AlbumFragment中需要刷新的地方添加

				Intent intent = new Intent("jerry");   //创建intent对象
                intent.putExtra("change", "yes");
				//intent.putExtra(albumBean.path,)   //将要传递的值附加到intent对象
                LocalBroadcastManager.getInstance((AlbumActivity) getActivity()).sendBroadcast(intent);
                Log.d("cchh", "onClick: 长按删除广播All");

以及我在AlbumPreviewFragment中一个返回键的时候也想刷新数据

			//返回
            @Override
            public void onRecall() {
                    getActivity().finish();
                    if (isDelect){
                        Log.d("cchh", "onRecall");
                        Intent intent = new Intent("jerry");
                        intent.putExtra("change","yes");
                        LocalBroadcastManager.getInstance(getContext()).sendBroadcast(intent);
                        Log.d("cchh", "onClick: 广播成功");
                        isDelect=false;
                    }

            }

总结

这里还参考了两篇写广播的文章:

Reference:

Android中广播使用小结
作者:曹丰斌(简书)
在这里插入图片描述

android广播简明介绍
作者:追风 (知乎)

广播在注册方式上可以分为动态注册和静态注册两种方式

动态注册:指的是在程序代码中进行广播注册的过程。下图展示了基于动态注册方式的广播代码结构。
在这里插入图片描述

第一部分:使用IntentFilter()设置自身期望捕获到的广播信号,这个信号要和发出的广播信号一直才会响应
第二部分:内部类NetworkChangeReceiver继承BroadcastReceiver,凡是需要监听广播信号的,都必须继承BroadcastReceiver类并实现其中的onReceive方法。
第三部分:registerReceiver将NetworkChangeReceiver的对象和IntentFilter的对象进行注册,以便接收传来的广播信号
第四部分:unregisterReceiver取消注册,任何注册了广播信号的对象都必须要实现取消注册的功能
上面程序的广播实现在onCreate方法中,这意味着程序必须打开才能接收到广播。

参考:

Viewpager超详解
《 Android基础:片段,看这篇就够了》
最详细的Tablayout的用法

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值