android笔记之首页框架搭建

首页采用viewpage+fragment实现,底部tab实现活动,消息,动态和个人页面的分类展示,viewpage不可以滑动。这里涉及到以下技术点:
1. pageadapter的选择,android提供了两种显示fragment的pageadapter,fragmentpageadapter和FragmentStatePagerAdapter,它们的区别如下,fragmentpageadapter主要用于缓存数据,一般用于静态数据的page,FragmentStatePagerAdapter主要用于实时刷新数据,一般用于动态数据的page。由于fragment会缓存页面,所以对于内存要求严格或者fragment保存的数据较多占用内存较大的情况下,应当考虑使用fragmentstatepageadapter,其实总的来说就是时间和空间的选择,fragmentpageadapter是通过空间换时间来提高性能,而fragmentstatepageadapter是通过时间换空间来降低内存消耗。因为我们这里fragment的数量并不多,只有4个,所以就使用了fragmentpageadapter
2. viewpage不可滚动,需要在viewpage的onInterceptTouchEvent()和onTouchEvent()中返回false,以保证viewpage不会拦截其子控件的事件。

遇到的坑:
1. 最初的做法是使用fragmentpageadapter缓存fragments,然后根据选择的tab来显示相应的fragmet,这里遇到一个问题就是内存重启后,tab和fragmentpageadapter里面缓存的fragment对应出错,fragmentpageadapter里面在内存重启后并没有如同view一样自动保存fragment的状态,这点是自己的理解错误。
2. fragment的懒加载实现,由于viewpage的预加载机制会带来一定的性能损失和流量消耗,所以我们控制fragment在可见状态下才加载数据,这样做的目的是优化,按需加载。一般是通过重写setUserVisibleHint()来实现。

在活动fragment中使用了viewpage+fragment来完成产品的业务需求。这里就涉及到了fragment的嵌套,所以需要注意getFragmentManager()和getChildFragmentManager()的使用。另外系统自动为我们保存了activity或者fragment内的fragment,当我们需要对fragment做处理时,通过以下方式即可:

try {
            List<Fragment> fragments = getChildFragmentManager().getFragments();
            for (int i = 0; i < fragments.size(); i++) {
                if (fragments.get(i) instanceof ActivityFragment) {
                    ActivityFragment fragmentActivity = (ActivityFragment) fragments.get(i);
                }

            }
        } catch (Exception e) {

        }

viewpage在使用fragmentpageadapter时会遇到一个使用notifyDatasetChanged()刷新页面无效的问题,这个在网络上普遍存在,也有相应的解决办法。我使用的方法如下:

@Override
    public int getCount() {
        return fragments == null ? 0 : fragments.size();
    }

    @Override
    public Fragment getItem(int position) {
        return fragments.get(position);
    }

    @Override
    public int getItemPosition(Object object) {
        return POSITION_NONE;
    }

    public void setSource(ArrayList<ActivityFragment> fragments) {
        if (this.fragments != null && !this.fragments.isEmpty()) {
            FragmentTransaction ft = fm.beginTransaction();
            for (ActivityFragment f : this.fragments) {
                ft.remove(f);
            }
            ft.commit();
            fm.executePendingTransactions();
        }

        this.fragments = fragments;
        notifyDataSetChanged();
    }

继承pageadapter并重写getItemPosition()方法,为什么要重写该方法呢?因为只有当getItemPosition()的返回值为POSITION_NONE的时候,viewpage才会调用getItem()方法,这样只要我们在getItem()方法中刷新fragment就可以正常刷新数据和UI了。这种方法有些暴力,因为fragment的创建代价还是较大的,通过重写instantiateItem()方法,可以复用已有的fragment,目前app没有采用这种方式,后续可以考虑使用该方式优化。所以一种更加优雅的方式为:

@Override
public Object instantiateItem(ViewGroup container, int position) {
    ActivityFragment fragment = (ActivityFragment) super.instantiateItem(container, position);
    Model data = datas.get(position);
    fragment.setData(data);
    return fragment;
}

我们知道fragment与activity通信一般使用接口的形式,比如让activity实现fragment中定义的某个接口,然后当fragment想要发送消息时回调该接口即可。然而当要实现activity给fragment发送消息时其实也可以采用接口的形式,让fragment实现activity中定义的某个接口,当activity想要给fragment发送消息时,回调该接口。目前app中采用直接获取fragment对象并调用相应method的形式,这种方法耦合性大,需要改进。

猜你喜欢

转载自blog.csdn.net/okgays/article/details/51718165
今日推荐