以前在我的意识里,所认为的ANR(Application Not Response)是指只要在主线程(即UI线程)里有了耗时操作,那么系统将会在几秒的延迟之后,弹框:“程序未响应”。但是,今天在学习RxJava时,遇到了一个问题,我将Observable处理数据和回调时的线程都设置在了AndroidSchedulers.MainThread()中,然后,在设置图片语句之前加上了Thread.sleep(30000),那么,按照我原先的理解,程序会在5秒之后弹框,提示我已经ANR了。可是程序并没有弹框,而是在等待30秒之后,安安稳稳的把图片加载出来了。这就让我很费解。
这样我就确定了这个问题:为什么在主线程中,使用了阻塞线程操作的语句后,程序并没有ANR?
经过思考之后,我提出了如下假设:
1.可能是因为我使用RxJava时,对他线程调度的语句使用错误或者理解错误,导致误打误撞将耗时操作放在了子线程进行了操作,最后把他放置在了主线程显示。
2.可能是我理解错了ANR本来的意义。
提出这两种假设之后,我便进行逐一验证。
假设1的验证,在翻阅了各个不同的技术博客后,证明了我使用的语句并没有问题。
代码片段为
Subscriber<Integer> subscriber = new Subscriber<Integer>() {
@Override
public void onCompleted() {
Log.d("aaa", "onCompleted: finish!");
}
@Override
public void onError(Throwable e) {
}
@Override
public void onNext(Integer integer) {
try {
Thread.sleep(30000);
} catch (InterruptedException e) {
e.printStackTrace();
}
mImageView.setImageResource(integer);
}
};
Observable observable = Observable.create(new Observable.OnSubscribe<Integer>(){
@Override
public void call(Subscriber<? super Integer> subscriber) {
subscriber.onNext(R.drawable.cart2);
subscriber.onCompleted();
}
});
observable.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(subscriber);
注:在上述代码中出现的几个线程调度函数使用,我会重新开篇讲解。
那么既然验证了假设一是不是真正的原因,那我就开始验证假设2。
假设2认为是我理解错了ANR的含义。所以,究其根源我进行资料查阅,在一个技术博客上,我找到了如下对于定义ANR弹框的描述和ANR的判定条件。
在Android中,程序的响应性是由Activity Manager与Window Manager系统服务来负责监控的。当系统监测到下面的条件之一时会显示ANR的对话框:
*
* 对输入事件(例如硬件点击或者屏幕触摸事件),5秒内都无响应。
* BroadReceiver不能够在10秒内结束接收到任务。
本段文字摘自某大神博客:http://hukai.me/android-training-performance-anr/
仔细阅读并理解了上述的定义,我得出了结论:在ANR弹窗时,要满足上述条件其中之一,否则系统不会提示ANR。
那么为什么在主线程中放置了Thread.sleep()之后,程序并没有结束呢?这是因为在onCreate()执行时,如果没有完成绘制,那么,每个组件对于用户的输入事件就没有监听,那么系统也不会进行ANR条件的判断,所以,在sleep之后,程序会继续执行相应的UI绘制。
代码片段
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mImageView = (ImageView) findViewById(R.id.image_view);
mImageView.setImageResource(R.drawable.cart2);
try {
Thread.sleep(3000);//主线程中进行阻塞操作
} catch (InterruptedException e) {
e.printStackTrace();
}
mImageView.setImageResource(R.drawable.booklable2);
}
这样就解释了并没有报错而是阻塞之后继续执行的原因。
所以,只有在点击事件中,使用阻塞语句后,会导致ANR。
代码如下
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mImageView = (ImageView) findViewById(R.id.image_view);
mImageView.setImageResource(R.drawable.cart2);
mImageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
mImageView.setImageResource(R.drawable.booklable2);
}
}).run();
}
});
}
总结,在今后遇到不能解决的问题时,都应该先将问题抽象出来,然后对问题的答案进行假设,再逐一验证。这样效率会高些,而且也会将自己的条理性和逻辑感培养出来。