Android Handler

作者: ghwaphon | 来源:发表于2016-09-11 19:25 被阅读125次

    Hanlder简介

    相比于 AsyncTaskHandler类允许准确的控制操作的运行时间,而且还可以多次使用,执行的操作会一直运行,直到被显示的停止。每个Handler实例都被包含在一个单独的线程里面。

    Handler有两个主要的用途 :

    1. 确保一些调度信息和任务在未来的某一时刻被执行
    2. 让一些行为在其他的线程中表现出来

    HandlerThread 介绍

    HandlerThread类用于创建一个带有 Looper 的新线程,这个Looper可以用于创建Handler实例,HandlerThread 的实例必须在调用start()方法后才可以使用。

    构造方法 :

    1. HandlerThread(String name)
    2. HandlerThread (String name, int priority) //priority 就是线程运行的优先级,由 Process类中的变量 来指定

    方法 :

    1. getLooper ()

    这个方法用于获取与该线程相关联的 Looper,如果该线程没有开启,也即未调用 start()方法,那么这个方法会返回一个 null值。如果线程已经开启,这个方法会被阻塞直到 Looper初始化完成。

    1. getThreadId ()

    用于返回线程的标识符

    1. quit ()

    停止线程中的Looper,该方法被调用后,任何对Looper 的请求都会失败。比如,sendMessage(Message)方法会返回false。使用这个方法可能是不安全的,因为在Looper被终止的时候可能还有 Message未被递交。

    1. quitSafely ()

    和上一个方法完成的功能相同,不过这个方法更安全,因为在Looper被终止时,一些未递交的Message会因为时间的关系不再递交。

    1. run ()

    调用Runnable对象中的run()方法,如果未设置Runnable,就什么也不做。

    1. onLooperPrepared ()

    该方法是protected类型的,当我们需要在Looperloop() 方法调用前需要完成一些工作,那么可以复写这个方法。

    Looper 的简单介绍

    Looper类用来为线程运行 消息循环,默认的Threads并不包含一个 message loop,为了创建一个,可以在线程中调用 prepare(),然后调用 loop()去处理messages

    官方给出的示例

     class LooperThread extends Thread {
      public Handler mHandler;
    
      public void run() {
          Looper.prepare();
    
          mHandler = new Handler() {
              public void handleMessage(Message msg) {
                  // process incoming messages here
              }
          };
    
          Looper.loop();
      }
    

    }

    介绍一下Looper 类中的一些方法

    1. Looper getMainLooper ()

    获得应用程序的主Looper,存在于主线程中

    1. Thread getThread ()

    返回与该Looper 关联的 Thread

    1. void loop ()

    在线程中运行message queue,与此方法对应的是quit()方法,而且这两个方法必须同时出现。

    1. Looper myLooper ()

    返回与该线程关联的 Looper,如果该线程没有关联 Looper,就返回 null

    1. MessageQueue myQueue ()

    返回与该线程关联的 MessageQueue,如果在未关联Looper的线程中调用该方法,会抛出NullPointerException

    1. void prepare ()

    初始化该线程作为一个Looper

    1. void quit ()
    2. void quitSafely()

    功能和上面HandlerThread中介绍的一样

    异步消息处理机制

    首先,在主线程中创建一个 Handler,并重写 handleMessage()方法,然后当子线程需要进行 UI 操作时,就创建一个Message 对象,并通过 Handler 将消息发送出去。之后这条消息会被添加到 MessageQueue的队列中进行等待,而 Looper 会一直尝试从 MessageQueue 中取出待处理消息,最后分发回 HandlerhandleMessage() 方法中。由于 Handler是在主线程中创建的,此时的 handleMessage()也会在主线程中得到执行。

    一个Message经过一个流程的辗转,从子线程进入到主线程,从不能更新 UI到可以更新UI,这就是异步消息处理机制的核心思想。

    Hanlder 的简单使用

    由于 Handler 中的方法太多,就不逐一介绍了,下面来介绍 几种给 Handler发送信息的方法。

    1. Message.obtain(mHanlder,FLAG,data).sendToTarget()

    创建一个标识为FLAG,数据为 dataMessage,立刻将其发送到 Handler去执行

    1. mHandler.sendEmptyMessage(FLAG)

    立刻给 Handler发送一个带有标识的空消息

    1. mHanlder.sendEmptyMessageAtTime(FLAG,1000)

    Handler发送一个简单的空消息,该消息会在一秒后被递交给Looper

    1. mHandler.sendEmptyMessageDelayed(FLAG,1000)

    效果同上

    下面利用 Handler 来更改 UI

    public class MainActivity extends AppCompatActivity {
    public static final int FLAG = 0;
    private Button mButton;
    private TextView mTextView;
    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            if (msg.what == FLAG) {
                mTextView.setText("After Changer");
            }
        }
    };
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mButton = (Button) findViewById(R.id.start);
        mTextView = (TextView) findViewById(R.id.tx);
    
        mButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        mHandler.sendEmptyMessage(FLAG);
                    }
                }).start();
            }
        });
      }
    }
    

    注意,这个时候mHandler使用的是默认Looper,也即 MainLooper,我们也可以通过 HandlerThread来使用自己的Looper执行该操作。

    public class MainActivity extends AppCompatActivity implements Handler.Callback {
    
    public static final int FLAG = 0;
    private Button mButton;
    private TextView mTextView;
    
    private HandlerThread mHandlerThread;
    private Handler mHandler;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mHandlerThread = new HandlerThread("MyHandlerThread");
        mHandlerThread.start();
        mHandler = new Handler(mHandlerThread.getLooper(), this);
    
        mButton = (Button) findViewById(R.id.start);
        mTextView = (TextView) findViewById(R.id.tx);
    
        mButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        mHandler.sendEmptyMessage(FLAG);
                    }
                }).start();
            }
        });
    
    }
    
    @Override
    public boolean handleMessage(Message message) {
        if (message.what == FLAG) {
            mTextView.setText("After Change");
        }
        return true;
    }
    

    }

    这个时候会出现一个错误,因为我们自己的Looper 是没有权限去更新 UI的,如果想要更新UI ,可以在Handler的构造方法中使用 getMainLooper()方法。

    以上我们都使用使用默认的mHandlerHandlerThread,我们也可以写一个类继承自HandlerThread或者Handler,在自定义的类中可以执行一些耗时任务,因为这个时候所有的任务都是在子线程中执行的,并不会阻塞主线程。

    关于 AsyncTaskHandler的选择,如果不是很频繁的执行一个操作,而且操作可以在较短时间内完成,使用AsyncTask是十分方便的。如果需要安排操作的时间或者需要快速间隔的执行某操作,Handler 是不错的选择。

    相关文章

      网友评论

        本文标题:Android Handler

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