Handler,Message,MessageQueue,AsyncTask,Service小知识点

来源:互联网 发布:centos输入法下载 编辑:程序博客网 时间:2024/05/16 08:28

我一直苦恼为什么IntentService为什么同一时刻只能执行一个任务,看源码也只是HandlerThread与Handler相配合sendMessage而已,后来经过测试才发现原来一个线程中的Looper与MessageQueue取Message是像队列一样去取的,取出来的Message中的任务执行完了之后再取下一个Message,后来我测试在onHandleIntent当中开启线程来执行,然后多次startService(IntentService),发现是并发的,因为可能后面启动的线程比前面启动的线程先结束,测试代码如下:
`public class TestIntentService extends IntentService {

public static final String TAG = "TestIntentService";public TestIntentService() {    super("TestIntentService");}@Overridepublic void onCreate() {    super.onCreate();    Log.e(TAG, "onCreate");}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {    Log.e(TAG, "onStartCommand:" + intent.getIntExtra("flag", 0));    return super.onStartCommand(intent, flags, startId);}@Overrideprotected void onHandleIntent(final Intent intent) {    new Thread(){        @Override        public void run() {            try {                Thread.sleep(new Random().nextInt(5000));            } catch (InterruptedException e) {                e.printStackTrace();            }            Log.e(TAG, "onHandleIntent finish:" + intent.getIntExtra("flag", 0));        }    }.start();}

}`

  • Handler,MessageQueue,Looper,HandlerThread:一个线程只能有一个Looper和MessageQueue,Looper.loop()负责循环的去取Message,handler负责把Message加入到MessageQueue当中。默认new出来的handler它的Looper是UI主线程中的Looper,所以它能执行UI操作,并且不能执行耗时操作,但是HandlerThread产生的Looper那就是跟另外的线程绑定的Looper,它产生的Handler既可以执行UI操作,也可以执行耗时操作,因为它不会阻塞主线程,其实HandlerThread的精华之处就在这里:产生和对应线程绑定的Looper,让handler能执行耗时操作和UI操作,要不然我们想在子线程中刷新UI需要Looper.prepare()和Looper.loop(),而且loop()方法是阻塞的,不能在这之后执行其他代码。
  • AsyncTask: 这里突然想到AsyncTask也是同一时间只能执行一个任务,因为里面是采用队列来存储执行任务,然后一个一个取出来执行,其实网上有人说用AsyncTask要谨慎,否则会造成多线程并发问题,其实大可不必担心,之所以可能造成多线程问题是因为我们使用AsyncTask的时候默认使用源码里面提供的顺序任务队列,这个列队是static类型的,所以大家公用这个顺序队列来执行任务,而新的android sdk对于AsyncTask实现已经做了很大的修改,只要我们正确的调用它提供的接口就不会有什么多线程并发问题,我看了这篇博客写的不错:AsyncTask详解,这里顺便提到一点:我看AsyncTask源码里面有一句:Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);把当前线程的优先级降低,我查了下是这样的,默认开启的用户线程是nomal级别的,这个跟android的UI主线程是一样的,平常我们总是说在UI线程中执行耗时任务要开启线程就不会让卡顿界面的或者避免ANR,实际上真的是这样的吗?我现在做的项目就遇到这样的问题:我命名把所有的耗时操作(数据库读取插入等)都放在Thread里面执行,但是界面卡顿并没有改善,实际上我们自己开的线程优先级和UI主线程是一样的,会产生竞争,当我们自己启动的Thread很多的时候UI主线程有可能就处于等待状态,等待Thread执行完再执行,这就会造成卡顿,界面上呈现的就是当刷新的数据量大的时候就卡顿,刷新数据量小的时候就不卡顿。查询了下解决方案说用AsyncTask可以避免界面卡顿,但是AsyncTask也是开线程执行,只不过AsyncTask开的线程的优先级比UI主线程低,所以会优先执行UI主线程,不会阻塞UI主线程,因此不会造成界面卡顿而是在后台默默执行任务,设置线程优先级在java里面是用setPriority(),但是用android自己提供的api:setThreadPriority据说是会让线程调度更加显著?网上是这么说的,具体没测,但是我统一这种观点,既然android有提供这种接口那就尽量用android提供的接口。
  • android四大组件都市运行在主线程中的,前两天网上看到说如果是在新线程中startService的Service不是运行在主线程中的,后来我测了下发现这是错误的,我在Service里面打印当前线程的名称依然是main!差点被欺骗了,所以万事还是要自己亲测才可靠!因此广播中不能执行耗时任务,Service里面可以执行耗时任务但是不能执行网络操作,在广播中执行耗时任务要开启服务来执行而不要直接开启线程,因为可能线程还没执行完,但是广播已经无效了,这是非常不可靠的做法,我看了网上一些IM SDK在广播里面执行耗时任务都是开启Service的,Service执行完之后要按时stop释放资源
0 0
原创粉丝点击