ANR爬坑

   以前在我的意识里,所认为的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();
        }
    });
}
   总结,在今后遇到不能解决的问题时,都应该先将问题抽象出来,然后对问题的答案进行假设,再逐一验证。这样效率会高些,而且也会将自己的条理性和逻辑感培养出来。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值