存在的问题

1. 默认情况下,ViewPager会根据setOffscreenPageLimit()方法设置的大小,自动预加载
2. 还是根据setOffscreenPageLimit()方法设置的大小,会去销毁fragment视图

下面的图说明情况

滑动fragment1,此时会预加载fragment2,滑动到fragment2会预加载fragment3,但是滑动到fragment3,此时会调用fragment1的destroyview方法,销毁视图。当重新滑动到fragment1才会重新调用fragment1的oncreateview方法。注意此时并不会销毁实例,不会调用ondestroy方法

这样就存在两个问题
1.pagerview频繁切换,导致fragment1.fragment3在频繁的调用destroyview和oncreateview方法,重新创建视图。这样也浪费了大量的资源,用户体验不佳,虽然内存消耗比较低
2.因为切换到fragment1的时候,同时预加载了fragment2,如果此时fragment2也有大量的耗时网络请求要做,如果应用对启动反应速度比较敏感,所以此时做了多余的工作。能否把这些耗时的工作延迟加载,也是个问题

解决方案

1.  防止频繁的销毁视图,setOffscreenPageLimit(2)/或者重写PagerAdaper的destroyItem方法为空即可

setOffscreenPageLimit(2)

//Set the number of pages that should be retained to either side of the current page in the view hierarchy in an idle state.Pages beyond this limit will be recreated from the adapter when needed.You should keep this limit low, especially if your pages have complex layouts. This setting defaults to 1.

大概意思就是说:

设置当前page左右两侧应该被保持的page数量,超过这个限制,page会被销毁重建(只是销毁视图),onDestroy-onCreateView,但不会执行onDestroy。尽量维持这个值小,特别是有复杂布局的时候,因为如果这个值很大,就会占用很多内存,如果只有3-4page的话,可以全部保持active,可以保持page切换的顺滑

这下很好理解了,默认情况下是1,所以当前fragment左右两侧,就会被保持1页pager,所以上述切换到fragment2并不会销毁任何视图,但是到fragment1,3会。这里注意这个值,是左右两侧能够维持的page,所以如果setOffscreenPageLimit(2),那么就不会频繁的销毁了

destroyItem()

//super.destroyItem(Container, position, object);  注释掉调用父类方法即可

2.  取消预加载,可以fragment的setUserVisibleHint实现,具体实现参考代码示例

setUserVisibleHint

//Set a hint to the system about whether this fragment's UI is currently visible to the user. This hint defaults to true and is persistent across fragment instance state save and restore.An app may set this to false to indicate that the fragment's UI is scrolled out of visibility or is otherwise not directly visible to the user. This may be used by the system to prioritize operations such as fragment lifecycle updates or loader ordering behavior.

大概意思就是:fragment对用户可见,isVisibleToUser为true,不可见isVisibleToUser为false。对应于viewpager,当前pager,非当前pager

代码:

public abstract class BaseFragment extends Fragment {  
    /** Fragment当前状态是否可见 */  
    protected boolean isVisible;  
  
    //setUserVisibleHint  adapter中的每个fragment切换的时候都会被调用,如果是切换到当前页,那么isVisibleToUser==true,否则为false  
    @Override  
    public void setUserVisibleHint(boolean isVisibleToUser) {  
        super.setUserVisibleHint(isVisibleToUser);  
        if(isVisibleToUser) {  
            isVisible = true;  
            onVisible();  
        } else {  
            isVisible = false;  
            onInvisible();  
        }  
    }  
      
    /** 
     * 可见 
     */  
    protected void onVisible() {  
        lazyLoad();       
    }  
          
    /** 
     * 不可见 
     */  
    protected void onInvisible() {        
    }  
      
    /** 
     * 延迟加载 
     * 子类必须重写此方法 
     */  
    protected abstract void lazyLoad();  
}

  

public class CustomListFragment extends BaseFragment {  
  
    private Context context;  
  
    private static final String FRAGMENT_INDEX = "fragment_index";  
    private final int FIRST_FRAGMENT = 0;  
    private final int SECOND_FRAGMENT = 1;  
    private final int THIRD_FRAGMENT = 2;  
  
    private TextView contentText;  
    private ProgressBar progressBar;  
  
    private int mCurIndex = -1;  
    /** 
     * 标志位,标志已经初始化完成 
     */  
    private boolean isPrepared;  
    /** 
     * 是否已被加载过一次,第二次就不再去请求数据了 
     */  
    private boolean mHasLoadedOnce;  
  
    /** 
     * 创建新实例 
     * 
     * @param index 
     * @return 
     */  
    public static CustomListFragment newInstance(int index) {  
        Bundle bundle = new Bundle();  
        bundle.putInt(FRAGMENT_INDEX, index);  
        CustomListFragment fragment = new CustomListFragment();  
        fragment.setArguments(bundle);  
        return fragment;  
    }  
  
    @Override  
    public void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        context = getActivity();  
  
        Bundle bundle = getArguments();  
        if (bundle != null) {  
            mCurIndex = bundle.getInt(FRAGMENT_INDEX);  
        }  
    }  
  
    @Override  
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {  
        View view = inflater.inflate(R.layout.fragment, container, false);  
        contentText = (TextView) view.findViewById(R.id.content);  
        progressBar = (ProgressBar) view.findViewById(R.id.progressbar);  
        isPrepared = true;  
        lazyLoad();  
        return view;  
    }  
  
    @Override  
    protected void lazyLoad() {  
        if (!isPrepared || !isVisible || mHasLoadedOnce) {  
            return;  
        }  
        new AsyncTask<Void, Void, Boolean>() {  
            @Override  
            protected void onPreExecute() {  
                super.onPreExecute();  
                progressBar.setVisibility(View.VISIBLE);  
            }  
            @Override  
            protected Boolean doInBackground(Void... params) {  
                try {  
                    Thread.sleep(2000);  
                    //在这里添加调用接口获取数据的代码  
                    //doSomething()  
                } catch (Exception e) {  
                    e.printStackTrace();  
                }  
                return true;  
            }  
            @Override  
            protected void onPostExecute(Boolean isSuccess) {  
                if (isSuccess) {  
                    // 加载成功  
                    setView();  
                    mHasLoadedOnce = true;  
                } else {  
                    // 加载失败  
                }  
                progressBar.setVisibility(View.GONE);  
            }  
        }.execute();  
    }  
  
    private void setView() {  
        // 根据索引加载不同视图  
        switch (mCurIndex) {  
            case FIRST_FRAGMENT:  
                contentText.setText("第一个");  
                break;  
  
            case SECOND_FRAGMENT:  
                contentText.setText("第二个");  
                break;  
  
            case THIRD_FRAGMENT:  
                contentText.setText("第三个");  
                break;  
        }  
    }  
  
    @Override  
    public void onDestroyView() {  
        super.onDestroyView();  
        Log.d("LiaBin", "onDestroyView: curIndex=" + mCurIndex);  
    }  
  
    @Override  
    public void onDestroy() {  
        super.onDestroy();  
        Log.d("LiaBin", "onDestroy: curIndex=" + mCurIndex);  
    }  
}  

  

硅谷新闻3--使用Android系统自带的API解析json数据的更多相关文章

  1. 系统自带的NSJSONSerialization解析json文件

    #import "ViewController.h" #import "Student.h" #import "GDataXMLNode.h" ...

  2. Android中实现全屏、无标题栏的两种办法(另附Android系统自带样式的解释)

    在进行UI设计时,我们经常需要将屏幕设置成无标题栏或者全屏.要实现起来也非常简单,主要有两种方法:配置xml文件和编写代码设置. 1.在xml文件中进行配置 在项目的清单文件AndroidManife ...

  3. 我的Android进阶之旅------>解决Jackson、Gson解析Json数据时,Json数据中的Key为Java关键字时解析为null的问题

    1.问题描述 首先,需要解析的Json数据类似于下面的格式,但是包含了Java关键字abstract: { ret: 0, msg: "normal return.", news: ...

  4. Android中使用Gson解析JSON数据的两种方法

    Json是一种类似于XML的通用数据交换格式,具有比XML更高的传输效率;本文将介绍两种方法解析JSON数据,需要的朋友可以参考下   Json是一种类似于XML的通用数据交换格式,具有比XML更高的 ...

  5. Android 学习笔记之Volley(七)实现Json数据加载和解析...

    学习内容: 1.使用Volley实现异步加载Json数据...   Volley的第二大请求就是通过发送请求异步实现Json数据信息的加载,加载Json数据有两种方式,一种是通过获取Json对象,然后 ...

  6. Android网络之数据解析----使用Google Gson解析Json数据

    [声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/4 ...

  7. php怎么解析utf-8带BOM编码的json数据,php解析json数据返回NULL

    今天遇到一个问题,json_decode解析json数据返回null,试了各种方法都不行,最后发现,原来是json文件编码的问题. 当json_decode解析utf-8带BOM格式的json数据时, ...

  8. Android解析Json数据之Gson解析

    Gson是谷歌官方提供的解析json数据的工具类.json数据的解析能够使用JSONObject和JSONArray配合使用解析数据,可是这样的原始的方法对于小数据的解析还是有作用的,可是陪到了复杂数 ...

  9. Android中使用HttpURLConnection实现GET POST JSON数据与下载图片

    Android中使用HttpURLConnection实现GET POST JSON数据与下载图片 Android6.0中把Apache HTTP Client全部的包与类都标记为deprecated ...

随机推荐

  1. 多线程锁--怎么理解Condition

    在java.util.concurrent包中,有两个很特殊的工具类,Condition和ReentrantLock,使用过的人都知道,ReentrantLock(重入锁)是jdk的concurren ...

  2. Windows CMD命令大全(转)

    Windows CMD命令大全   命令简介 cmd是command的缩写.即命令行 . 虽然随着计算机产业的发展,Windows 操作系统的应用越来越广泛,DOS 面临着被淘汰的命运,但是因为它运行 ...

  3. C++中文件按行读取和逐词读取 backup

    http://blog.csdn.net/zhangchao3322218/article/details/7930857 #include  <iostream>#include  &l ...

  4. git 在提交之前撤销add操作

    问题 在使用git时,在未添加.ignore文件前使用 git add . 将所有文件添加到库中,不小心将一些不需要加入版本库的文件加到了版本库中.由于此时还没有提交所以不存在HEAD版本,不能使用 ...

  5. sencha touch api 使用指南

    本文主要讲解如何使用sencha touch的api以及如何查看api中官方示例源码 前期准备 1.sdk 下载地址:http://www.sencha.com/products/touch/down ...

  6. Redis和Memcached的区别

    From: https://www.biaodianfu.com/redis-vs-memcached.html Redis的作者Salvatore Sanfilippo曾经对这两种基于内存的数据存储 ...

  7. IT项目经理成长手记

    1.流程化,项目化,工业化: 2.启动,规划,实施,监控,收尾.五个过程 3.需求管理,项目策划,项目监控,集成项目管理,定量项目管理,供应商协议管理,风险管理. 4.项目经理是熬出来的,伟大都是熬出 ...

  8. MyBatis知多少(21)更新操作

    上一章展示了如何使用MyBatis对表进行读取操作.本章将告诉你如何在一个表中使用MyBatis更新记录. 我们已经在MySQL下有EMPLOYEE表: CREATE TABLE EMPLOYEE ( ...

  9. Git 文件比较

    Git 的三个作业场: 工作区(Work Tree) 项目根目录下 .git 目录以外所有区域,是编辑项目文件的地方. 缓存区(Index) 工作区文件必须先保存在缓存区,之后从缓存区保存到仓库. 仓 ...

  10. 找工作--Java相关

    Hi 各位 首先自我描述一下,80后程序员,现在在做Eclipse插件开发. 求Java相关职位(Java/Swing/Eclipse Plugin/Python etc), 或者Linux下C相关职 ...