zoukankan      html  css  js  c++  java
  • 用Fragment实现Tab页面切换效果初步总结

    前言:

    最近在Android项目中需要在活动中实现多页面切换的功能,第一次是实现的过程中,是让Activity同时去加载三个界面的,通过点击tab按钮对页面设置隐藏和显示,实现页面切换效果,但是后面发现这种实现方式其实存在很多问题:

    1. 首先,同时去加载三个页面,切换Activity的速度会变慢,尤其是布局中如果有很多ImageView,ImageButton等使用到图片资源的控件时,切换效果非常不好;
    2. 其次,由于使用了很多图片资源,在退出Activity的时候,像Drawable,Bitmap等一些资源并不会随着Activity的销毁而立即回收,导致手机占用很多内存空间,导致ANR(应用程序无响应)或者OOM(内存溢出)的Bug。然而,很多经验不足的Android开发人员,包括我自己,每次写Activity的时候,并没有去考虑这些问题,导致项目后面出现一系列的问题,还好没到那种无可挽回的地步,知道这点以后,一定要养成好的代码习惯。
    3. 然后,一个Activity里面会有大量的初始化控件的代码,还有其他的一些方法等等,是的Activity变的非常臃肿,难以维护,有时候出现一个错误,都不太好找。

    然后网上找到一些资料,使用Fragment去实现Tab切换,是一个很不错的方式,基本可以解决以上问题。

    我对Fragment的理解:中文翻译就叫碎片,它可以最大限度的利用手机和平板的显示空间,让开发者可以活用布局,实现很多不错的布局效果,当然要学会使用它,需要了解它的一些基本特性,方法,以及生命周期等。

    关于Fragment的详细介绍,在这里推荐鸿洋的博客http://blog.csdn.net/lmj623565791/article/details/37970961,里面分了三篇将Fragment的使用以及一些需要注意的地方讲的非常详细,篇幅比较长,所以需要拿出点耐心来看。

    第一部分:

    在开展项目的这段时间中,将遇到的一些Bug贴出来,网上并不是那么容易就能找到答案的Bug,同时也是困扰了很久才解决的

    Bug1:

    描述:(java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.zaina/wayto.com.cn.task.TaskInfoActivity}: android.view.InflateException: Binary XML file line #17: Error inflating class <unknown>)

    思路分析:起初认为是布局文件的错误,然而并没有找到答案,之后再网上搜寻答案,大部分都是说由于使用了自定义控件导致的,其他的原因也有,无奈的是,我并没有使用自定义控件,只是简单的不了个局,为控件使用了统一的Style样式而已。但是这个Bug有点奇怪的是,程序刚运行的时候,进入多页面的Activity,退出再进,没问题,随着次数的增多,程序就报这个错误。Bug的出现并没有固定的一个时机,于是,我就想到,可能是手机内存不足导致,后面用了eclipse里面一个强大的插件内存分析工具MAT(Memory Analyzer Tool) ,果然不出所料,找到了内存泄露的地方,正是布局里面使用了过多的图片资源而没有手动回收导致异常。

    解决方案:1,在Activity中使用了图片资源,一定要记得在onStop()方法里面去手动释放资源,这里贴一段代码,也是网上找到的,仅供参考。

     1 try {
     2             for (ImageView image : imageList) {
     3                 if (image!=null) {
     4 //                    Drawable d=image.getDrawable();
     5 //                    if (d!=null) d.setCallback(null);
     6 //                    image.setImageDrawable(null);
     7                     BitmapDrawable bd=(BitmapDrawable) image.getBackground();
     8                     if (bd!=null) {
     9                         System.gc();
    10                         //释放的大小
    11                         long size=Runtime.getRuntime().totalMemory();
    12                         bd.setCallback(null);
    13                         bd.getBitmap().recycle();
    14                         bd=null;
    15                         System.gc();
    16                         Log.i("TaskInfo", "释放"+size);
    17                     }
    18                 }
    19                 image=null;
    20             }
    21             imageList=null;
    22         } catch (Exception e) {
    23             e.printStackTrace();
    24             Log.i("TaskInfo", "错误"+e.getMessage());
    25         }

    2,如果程序中有多次重复使用图片资源的情况,可以使用SoftReference或者LruCache一些缓存机制去处理,而不是每次去重新加载图片,相关内容可以参考http://blog.csdn.net/xiaanming/article/details/9825113,也是写的非常好的一篇博客,里面主要是讲到使用LruCache+线程池的方式异步下载图片,设计到的技术点也很多了。


    相关参考:http://www.2cto.com/kf/201408/326452.html  

         http://stackoverflow.com/questions/7536988/android-app-out-of-memory-issues-tried-everything-and-still-at-a-loss/7576275

    Bug2:

    描述:Android FragmentManager BackStackRecord.run throwing NullPointerException

    思路分析:这是我后面采用Fragment实现多页面效果的过程中遇到的一个错误,也是困扰了我一段时间,其实后面想想,根本原因还是自己对Fragment还不够了解,使用过程中遇到的一些错误就不知道该从哪里入手分析,后面还是借助百度找到了答案。其实是使用Fragment切换页面过程中,之前用每次都是用FragmentTransaction的replace()方法去实现,没有问题,但是每次都是销毁上一个Fragment,然后重新加载新的Fragment,这样也可以,然是效率不高,因为每次切换都要重新new 一个Fragment,重新createView(),切换页面过程中会有卡顿。看了弘扬的博客里面写到,如果想要保留前一个Fragment的参数,最好使用FragmentTransaction的hide()和show()方法。

    第一次的写法:

    //Fragment 声明三个Fragment为全局变量
        private TaskDetailFragment detailFragment;
        private TaskTimeLineFragment timeLineFragment;
        private TaskAttachFragment attachFragment;
    private void ChangeFragment(int tabId){
            FragmentManager fm=getFragmentManager();
            //开发Fragment事务
            FragmentTransaction transaction = fm.beginTransaction();
            String tag="";
            switch (tabId) {
            case R.id.btn_detail:
                //详情
                if (detailFragment==null) {
                    detailFragment=TaskDetailFragment.newInstance(ticket);
                    transaction.add(R.id.taskinfo_content,detailFragment,"DETAIL");
                    break;
                }
                transaction.show(detailFragment);//隐藏
                transaction.hide(timeLineFragment);//显示
                transaction.hide(attachFragment);//显示
                break;
                /后面代码类似...
                }    

    依次按顺序,从第一个Fragment切换第二的Fragment,然后切换到第三个,都没问题,但是,从第一个切换到第二个Fragment,然后再切换回第一个Fragment时,第三个Fragment并没有加载,也就是为null,这也就是为什么会出现这个空指针的Bug。


    解决:在执行FragmentTransaction的hide(),show(),replace(),add(),detach()等方法时,首先要判断Frangment是否为null,这里就直接贴代码了,判断为空的方式在代码中体现出来了

    首先在transaction的add()方法中为Fragment制定Tag,然后用FragmentManager的findFragmentByTag("DETAIL")方法,判断返回值是否为空。

        //开始Fragment事务
            FragmentTransaction transaction = fm.beginTransaction();
    //        String tag="";
            switch (tabId) {
            case R.id.btn_detail:
                //详情
                if (detailFragment==null) {
                    detailFragment=TaskDetailFragment.newInstance(ticket);
                    transaction.add(R.id.taskinfo_content,detailFragment,"DETAIL");
                    break;
                }
                if(fm.findFragmentByTag("DETAIL")!=null)transaction.show(detailFragment);
                if(fm.findFragmentByTag("TIME")!=null)transaction.hide(timeLineFragment);
                if(fm.findFragmentByTag("ATTACH")!=null)transaction.hide(attachFragment);
                break;
    View Code

    相关参考:http://stackoverflow.com/questions/13393693/android-fragmentmanager-backstackrecord-run-throwing-nullpointerexception

    第三部分:

    最后,总结以上几点,发现自己对于Android的学习还是存在很多需要认真钻研的地方,对于自己不熟悉的技术和知识,一定要知其根源,多加练习,才能熟练运用,被自己所掌握,然后,分析问题的时候,思维不能形成固式,多发散,多参考资料,最终要的还是要多分析自己的代码,不要盲目修改,这样只会把Bug越改越多。

    ps:项目还剩不到两周时间就要交差了,自己一定要好好努力,争取把自己第一个项目做好,做到不让自己留下遗憾!

  • 相关阅读:
    BAT脚本批量调用Sql执行文件 (SqlServer 数据库)
    树莓派系统刻录到首次登陆等问题
    数据库视图的使用
    MQ配置安装
    PLSQL集合类型
    PLSQL-包函数存储过程
    Oracle 字段拆分替换在合并成一条
    ORACLE-EXP和IMP方法介绍
    javascript几个月前的时间
    返回顶部实现方式
  • 原文地址:https://www.cnblogs.com/David-Young/p/4655854.html
Copyright © 2011-2022 走看看