当前位置:天才代写 > tutorial > 安卓教程 > Android开发的那些坑和小技巧

Android开发的那些坑和小技巧

2021-02-02 15:01 星期二 所属: 安卓教程 浏览:583

1、android:clipToPadding

意思是控制的绘图地区是不是在padding里边。默认设置为true。假如你设定了此特性数值false,就能完成一个在合理布局上事半功陪的实际效果。首先看一个设计效果图。

图中中的ListView顶端默认设置有一个间隔,往上滚动后,间隔消退,如下图所显示。

假如应用margin或padding,都不可以完成这一实际效果。加一个headerView又看起来屈才,并且过度不便。这里的clipToPadding相互配合paddingTop实际效果就正好。

一样,也有此外一个特性也很奇妙:android:clipChildren,实际请参照:【Android】奇妙的android:clipChildren特性

2、match_parent和wrap_content

照理说这两个特性一目了然,一个是添充合理布局室内空间融入父控制,一个是融入本身內容尺寸。但假如在目录如ListView中,用不对难题就变大。 ListView中的getView方式必须测算目录内容,那么就必定必须明确ListView的高宽比,onMesure才可以做精确测量。假如特定了 wrap_content,就相当于告知系统软件,假如是我一万个内容,你都给我测算表明出去,随后系统软件依照你的规定就new了一万个目标出去。那么你不悲剧了? 首先看一个图。

 

假定如今ListView有8条数据信息,match_parent必须new出七个目标,而wrap_content则必须八个。这儿牵涉到View的器重,就很少讨论了。因此 这两个特性的设定将决策getView的启用频次。

从而再拓宽出此外一个难题:getView被数次启用

什么是数次启用?例如position=0它很有可能启用了几回。看起来很怪异吧。GridView和ListView都是有很有可能出現,或许这一元凶便是 wrap_content。归根结底是View的合理布局出現了难题。假如嵌入的View过度繁杂,解决方法能够是根据编码精确测量目录所必须的高宽比,或是在 getView中应用一个小窍门:parent.getChildCount == position

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    if (parent.getChildCount() == position) {
       // does things here
    }
    return convertView;
   }

3、IllegalArgumentException: pointerIndex out of range

出現这一Bug的情景還是很无奈的。一开始我就用ViewPager PhotoView(一个开源系统控制)表明照片,在多点触摸变大变小时就出現了这个问题。一开始我怀疑是PhotoView的bug,找了大半天未果。要人命的 是不知道怎样try,老是crash。之后才知道是android留存下来的bug,源代码里没对pointer index做检查。改源代码再次编译程序不大可能吧。明知道有exception,又不可以从源头上处理,假如不许它crash,那么就只有try-catch了。解 决方法是:自定一个ViewPager并承继ViewPager。可以看下列编码:

/**
 * 自定封裝android.support.v4.view.ViewPager,重写onInterceptTouchEvent事情,捕捉系统软件等级出现异常
 */
public class CustomViewPager extends ViewPager {

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

    public CustomViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        try {
            return super.onInterceptTouchEvent(ev);
        } catch (IllegalArgumentException e) {
            LogUtil.e(e);
        } catch (ArrayIndexOutOfBoundsException e) {
            LogUtil.e(e);
        }
        return false;
    }
}

把采用ViewPager的合理布局文档,换成CustomViewPager就OK了。

4、ListView中item点击事件无响应

listView的Item点击事件忽然无响应,难题一般是在listView中添加了button、checkbox等控制后出現的。这个问题是 聚焦点矛盾导致的。在android里边,点一下显示屏以后,点击事件会依据你的合理布局来开展分派的,如果你的listView里边提升了button以后,点一下事 件第一优先选择分派让你listView里边的button。因此 你的点一下Item就无效了,这个时候你就需要依据你的要求,是让你的item的最表层 layout设定点击事件,還是让你的某一合理布局原素加上点击事件了。

解决方案:在ListView的根控制中设定(若根控制是LinearLayout, 则在LinearLayout中添加下列特性设定)descendantFocusability特性。

android:descendantFocusability="blocksDescendants"

官方网文本文档也是那样表明。

5、getSupportFragmentManager()和getChildFragmentManager() 

有一个要求,Fragment必须嵌入3个Fragment。大部分能够想起用ViewPager完成。逐渐编码是那样写的:

mViewPager.setAdapter(new CustomizeFragmentPagerAdapter(getActivity().getSupportFragmentManager(), subFragmentList));

造成的难题是嵌入的Fragment有时候会无缘无故无法显示。逐渐压根不清楚难题出現在哪儿,当你永远不知道难题的缘故时,去处理这个问题显而易见较为不便。经 过一次又一次的找寻,总算在stackoverflow上看到了一样的提出问题。说成用getChildFragmentManager()就可以了。真 是那么奇妙!

mViewPager.setAdapter(new CustomizeFragmentPagerAdapter(getChildFragmentManager, subFragmentList));

使我们看一下这两个有什么不同。最先是getSupportFragmentManager(或是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.

Basically, the difference is that Fragment’s now have their own internal FragmentManager that can handle Fragments. The child FragmentManager is the one that handles Fragments contained within only the Fragment that it was added to. The other FragmentManager is contained within the entire Activity.

早已说得较为懂了。

6、ScrollView嵌入ListView

那样的设计方案是否很怪异?2个一样会翻转的View竟然放进了一起,并且還是嵌入的关联。以前有一个那样的要求:页面一共有4个地区一部分,分别是公 司基本资料(logo、名字、法定代表人、详细地址)、公司概况、企业荣誉、企业用户评价目录。每一部分內容都必须依据內容响应式高宽比,不可以写死。敝人最先想起的也是外界 用一个ScrollView包围起来。随后把这4一部分各自用4个自定控制封裝起來。基本资料和公司概况非常简单,殊荣必须采用RecyclerView 和TextView的组成,RecyclerView(自然,用GridView还可以,3列几行的表明)储放殊荣照片,TextView表明殊荣名字。 最终一部分用户评价目录自然是ListView了。此刻,难题就出来。必须处理ListView放进ScrollView中的滚动难题和 RecyclerView的表明难题(假如RecyclerView的高宽比无法测算,你是看不见內容的)。

自然,在网上早已有相近的提出问题和解决方法了。

给一个网站地址:

四种计划方案处理ScrollView嵌入ListView难题

ListView的状况还比较好处理,雅致的作法只不过写一个类承继ListView,随后重写onMeasure方式。

@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;此外一种跟ListView的处理方法相近,界定一个类承继LinearLayoutManager或GridLayoutManager(留意:并不是承继RecyclerView),重写onMeasure方式(此方式较为不便,此处不表,下一次写一篇文章再作详细介绍)。

动态性测算高宽比以下:

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);

构思是那样的:服务器端回到殊荣照片后,因为是3列表明的方法,只必须测算必须表明两行,随后给出行距和照片的高宽比,再设定setLayoutParams就可以了。

int lines = (int) Math.ceil(totalImages / 3d);

到此,这一怪异的要求获得了处理。

但是在滚动的情况下,觉得出現卡屏的状况。聪慧的你毫无疑问想起是滚动矛盾了。应该是ScrollView的滚动影响到ListView的滚动。怎么办呢?是否可以使禁掉ScrollView的滚动?

百度一下,你毫无疑问能检索到回答的。先上编码:

/**
 * @author Leo
 * 
 *         Created in 2015-9-12
 *         阻拦ScrollView滚动事情
 */
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);
    }
}

只需了解了getScaledTouchSlop()这一方式就找邦企了。这一方式的注解是:Distance in pixels a touch can wander before we think the user is scrolling。说这是一个间距,表明滚动的情况下,手的挪动要超过这一间距才逐渐挪动控制,假如低于此间距也不开启挪动。

看起来很极致了。

可是也有此外一个难题:我每一次载入这一页面花的時间太长了,每一次由其他页面运行这一页面时,都需要卡上1~2秒,并且因手机配置時间不一。并并不是因为互联网要求,取数据信息由子进程做,跟UI进程无关。那样的感受自身看过都很难受。

几日过去,還是那般。立刻要给老总演试了。那样的感受要被骂十次呀。

难道说跟ScrollView的嵌入相关?

行吧,那么我重新构建编码。无需ScrollView了。立即用一个ListView,随后add一个headerView储放其他內容。由于控制封裝得还算好,没改是多少合理布局就OK了,一运作,顺畅丝滑,一切得到解决!

原本便是那么简易的难题,为何非要用ScrollView嵌入呢?

stackoverflow早已对你说了,别这样嵌入!别这样嵌入!别这样嵌入!关键的事儿说三遍。

ListView inside ScrollView is not scrolling on Android

自然,从android 5.0 Lollipop逐渐出示了一种新的API适用置入滚动,这时,让像那样的要求也可以非常好完成。

这里给一个网站地址,大伙儿有兴趣爱好自主掌握,这里不会再探讨。

Android NestedScrolling 实战演练

7、EmojiconTextView的setText(null)

它是开源系统小表情库com.rockerhieu.emojicon中的TextView增强版。坚信很多人采用过这一开源系统工具箱。TextView用setText(null)完全没问题。但EmojiconTextView setText(null)后就悲剧了,立即crash,表明的是null pointer。逐渐我怀疑时这一view没复位,但并并不是。那么就调节一下呗。

@Override
public void setText(CharSequence text, BufferType type) {
    SpannableStringBuilder builder = new SpannableStringBuilder(text);
    EmojiconHandler.addEmojis(getContext(), builder, mEmojiconSize);
    super.setText(builder, type);
}

EmojiconTextView中的setText来看没有什么难题。点SpannableStringBuilder进来看一下,源代码原来是这个样子的:

/**
 * Create a new SpannableStringBuilder containing a copy of the
 * specified text, including its spans if any.
 */
public SpannableStringBuilder(CharSequence text) {
    this(text, 0, text.length());
}

行吧。难题早已找到,text.length(),不空指针才怪。

text = text == null ? "" : text;
SpannableStringBuilder builder = new SpannableStringBuilder(text);

加一行分辨就可以了。

8、cursor.close()

一般来说,database的开和关不怎么会忘掉,但游标的应用很有可能并不会造成过多高度重视,尤其是游标的随便应用。例如用ContentResolver融合Cursor查看SD卡中照片,非常容易写成下列的编码:

Cursor cursor = contentResolver.query(uri, null, MediaStore.Images.Media.MIME_TYPE   "=? or "
                          MediaStore.Images.Media.MIME_TYPE   "=?", new String[] { "image/jpeg", "image/png" },
                        MediaStore.Images.Media.DATE_MODIFIED);
while (cursor.moveToNext()) {
    // TODO     
}

cursor也不做非空分辨,并且通常在关掉游标的情况下不留意有可能出现异常抛出去。

之前在新项目中,经常会出现因为游标没立即关掉或关掉出出现异常没解决好造成其他的难题造成,并且难题看上去十分的怪异,不太好处理。之后,我将全部新项目中相关游标的应用重新构建一遍,之后就再没产生过相近的难题。

标准非常简单,全部Cursor的申明为:

Cursor cursor = null;

且放到try-catch外边;必须采用cursor,先做非空分辨。随后在方式的最终用一个java工具解决游标的关掉。

/**
 * @author Leo
 * 
 *         Created in 2015-9-15
 */
public class IOUtil {
    private IOUtil() {
    }
    public static void closeQuietly(Closeable closeable) {
        if (closeable != null) {
            try {
                closeable.close();
            } catch (Throwable e) {
            }
        }
    }
    public static void closeQuietly(Cursor cursor) {
        if (cursor != null) {
            try {
                cursor.close();
            } catch (Throwable e) {
            }
        }
    }
}

我觉得,那样就没必要在每一个地区都try-catch-finally了。

9、java.lang.String cannot be converted to JSONObject

分析服务器端回到的JSON字符串数组时,竟然抛出去了这一出现异常。调节没发觉一切难题,看上去是一切正常的JSON文件格式。之后发觉竟然是JSON串多了BOM(Byte Order Mark)。服务器端的编码由PHP完成,有时候开发设计为了更好地改动便捷,立即用windows文本文档开启储存,引进了人的眼睛看不见的难题。实际上便是多了”\ufeff”这一东西,手机客户端编码过虑一下就可以了。

// in case: Value of type java.lang.String cannot be converted to JSONObject
// Remove the BOM header
if (jsonStr != null) {
    jsonStr = jsonStr.trim();
    if (jsonStr.startsWith("\ufeff")) {
        jsonStr = jsonStr.substring(1);
    }
}

10、Shape round rect too large to be rendered into a texture

环形矩形框很大?

一开始我发现了一个acitivity中的scrollView滚动一顿一顿的,而事实上沒有嵌入一切的目录控制如ListView、GridView,包括的只不过是一些TextView、ImagView等。看过下Eclipse中log輸出,发觉出現了这一warn等级的提醒。难道说是我还在表层嵌入了这一环形矩形框?我还在许多地区都用了呀,为什么就这个页面出現难题了?

之后才发觉,这一环形矩形框包括的內容太多了,早已超过了手机上的高宽比,并且能够滑多页。

StackOverFlow上有些人说:The easiest solution is to get rid of the rounded corners. If you remove the rounded corners and use a simple rectangle, the hardware renderer will no longer create a single large texture for the background layer, and won’t run into the texture size limit any more.

也是有提议:to draw onto the canvas.

实际连接:How Do Solve Shape round rect too large to be rendered into a texture

我试了下自定控制LinearLayout,根据canvas开展draw,没能处理。除掉radius属性确实行得通,可我觉得保存该怎么办?

还有一个解决方案,根据在androidManifest.xml中禁止使用硬件加速器,为了更好地操纵粒度分布,我只在这里activity中禁止使用此作用。

<activity android:hardwareAccelerated="false" />

参照:

android:clipToPadding和android:clipChildren

HowTo: ListView, Adapter, getView and different list items’ layouts in one ListView

android ListView 在复位时数次启用getView()根本原因

java.lang.IllegalArgumentException: pointerIndex out of range Exception – dispatchTouchEvent

What is difference between getSupportFragmentManager() and getChildFragmentManager()

 

    关键字:

天才代写-代写联系方式