返回顶部
首页 > 资讯 > 移动开发 >了解Android核心:Looper,Handler和HandlerThread
  • 453
分享到

了解Android核心:Looper,Handler和HandlerThread

handlerthreadlooperhandlerAndroid 2022-06-06 13:06:32 453人浏览 薄情痞子
摘要

  Android中的主线程由 looper 和 Handlers 组成。所以了解创建无阻碍的响应式 UI 很重要。 MessageQueue 是一个队列,其中包含消息任务

 

Android中的主线程由 looper 和 Handlers 组成。所以了解创建无阻碍的响应式 UI 很重要。

MessageQueue 是一个队列,其中包含消息任务。 Handler 在 MessageQueue 中以任务形式排队,Looper 在任务出现时执行它们 MessageQueue. Looper 使线程保持活动状态,循环 MessageQueue 并向相应 Handler 的进程发送消息。 Thread 通过调用 Looper 的 quit() 方法终止。 Handler 及其组件 Handler:框架的重要对象,它具有双重责任。它绑定到给定线程的特定 Looper,并提供了将消息发送到相关 MessageQueue 的方法。该处理器还负责在实际执行消息的内容。 Message:封装有关在特定线程上执行的操作信息。 Runnable:抽象一个线程可以执行的任何操作的接口。 MessageQueue:表示线程消耗的消息队列。 Looper:负责循环的对象,循环检查 MessageQueue 以查看是否有消息要运行并将其发送到特定的 Handler。每个线程只能有一个 Looper。

现在,开始编写代码了。

例子1: 使用 Thread:

创建主线程处理程序

Handler handler = new Handler(Looper.getMainLooper());
 thread = new Thread(new Runnable() {
            @Override
            public void run() {
                handler2 = new Handler(Looper.getMainLooper());
                handler2.post(new Runnable() {
                    @Override
                    public void run() {
                        Toast.makeText(MainActivity.this,"hello world",Toast.LENGTH_SHORT).show();
                    }
                });
            }
       });
使用 HandlerThread:
handlerThread = new HandlerThread("name");
handlerThread.start();
handler = new Handler(handlerThread.getLooper());
handler.post(new Runnable() {
      @Override
      public void run() {
          Toast.makeText(MainActivity.this,"世界你好",Toast.LENGTH_SHORT).show();
      }
});

注意:使用完 HandlerThread 后,要调用 quit() 方法退出。

例子2: 进度条


MainActivity.java
public class MainActivity extends AppCompatActivity {
    Handler handler;
    Thread thread;
    Button botton;
    int MAX = 100;
    TextView textView;
    HandlerThread handlerThread;
    ProgressBar progressBar;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
        initThread();
    }
    private void initView(){
        botton = (Button)findViewById(R.id.start_progress);
        progressBar = (ProgressBar)findViewById(R.id.progressBar);
        textView = (TextView)findViewById(R.id.textView);
        progressBar.setMax(MAX);
    }
    private void initThread(){
        handler = new Handler(){
            @Override
            public void handleMessage(Message message){
                super.handleMessage(message);
                textView.setText(message.what+"");
            }
        };
        thread = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i=0;i<100;i++){
                    progressBar.setProgress(i);
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    Message msg = new Message();
                    msg.what = i;
                    msg.obj = "obj";
                    handler.sendMessage(msg);
                }
            }
        });
    }
    public void onClick(View view){
        switch (view.getId()){
            case R.id.start_progress:
                thread.start();
                break;
             default:
                 break;
        }
    }
    public void onDestroy(){
        super.onDestroy();
        handlerThread.quit();
    }
}

activity_main.xml

    
例子3: 看到这一点,您可能不太了解,也许会感觉到我在哪里。
接下来,我们使用一个简单的示例来验证和解决我们内心的疑虑。

在这里,我们放置一个按钮,单击后更改TextView的值。

还设置延迟以模拟要处理的大量数据。

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
    public void buttonClick(View view)
    {
        try {
            Thread.sleep(6000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        TextView myTextView = (TextView)findViewById(R.id.myTextView);
        myTextView.setText("Button Pressed");
    }
}

    

运行后发现,延迟了6秒后才更新视图,这在实际开发中,会严重影响用户体验,造成一种严重卡顿的现象。

要解决这个问题,我们可以使用多线程的方法,修改后如下。

    public void buttonClick(View view)
    {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(6000);
                    Log.d("thread:","hello world");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        thread.start();
    }
在主线程以外的线程中更新用户界面元素违反了Android开发的关键规则。因此,为了更新用户界面,有必要实现线程的处理程序(Handler)。
    Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg){
            super.handleMessage(msg);
            TextView myTextView = (TextView)findViewById(R.id.myTextView);
            myTextView.setText("Button click");
        };
    };

再次修改 buttonClick() 中的内容

    public void buttonClick(View view)
    {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(6000);
                    Log.d("thread:","hello world");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                handler.sendEmptyMessage(0);
            }
        });
        thread.start();
    }

拓展内容:handler 几种方法

方法 描述
sendMessage 将消息推送到消息队列的末尾。
sendMessageDelayed 将消息推送到消息队列的末尾。
sendMessageAtTime 将消息推送到消息队列的末尾。
sendEmptyMessage 发送仅包含单个int代码的消息。
sendEmptyMessageDelayed 在指定的时间过后发送要传递的消息。
sendEmptyMessageAtTime 发送消息以在指定的绝对时间传递。
使用 messaga 对象保存数据
    public void buttonClick(View view)
    {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(6000);
                    Log.d("thread:","hello world");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                Message msg = handler.obtainMessage();
                Bundle bundle = new Bundle();
                bundle.putString("name","anny");
                msg.setData(bundle);
                handler.sendMessage(msg);
            }
        });
        thread.start();
    }

obtainmessage() 是从消息池中拿来一个msg 不需要另开辟空间new

取出数据并赋值给 TextView 

    Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg){
            super.handleMessage(msg);
            Bundle bundle = msg.getData();
            String name = bundle.getString("name");
            TextView myTextView = (TextView)findViewById(R.id.myTextView);
            myTextView.setText(name);
        };
    };
  例子4:

为线程创建Looper和MessageQueue:

public class Test extends Thread{
    public Handler handler;
    public void run(){
        Looper.prepare();
        handler = new Handler(){
            @Override
            public void handleMessage(Message message){
                super.handleMessage(message);
                Log.d("obj:","hello world");
            }
        };
        Looper.loop();
    }
}
仔细看你会发现,我们在这里使用了 Looper.prepare()和 Looper.loop()

为什么前面的示例不起作用?为什么在这里使用它?

1:在默认线程下,主线程系统将自动创建Looper对象并启动消息循环。 2:在主线程中mainHandler = new Handler()等同于new Handler(Looper.myLooper()) 将消息发送到 MessageQueue

第一种方式:Message

Message msg = new Message();
msg.obj = "Ali send message";
handler.sendMessage(msg);

第二种方式:Runnable

new Handler(Looper.getMainLooper()).post(new Runnable() {
    @Override
    public void run() {
        // this will run in the main thread
    }
});

拓展:

方法 描述
post 立即让Runnable排队执行。
postAtTime 使Runnable排队以在以毫秒为单位的绝对时间执行。
postDelayed 使Runnable排队以指定的毫秒延迟后执行。
postAtFrontOfQueue 立即将Runnable排队到要执行的前端
 Android 提供了 HandlerThread (线程的子类) 来简化过程。在内部,它以健壮的方式执行与我们相同的操作,因此,请始终使用 HandlerThread。
public class Test extends HandlerThread {
    public Handler handler;
    public Test(String name) {
        super(name);
    }
    @Override
    protected void onLooperPrepared(){
        handler = new Handler(getLooper()){
            @Override
            public void handleMessage(Message message){
                super.handleMessage(message);
                //接收消息
            }
        };
    }
}

 

我们在调用 onLooperPrepared 时实例化了 Handler。因此,Handler 可以将其与 Looper 关联。

1:仅在 start() 调用 HandlerThread 之后,即线程运行之后,才准备 Looper。

2:只有在准备好之后,Handler 才能与 HandlerThread Looper 关联。

另一种方式创建 HandlerThread 的方式(之前提过):

HandlerThread handlerThread = new HandlerThread("myHandlerThread");
handlerThread.start();
Looper looper = handlerThread.getLooper();
Handler handler = new Handler(looper);
重要说明:请记住,在完成后台线程或活动onDestroy()方法之后调用handlerThread.quit()。
作者:你敢凝视深渊嘛


--结束END--

本文标题: 了解Android核心:Looper,Handler和HandlerThread

本文链接: https://lsjlt.com/news/29597.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作