美文网首页
Android-HandlerThread

Android-HandlerThread

作者: zzq_nene | 来源:发表于2021-01-20 18:19 被阅读0次

    在外部线程并不能拿到匿名内部类线程对象的Looper。比如主线程,创建了一个Thread对象,并不能通过Thread对象获取到该Thread的Looper对象。
    而如果将Thread的Looper写全局对象,那么就存在耦合,并不会随着线程Thread的消失而消失。
    HandlerThread就是一个线程。在HandlerThread中的run方法中,自动帮我们完成了Looper.prepare和Looper.loop()。
    HandlerThread存在的意义主要是:
    方便初始化,方便取线程Looper对象
    保证了线程安全
    解决有可能的异步问题。
    面试:多线程的锁机制。
    当有人通过HandlerThread的getLooper()方法获取线程对应的Looper对象的时候,如果Looper对象为null,那么就会调用wait()等待。而在HandlerThread的run方法中,如果Looper.prepare()成功之后,就会调用notifyAll()通知需要获取锁。
    wait():会释放锁
    notifyAll():不会释放当前持有的锁,只是会唤醒其他等待这个锁的线程,但是并不意味着会立马执行,需要等待notifyAll()所在的锁中的代码执行完成并且释放锁之后,被唤醒的其他线程去持有锁并且继续执行。

    HandlerThread的应用:在IntentService中
    IntentService初始化之后,实现onHandleIntent方法,而在IntentService中处理Handler消息的时候,就是调用onHandleIntent方法进行处理。
    而IntentService就是可以在Service中实现耗时操作,其实就是在其内部有一个ServiceHandler,而ServiceHandler的创建,就是通过HandlerThread对象获取到子线程的Looper对象,然后创建了ServiceHandler对象。
    IntentService.ServiceHandler源码:

    private final class ServiceHandler extends Handler {
        public ServiceHandler(Looper looper) {
            super(looper);
        }
    
        @Override
        public void handleMessage(Message msg) {
            onHandleIntent((Intent)msg.obj);
            // 处理消息之后,停止Service,自己停止自己。
            stopSelf(msg.arg1);
        }
    }
    

    IntentService.onCreate()源码:

    @Override
    public void onCreate() {
        // TODO: It would be nice to have an option to hold a partial wakelock
        // during processing, and to have a static startService(Context, Intent)
        // method that would launch the service & hand off a wakelock.
    
        super.onCreate();
        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
        thread.start();
    
        mServiceLooper = thread.getLooper();
        // 创建子线程HandlerThread对象的Handler
        mServiceHandler = new ServiceHandler(mServiceLooper);
    }
    

    Service一般用于处理后台耗时任务。
    IntentService会维持一个子线程独有的消息队列,保证每一个任务都是在同一个线程。这样就可以保证在IntentService一定是处理的同一个线程的任务。这样就可以保证任务在同一个线程中按照先后顺序执行。
    应用需求:一项任务分成几个子任务,子任务按顺序先后执行,子任务全部执行完成之后,这项任务才算成功。
    这个需求可以用多个线程来处理,一个线程处理完->下一个线程->下一个线程
    IntentService也可以帮助我们实现这个需求。而且,能够很好的管理线程,保证只有一个子线程处理工作,而且是一个一个的完成任务,有条不紊的进行对多个子任务的处理。
    IntentService的使用:

    public class MyIntentService extends IntentService {
    
      /** 
        * 在构造函数中传入线程名字
        **/  
        public myIntentService() {
            // 调用父类的构造函数
            // 参数 = 工作线程的名字
            super("myIntentService");
        }
    
       /** 
         * 复写onHandleIntent()方法
         * 根据 Intent实现 耗时任务 操作
         **/  
        @Override
        protected void onHandleIntent(Intent intent) {
    
            // 根据 Intent的不同,进行不同的事务处理
            String taskName = intent.getExtras().getString("taskName");
            switch (taskName) {
                case "task1":
                    Log.i("myIntentService", "do task1");
                    break;
                case "task2":
                    Log.i("myIntentService", "do task2");
                    break;
                default:
                    break;
            }
        }
    
        @Override
        public void onCreate() {
            Log.i("myIntentService", "onCreate");
            super.onCreate();
        }
       /** 
         * 复写onStartCommand()方法
         * 默认实现 = 将请求的Intent添加到工作队列里
         **/  
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            Log.i("myIntentService", "onStartCommand");
            return super.onStartCommand(intent, flags, startId);
        }
    
        @Override
        public void onDestroy() {
            Log.i("myIntentService", "onDestroy");
            super.onDestroy();
        }
    }
    

    在AndroidManifest.xml中注册

    <service android:name=".myIntentService">
                <intent-filter >
                    <action android:name="cn.scu.finch"/>
                </intent-filter>
            </service>
    

    在Activity中启动IntentService

    public class MainActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
                // 同一服务只会开启1个工作线程
                // 在onHandleIntent()函数里,依次处理传入的Intent请求
                // 将请求通过Bundle对象传入到Intent,再传入到服务里
    
                // 请求1
                Intent i = new Intent("cn.scu.finch");
                Bundle bundle = new Bundle();
                bundle.putString("taskName", "task1");
                i.putExtras(bundle);
                startService(i);
    
                // 请求2
                Intent i2 = new Intent("cn.scu.finch");
                Bundle bundle2 = new Bundle();
                bundle2.putString("taskName", "task2");
                i2.putExtras(bundle2);
                startService(i2);
    
                startService(i);  //多次启动
            }
        }
    

    除了在IntentService使用HandlerThread以外:
    (1)在Fragment的生命周期管理
    Fragment一般是通过FragmentManager事务提交,而提交的时候,是通过Handler发送消息执行提交过程。
    FragmentManager中使用了Handler进行提交。

    void scheduleCommit() {
        synchronized (this) {
            boolean postponeReady =
                    mPostponedTransactions != null && !mPostponedTransactions.isEmpty();
            boolean pendingReady = mPendingActions != null && mPendingActions.size() == 1;
            if (postponeReady || pendingReady) {
                mHost.getHandler().removeCallbacks(mExecCommit);
                mHost.getHandler().post(mExecCommit);
            }
        }
    }
    

    (2)在Glide的生命周期管理也使用了类似的方式,即创建一个空的Fragment管理生命周期,如果Fragment是空的时候,先从缓存去中,如果缓存中还是空的,则重新创建一个新的Fragment,这里使用缓存的目的,是因为Fragment事务提交的时候,是通过Handler发送消息提交事务,而这个任务并不一定是立马执行,也不一定是在下一次任务来的时候就已经提交完成,因为Glide可以多线程使用。当一个线程使用创建了空的Fragment生命周期管理,那么下一个线程异步请求创建空的生命周期管理的时候,先去查询一个临时HashMap缓存,这是因为Fragment事务提交是Handler发送消息,并不能保证立马执行完成,而在临时HashMap缓存一个空的Fragment生命周期,然后经过两次的判空,而空的Fragment就算没有绑定,那么也会先在缓存中存在这个对象,那么第二个线程进来之后就不会去创建这个空的Fragment生命周期管理。

    @NonNull
    private RequestManagerFragment getRequestManagerFragment(
        @NonNull final android.app.FragmentManager fm,
        @Nullable android.app.Fragment parentHint,
        boolean isParentVisible) {
      RequestManagerFragment current = (RequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
      if (current == null) {
        current = pendingRequestManagerFragments.get(fm);
        if (current == null) {
          current = new RequestManagerFragment();
          current.setParentFragmentHint(parentHint);
          if (isParentVisible) {
            current.getGlideLifecycle().onStart();
          }
          pendingRequestManagerFragments.put(fm, current);
          fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
          handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget();
        }
      }
      return current;
    }
    

    相关文章

      网友评论

          本文标题:Android-HandlerThread

          本文链接:https://www.haomeiwen.com/subject/dzvqbktx.html