黑马程序员技术交流社区

标题: 安卓 handler机制的loop()为什么不会ANR? [打印本页]

作者: Kas_ygx    时间: 2016-11-24 00:28
标题: 安卓 handler机制的loop()为什么不会ANR?
学习了一个月左右的安卓基础知识, 现在安卓安全卫士刚结束, 新手在学习基础的时候有讲过handler机制, 一个handler,looper, messagequeue
视频里解释的说是handler.sendMessage(msg) --> 发送到MessageQueue , Looper里面有个方法loop(), 它其实是一个无线循环, 不断的从MessageQueue中轮询, 如果有消息则取出, 分发给dispatchMessage(msg);  后者有调用了handlerMessage方法来执行,
一直想不通的是,
1.既然loop()是死循环,为什么不会造成系统ANR?
     网上的资料实在是看不懂, 据说loop和ui线程是同一个线程,有消息的时候取出,没有消息的时候 阻塞,  这个阻塞又是指什么意思呢?
    是指线程停在那里不动等着有消息来了继续循环码, 那么既然是同一个线程,而且线程又是停在那里的,当我们的activity中触发事件的时候, 应用程序岂不是得不到执行, 不是就要挂掉吗
2.loop()是什么时候开启的, 是在初始化handler对象的时候吗,?
3.能不能用学过的知识自己也模拟一段handler机制这样的代码看看?

作者: Kas_ygx    时间: 2016-11-24 00:29
望各位老师和学霸们不吝赐教
作者: Kas_ygx    时间: 2016-11-24 00:31
{:8_529:}20个黑马币是不是有点低
作者: Kas_ygx    时间: 2016-11-25 00:27
{:8_544:}一个晚上了发现没人鸟
作者: javantiger93000    时间: 2016-11-28 14:02
本帖最后由 javantiger93000 于 2016-11-28 14:06 编辑

//这是我做的主活动代码,由于Android中不允许在子线程中进行UI操作,所以是基于Android的异步消息处理机制,实现了UI在子线程中的更新操作
//MainActivity.java文件
package com.example.androidthreadtest;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends Activity implements OnClickListener{

        public static final int UPDATE_TEXT = 1;
        private TextView text;
        private Button changeText;
        
        private Handler handler = new Handler(){
                public void handleMessage(Message msg){
                        switch(msg.what){
                        case UPDATE_TEXT:
                                text.setText("Nice to meet you");
                                break;
                        default:
                                break;
                        }
                }
        };
        
        @Override
        protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.activity_main);
                text=(TextView)findViewById(R.id.text);
                changeText=(Button)findViewById(R.id.change_text);
                changeText.setOnClickListener(this);
        }

        @Override
        public boolean onCreateOptionsMenu(Menu menu) {
                // Inflate the menu; this adds items to the action bar if it is present.
                getMenuInflater().inflate(R.menu.main, menu);
                return true;
        }
        
        @Override
        public void onClick(View v){
                switch(v.getId()){
                case R.id.change_text:
                        new Thread(new Runnable(){
                                @Override
                                public void run(){
                                        Message message = new Message();
                                        message.what = UPDATE_TEXT;
                                        handler.sendMessage(message);
                                }
                        }).start();
                        break;
                default:
                                break;
                }
        }

}

//activity_main.xml文件
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >

   <Button
       android:id="@+id/change_text"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:text="Change Text"
       />

    <TextView
        android:id="@+id/text"
        android:layout_centerInParent="true"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/hello_world"
        android:textSize="20sp" />

</RelativeLayout>



作者: javantiger93000    时间: 2016-11-28 14:22
本帖最后由 javantiger93000 于 2016-11-28 14:51 编辑

一个例子未必就能讲明白Android的异步处理机制,所以了我在提一下Android中异步消息处理的四个组成部分,Message、Handle、MessageQueue和
Looper。
1,Looper是每个线程中的MessageQueue的管家,调用Looper的loop()方法后,就会进入到一个无线循环中,然后每当发现MessageQueue中存在一条
消息,就会将它取出,并传递到Handler的handleMessage()方法中。每个线程中也只会有一个Looper对象。
  至于楼主所说的安卓handler机制的loop()方法为什么不会导致ANR?那就很好解释了,因为android的消息异步处理机制中采用了java中的多线程技术,多个线程独立运行,所以不会出现ANR现象。
2、Message是在线程之间传递的消息,它可以在内部携带少量的信息,用于在不同线程之间交换数据。
所以说你说的loop()和ui同属一个线程,这个是没错的,至于和这个线程之间交换数据的线程嘛,肯定就是主线程了。它是在和主线程之间交换数据,你也许没有考虑到主线程吧,哥们?
3、Handler一看名就知道这个是处理者的意思吧,它主要用于发送和处理消息的,它发送消息使用的方法就是sendMessage()方法,很关键的一
点是:这个SendMessage()方法在子线程中。   你对照我给的代码看,就明白了,而发出的消息经过一系列的辗转处理后,最终会传递到Handler的handleMessage()方法中。HandleMessage()方法在主线程中!!!
4、说到这差不多你也能明白了,多的也就不说了,兄弟,这条路上,我们一起努力吧!

作者: 谭世霖    时间: 2016-12-3 12:47
本帖最后由 谭世霖 于 2016-12-3 12:57 编辑

anr是主线程长时间未响应 (android not response),未响应在虚拟机上指的是任务"未执行",handler 中死循环读取messag并非“未执行”,只是执行的延迟而已,轮询器机制:内部有两个类似javaCondition对象的c/cpp代码变量 记录是否阻塞,当消息队列messageQueue中已经存了的数量等于总容量时,改变Condition为阻塞,调用await方法,所以说当占用满了的时候 调用发送消息也是并没有 效果,而且短时间内频繁更新ui也是看不到效果的;反之,则通知其他地方进行处理message,  这里类似于多线程的消费者和生产者的关系
作者: 阿萨德第三方    时间: 2017-3-3 17:32
看不懂,但好想要金币··
作者: 败事不足    时间: 2017-4-21 17:09
http://www.jianshu.com/p/cfe50b8b0a41
看看这个连接,这里或许有你想要的答案




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2