A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

本帖最后由 大山哥哥 于 2017-5-24 15:48 编辑

       今天我们来聊一点工作中很实用的东西,就是Android开发中的那些坑。这些东西在理论学习阶段几乎不会注意到,但到了实际开发阶段却经常冒出来,而且一旦出现短时间不好解决,但是当你解决的时候,又发现解决方案这么的简单。说了这么多,有点晕了吧,下面直接上干货,学会这些,至少能节省你好几天的开发时间。
       1、android:clipToPadding
       意思是控件的绘制区域是否在padding里面,默认为true,如果你设置了此属性值为false,就能实现一个在布局上事半功陪的效果。先看一个效果图:

       上图中的ListView上方有一块灰色的区域,向上滑动ListView,这个灰色区域是可以跟着ListView移动而消失的。如果使用margin或padding,都不能实现这个效果。加一个headerView又显得大材小用,而且过于麻烦。此处的clipToPadding配合paddingTop效果就刚刚好。具体写法就是在布局文件中给ListView设置clipToPadding为false,然后设置paddingTop为灰色区域的高度即可。
        2、ListView中item点击事件无响应
        listView的Item点击事件突然无响应,问题一般是在listView中加入了button、checkbox等控件后出现的。这个问题是聚焦冲突造成的。在android里面,点击屏幕之后,点击事件会根据你的布局来进行分配的,当你的listView里面增加了button之后,点击事件第一优先分配给你listView里面的button。所以你的点击Item就失效了,这个时候你就要根据你的需求,是给你的item的最外层layout设置点击事件,还是给你的某个布局元素添加点击事件了。
       解决办法:在ListView的根控件中设置(若根控件是LinearLayout, 则在LinearLayout中加入以下属性设置)descendantFocusability属性为blocksDescendants。这样item就可以接收点击时间了,而且button或checkbox的点击时间也不会被屏蔽掉。
       3、getSupportFragmentManager()和getChildFragmentManager()
       有时候有这样的需求:在一个Fragment里面嵌套几个Fragment,也就是Fragment包含子Fragment,这样的需求并不奇葩,很常见。很容易就会想到在Fragment里面getActivity().getSupportFragmentManager()的方式管理子Fragment。然而,这么使用之后,你会发现有时候子Fragment不显示。你找代码的错误是徒劳的,因为你用错了你一直都在用的东西,这个地方,应该使用getChildFragmentManager()。我们来看看这两个api有什么区别:从名字上看,getChildFragmentManager()应该就是管理子Fragment的,我们查看一下官方的文档中的解释。
getFragmentManager()的说明:
Return the FragmentManager for interacting with fragments associated with this fragment's activity.
然后是getChildFragmentManager():
Return a private FragmentManager for placing and managing Fragments inside of this Fragment.
       很清晰了,嵌套使用Fragment的时候要使用getChildFragmentManager()来管理,不要和Activity中的FragmentManager混用。
       4、ScrollView嵌套ListView或RecyclerView
       这个需求有点奇葩,但是有时候会遇到。例如一个长页面,分成几个部分,每部分都有很多数据滚动显示,用一个竖直的LinearLayout来做是显示不完整的,这时候需要用ScrollView把ListView或RecyclerView包裹起来。这时候就会出现很多问题,看不到内容、滚动冲突。
       怎么解决呢,有以下几种方式。
       1)写一个类继承ListView,然后重写onMeasure方法
[AppleScript] 纯文本查看 复制代码
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {   
     int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);   
     super.onMeasure(widthMeasureSpec, expandSpec);   
}

ListView可以重写onMeasure解决,RecyclerView重写这个方法是行不通的。只能动态计算RecycleView,然后设置setLayoutParams。

[AppleScript] 纯文本查看 复制代码
int heightPx = DensityUtil.dip2px(getActivity(), (imageHeight + imageRowHeight) * lines);   
 MarginLayoutParams mParams = new MarginLayoutParams(LayoutParams.MATCH_PARENT, heightPx);   
 mParams.setMargins(0, 0, 0, 0);   
 LinearLayout.LayoutParams lParams = new LinearLayout.LayoutParams(mParams);   
 honorImageRecyclerView.setLayoutParams(lParams);

       其中,lines是数据的行数,可以自己根据需求设置,也可以自己动态的计算出来。可是在滑动的时候,感觉出现卡顿的现象。肯定想到是滑动冲突了。应该是ScrollView的滑动干扰到了ListView的滑动,怎么解决呢?ListView的部分解决了,接下来对ScrollView动手,把事件分发的事情做一做。这地方可以使用NestedScrollView,也可以自定义一个ScrollView。NestedScrollView就是官方的实现,很容易用,我们说下自定义的方式:

[AppleScript] 纯文本查看 复制代码
public class CustomScrollView extends ScrollView {   

     private int downY;   
     private int touchSlop;   

     public CustomScrollView(Context context) {   
         this(context, null);   
     }   

     public CustomScrollView(Context context, AttributeSet attrs) {   
         this(context, attrs, 0);   
     }   

     public CustomScrollView(Context context, AttributeSet attrs, int defStyleAttr) {   
         super(context, attrs, defStyleAttr);   
         touchSlop = ViewConfiguration.get(context).getScaledTouchSlop();   
     }   

     @Override   
     public boolean onInterceptTouchEvent(MotionEvent e) {   
         int action = e.getAction();   
         switch (action) {   
         case MotionEvent.ACTION_DOWN:   
             downY = (int) e.getRawY();   
             break;   
         case MotionEvent.ACTION_MOVE:   
             int moveY = (int) e.getRawY();   
             if (Math.abs(moveY - downY) > touchSlop) {   
                 return true;   
             }   
         }   
         return super.onInterceptTouchEvent(e);   
     }   
 }

       其实就是自己把ScrollView的事件拦截逻辑重做了一下,从而解决滚动冲突。让ListView滚动的时候不要把事件拦截就行了。
       5、java.lang.String cannot be converted to JSONObject
       这个问题也很诡异,就是一个Json字符串怎么也封装不成一个Json对象。你把json串打印出来,也没有问题,格式都对。其实,是因为服务器端在字符里加入了BOM(Byte Order Mark),其实就是开头多了"\ufeff"这个玩意,客户端代码过滤一下就行了。代码也很好写:
[AppleScript] 纯文本查看 复制代码
 if (jsonStr != null) {   
     jsonStr = jsonStr.trim();   
     if (jsonStr.startsWith("\ufeff")) {   
         jsonStr = jsonStr.substring(1);   
     }   
 }

       代码很简单,一看就懂,就不多解释了。
      6、Shape round rect too large to be rendered into a texture
      在你使用shape来做一个圆角矩形的时候,有时候会发现页面很卡顿,特别是用一个ScrollView包裹大量内容的时候。即使你的页面里面没有嵌套listview这样的组件也会很卡。后来才发现,这个圆形矩形包含的内容太多了,已经超出了手机的高度,而且可以滑好几页。最简单的解决方案就是不要使用圆角,如果你移除了圆角,也就是shape里的radius属性,问题就迎刃而解了。如果你还是想用它,那么最好使用.9图来做一个背景图。或者采取折中的方案,在当前activity中禁用掉硬件加速。
[AppleScript] 纯文本查看 复制代码
<activity android:hardwareAccelerated="false" />

      OK,这些问题看起来都是一些不起眼的小问题,实际上这些问题确实是阻碍我们工作最大的绊脚石。因为问题比较刁钻,按照常理不会想到会出问题,所以解决起来经常不知道如何下手,这些东西也只能靠经验积累。踩过的坑多了,才知道哪个坑深,哪个坑浅,以后再走这条路的时候才知道应该趟过去还是绕行。

1 个回复

倒序浏览
多谢分享
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马