• Android基础之六:多线程开发


    • 多线程开发为复杂的耗时处理功能提高了效率,同时也不影响UI界面的显示效果,是在Android开发或者Java开发中经常用到的一种开发机制
    • 首先理解多线程的概念:
      • 多线程并不是真正的多个任务在同一时间点上并发执行,而是分时间片来执行,即同一个时间点上执行的任务只有一个,但是从一小段时间来看,却是许多任务并发执行
      • 多线程需要注重资源的分配
      • 需要注意Java中多线程机制
      • 主线程:即应用的UI线程
      • 辅线程:即工作线程,不能直接操作UI
    • Android中的多线程
      • Handler类
        • post方法
          • post方法并没有新起线程,仍然运行在UI线程中,其本质上还是UI线程,只是是UI现成的子线程,可以优化UI操作性能
          • 与View自带的post方法原理相同,都是在UI子线程中操作UI变化
          • Handler handler=new Handler();
            handler.post(new Runnable() {
                  @Override
                   public void run() {
                          //ToDo
                   }
            });
          • 注意:进行UI操作,例如修改UI控件属性等,虽然直接修改一般不会出现问题,但是如果在UI执行耗时操作时会造成卡顿,通常使用post来通过UI子线程来操作
        • sendMessage方法
          • post方法只适合在单独操作UI的情况下使用,如果其中涉及到耗时操作以及UI操作,例如:UI与Service通信,根据Service返回的结果修改UI,Service通常是一个比较耗时的操作,在这种情况下就不能直接使用post将耗时操作放到UI线程中,而是需要开启辅线程
          • 辅线程是独立于UI线程之外的工作线程,在工作线程中能够处理复杂的业务逻辑计算等耗时操作,但是不能直接操作UI
          • 辅线程(工作线程)与UI线程之间的交互
            • UI线程中创建Handler
            • Handler handler=new Handler(){
                  @Override
                  public void handleMessage(Message msg) {
                      super.handleMessage(msg);
                      //UI 操作
                  }
              };
            • 辅线程中创建Message消息,并向主线程的handler传递消息
            • Message message=new Message();
              message.setData(new Bundle());
              handler.sendMessage(message);
            • 这样就可以实现工作线程执行耗时操作,UI线程负责界面处理
      • HandlerThread类
        • HandlerThread可以另起新线程,但不能操作UI,属于工作线程
        • 通过HandlerThread的Looper创建的Handler使用post方法也不能操作UI,只有通过主线程的Looper创建的Handler才能操作UI,即Handler的构造方法中不传参时表示的是使用主线程的Looper创建实例
        • HandlerThread使用
          • 创建实例
          • HandlerThread ht = new HandlerThread("handler thread");
            ht.start();
          • 实例化后必须使用start启动
          • 通过HandlerThread实例的Looper创建Handler实例
          • Handler handler=new Handler(ht.getLooper());
          • 通过Handler实例进行post方法调用
          • handler.post(new Runnable(){//这里run()方法其实还是在等ht.start()调用
                public void run(){
                    Log.e("当前线程:",Thread.currentThread().getName());//这里打印的会是handler thread
                    setTitle("哈哈");//这样必定报错
                }
            });
          • 在run中如果操作UI会直接报错,因为这个县城是工作线程,不能执行UI操作,而如果想要执行UI操作,需要通过sendMessage来实现,在UI线程中再实例化一个Handler实例,重写handlerMessage方法,然后在run中向该实例发送消息
          • 这样实现会发现比较繁琐而且低效,不建议使用这种方法,即HandlerThread不建议使用
          • 并且一个HandlerThread中创建的多个Handler,在post的时候并不是并打的,而是顺序执行的
      • Java中创建线程方法
        • Java提供了通用的多线程类与接口,能够简单而直接创建工作线程,不需要使用HandlerThread创建一个handler
        • 通过new Thread(){run}.start();
        • new Thread(){
              @Override
              public void run() {
                  super.run();
                  //ToDo
              }
          }.start();
          • 该方法是通过匿名类来实例化Thread的子类实例的,在run中处理复杂操作,并发送消息到UI线程中,完成与UI线程通信
        • 通过new Thread(Runnable).start();
        • new Thread(new Runnable() {
              @Override
              public void run() {
                  
              }
          }).start();
          • 通过Runnable接口实例化Thread实例,与匿名类一样,只是两种不同的实例化方法
      • AsyncTask异步任务
        • Android中提供一种异步任务类,能够实现简单的工作线程与主线程操作,是Handler、Message的结合,使用更加简单
        • 创建异步任务
          • 注意AsyncTask中的5个可重写方法
            • onPreExcute:是在异步任务执行前执行的操作,可以操作UI线程
            • doInBackground(params):在工作线程中执行的操作
            • onProgressUpdate(values):在工作线程执行过程中如果需要操作UI,就可以在doInBackground中使用publicProgress();来广播进度,在onProgressUpdate中就会收到进度值
            • onPostExcute(retult):任务执行结束后调用,即将doInBackground中返回的结果传到该方法中
            • 在实例化AsyncTask的时候可以直接指定不同方法中参数的类型,即AsyncTask是泛型类
            • 在整个过程中只有一个方法doInBackground是在工作线层中运行的,其他三个方法都是在主线程中运行的
          • 实例化
          • AsyncTask<String,String,String> asyncTask=new AsyncTask<String, String, String>() {
                @Override
                protected void onPreExecute() {
                    super.onPreExecute();
                }
                @Override
                protected String doInBackground(String... params) {
                    return null;
                }
                @Override
                protected void onProgressUpdate(String... values) {
                    super.onProgressUpdate(values);
                }
                @Override
                protected void onPostExecute(String s) {
                    super.onPostExecute(s);
                }
            };
          • 与Thread+Handler+Message实现多线程比较
            • AsyncTask本质上就是Thread+Handler+Message的封装
            • 在Activity被重新创建(设备状态改变,例如屏幕方向变化引起的Activity重启)时,任务会被取消
            • 在线程池中只能容纳5个后台运行程序,再多会造成阻塞,这里表示的是通过AsyncTask创建的线程,用Thread创建的不算
            • 执行方式不同,AsyncTask通过excute来执行,Thread通过start来执行
      • ExecutorService线程池
        • 线程池适合处理大量线程的操作,例如多线程加载1000张图片,多线程批量下载
        • 实例化线程池
          • 单线程
          • ExecutorService service=Executors.newSingleThreadExecutor();
          • 固定数量线程
          • ExecutorService service=Executors.newFixedThreadPool(10);
          • 动态线程
          • ExecutorService service=Executors.newCachedThreadPool();
        • 执行线程操作:
          • submit(Runnable):创建并执行一个工作线程
  • 相关阅读:
    多功能回到顶部组件,速度可调控,带隐藏效果,返回过程中可回滚。
    可扩展进度条,商城常用!
    多功能万能模态框插件,项目实用,持续更新中...
    前端页面重构技巧总结TIP【持续更新...】
    微信小程序入门实例之记事本
    webpack1.x环境配置与打包基础【附带各种 "坑" 与解决方案!持续更新中...】
    CSS3利用背景渐变和background-size配合完成渐变与条纹效果[持续更新中...]
    CSS3利用一个div实现内圆角边框效果
    CSS3实现原腾讯视频透明边框,多重边框等(关于边框那些不为人知的事情)
    使用条件注释完成浏览器兼容
  • 原文地址:https://www.cnblogs.com/xl-xlg/p/5036035.html
Copyright © 2020-2023  润新知