ANR 定位和修正( Application Not Responding)

ANR 定位和修正( Application Not Responding)

1、ANR排错一般有三种情况

KeyDispatchTimeout(5 seconds) –主要类型按键或触摸事件在特定时间内无响应

BroadcastTimeout(10 secends) –BroadcastReceiver在特定时间内无法处理完成

ServiceTimeout(20 secends) –小概率事件 Service在特定的时间内无法处理完成(Service 相当于主线程)

发生原因

主线程被IO操作(从4.0之后网络IO不允许在主线程中)阻塞。

主线程中存在耗时的计算

主线程中错误的操作,比如Thread.wait或者Thread.sleep等 Android系统会监控程序的响应状况

使用AsyncTask处理耗时IO操作。

内存抖动(onDraw) 内存频繁的分配和回收,频繁的gc会导致UI卡顿,严重的时候导致out of memory error(ANR)(内存超过分配的最大值)

2、如何避免

UI线程尽量只做跟UI相关的工作

耗时的操作(比如数据库操作,I/O,连接网络或者别的有可能阻塞UI线程的操作)把它放在单独的线程处理

尽量用Handler来处理UIthread和别的thread之间的交互.

使用Thread或者HandlerThread时,调用Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND)设置优先级,否则仍然会降低程序响应,因为默认Thread的优先级和主线程相同。

使用Handler处理工作线程结果,而不是使用Thread.wait()或者Thread.sleep()来阻塞主线程。

Activity的onCreate和onResume回调中尽量避免耗时的代码

BroadcastReceiver中onReceive代码也要尽量减少耗时,建议使用IntentService处理。

3、ANR定位和修正

如果开发机器上出现问题,我们可以通过查看/data/anr/traces.txt即可,最新的ANR信息在最开始部分。

如何解决内存抖动问题:

尽量避免在循环体内创建对象,应该把对象创建移到循环体外。

注意自定义View的onDraw()方法会被频繁调用,所以在这里面不应该频繁的创建对象。

当需要大量使用Bitmap的时候,试着把它们缓存在数组中实现复用。

         对于能够复用的对象,同理可以使用对象池将它们缓存起来。

Bitmap的复用:以LruCache的bitmapPool 为列

public interface BitmapPool {

void put(Bitmap bitmap);

/**

* 获得一个可复用的Bitmap

* 三个参数计算出 内存大小

* @param width

* @param height

* @param config

* @return

*/

Bitmap get(int width,int height,Bitmap.Config config);

void clearMemory();

void trimMemory(int level);

}

public class LruBitmapPool extends LruCache<Integer, Bitmap> implements BitmapPool {

private boolean isRemoved;

 

// 负责筛选

NavigableMap<Integer, Integer> map = new TreeMap<>();

 

/**

* 最多2 个 bitmap

*/

private final static int MAX_OVER_SIZE_MULTIPLE = 2;

 

public LruBitmapPool(int maxSize) {

super(maxSize);

}

 

/**

* 将Bitmap放入复用池

*

* @param bitmap

*/

@Override

public void put(Bitmap bitmap) {

//isMutable 必须是true

if (!bitmap.isMutable()) {

bitmap.recycle();

return;

}

int size = 0;

if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {

size = bitmap.getAllocationByteCount();

}else {

size=bitmap.getByteCount();

}

if (size >= maxSize()) {

bitmap.recycle();

return;

}

put(size, bitmap);

map.put(size, 0);

}

 

/**

* 获得一个可复用的Bitmap

*/

@Override

public Bitmap get(int width, int height, Bitmap.Config config) {

//新Bitmap需要的内存大小 (只关心 argb8888和RGB65)

int size = width * height * (config == Bitmap.Config.ARGB_8888 ? 4 : 2);

//获得等于 size或者大于size的key

Integer key = map.ceilingKey(size);

//从key集合从找到一个>=size并且 <= size*MAX_OVER_SIZE_MULTIPLE

if (null != key && key <= size * MAX_OVER_SIZE_MULTIPLE) {

isRemoved = true;

Bitmap remove = remove(key);

isRemoved = false;

return remove;

}

return null;

}

 

 

@Override

protected int sizeOf(Integer key, Bitmap value) {

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {

return value.getAllocationByteCount();

}

return value.getByteCount();

}

 

@Override

protected void entryRemoved(boolean evicted, Integer key, Bitmap oldValue, Bitmap newValue) {

map.remove(key);

if (!isRemoved) {

oldValue.recycle();

}

}

 

@Override

public void clearMemory() {

evictAll();

}

 

@Override

public void trimMemory(int level) {

if (level >= ComponentCallbacks2.TRIM_MEMORY_BACKGROUND) {

clearMemory();

} else if (level >= ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {

trimToSize(maxSize() / 2);

}

}

部分方法引入于import android.support.v4.util.LruCache;

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值