Skip to content

android在线程中创建handler应注意什么 #44

@xuchao49

Description

@xuchao49
No description provided.

Activity

shcalm

shcalm commented on Mar 12, 2015

@shcalm

无参数构造, 会默认使用当前thread的looper; 有参数构造,使用参数的looper....

soyoungboy

soyoungboy commented on Mar 13, 2015

@soyoungboy

Looper.prepare(),主线程使用handler,系统默认prepare了,子线程中创建handler必须在前面Looper.prepare(),后面加上Looper.loop();

源码中:
主线程:
在程序启动的时候,系统已经帮我们自动调用了Looper.prepare()方法。查看ActivityThread中的main()

public static void main(String[] args) {  
SamplingProfilerIntegration.start();  
CloseGuard.setEnabled(false);  
Environment.initForCurrentUser();  
EventLogger.setReporter(new EventLoggingReporter());  
Process.setArgV0("<pre-initialized>");  
Looper.prepareMainLooper();  
ActivityThread thread = new ActivityThread();  
thread.attach(false);  
if (sMainThreadHandler == null) {  
    sMainThreadHandler = thread.getHandler();  
}  
AsyncTask.init();  
if (false) {  
    Looper.myLooper().setMessageLogging(new LogPrinter(Log.DEBUG, "ActivityThread"));  
}  
Looper.loop();  
throw new RuntimeException("Main thread loop unexpectedly exited");  
}  

请注意Looper.prepareMainLooper():

public static final void prepareMainLooper() {  
prepare();  
setMainLooper(myLooper());  
if (Process.supportsProcesses()) {  
    myLooper().mQueue.mQuitAllowed = false;  
}  
}  

子线程:

new Thread(new Runnable() {  
        @Override  
        public void run() {  
            Looper.prepare()
            handler2 = new Handler(); 
            Looper.loop() 
        }  
    }).start();

如果没有Looper.prepare().会报错:

Can't create handler inside thread that has not called Looper.prepare()
因为没looper对象创建

looper.prepare()源码:

public static final void prepare() {  
if (sThreadLocal.get() != null) {  
    throw new RuntimeException("Only one Looper may be created per thread");  
}  
sThreadLocal.set(new Looper());  
}  
supercwn

supercwn commented on Mar 18, 2015

@supercwn

在Android开发中经常会使用到线程,一想到线程,一般都会想到

new Thread(){...}.start();

这样的方式。这样如果在一个Activity中多次调用上面的代码,那么将创建多个匿名线程,如果这些线程的没有被销毁,那肯定会影响性能呢。这个时候我么就想到了android提供的一个异步处理线程的类HandlerThread。

一般Handler的用法
Handler handler = new Handler(){...};
这样创建的handler是在主线程即UI线程下的Handler,即这个Handler是与UI线程下的默认Looper绑定的(当然也只有主线程才能这么干,子线程是干不了的,除非自己创建个looper)。因此,有些时候会占用ui主线程,引起一些问题,所以我们就想到了重新创建个子线程,来处理handler。。。。
使用HandlerThread解决问题

HandlerThread实际上继承于Thread,只不过它比普通的Thread多了一个Looper。我们可以使用下面的例子创建Handler

HandlerThread thread = new HandlerThread("MyHandlerThread");
thread.start();
创建HandlerThread时要把它启动了,即调用start()方法。

接着就是handler的使用,如下:

mHandler = new Handler(thread.getLooper());
//TODO:you can post or send something....
创建Handler时将HandlerThread中的looper对象传入。那么这个mHandler对象就是与HandlerThread这个线程绑定了(这时就不再是与UI线程绑定了,这样它处理耗时操作将不会阻塞UI)。

alvminvm

alvminvm commented on Mar 20, 2015

@alvminvm

@supercwn

mHandler = new Handler(thread.getLooper());
//TODO:you can post or send something....
创建Handler时将HandlerThread中的looper对象传入。那么这个mHandler对象就是与HandlerThread这个线程绑定了(这时就不再是与UI线程绑定了,这样它处理耗时操作将不会阻塞UI)

耗时操作放thread不就行了吗,为什么要弄到handler里去做?

ghost

ghost commented on Aug 10, 2015

@ghost

@JeremyHe-cn

耗时操作放thread不就行了吗,为什么要弄到handler里去做?

handler是等待处理结果的,处理结果也可能耗时吧。

xiexinhong

xiexinhong commented on Jul 20, 2016

@xiexinhong

@JeremyHe-cn
我觉得这就是 线程之间的一种通信机制,A线程拥有一个handler 这个handler绑定的是B线程,A线程就可以通过handler 发送消息给B线程的消息队列,handler里面当然就可以处理耗时实际上就是B线程在处理耗时。

jp1017

jp1017 commented on Jul 24, 2016

@jp1017

郭大神的这个写的不错哦 😃

http://blog.csdn.net/guolin_blog/article/details/9991569

okadaNana

okadaNana commented on Dec 28, 2016

@okadaNana

我在子线程中创建了 Handler,也调用 Looper.prepare() 和 Looper.loop() 然后发送一条 Message,但是 Handler 的 handlerMessage 没有执行到,这是为什么啊?

public class MainActivity extends AppCompatActivity {

    private TextView mTextView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mTextView = (TextView) findViewById(R.id.tv);
        findViewById(R.id.btn).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                createHandlerInThread();
            }
        });
    }

    private void createHandlerInThread() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                Looper.prepare();
                Handler handler = new Handler(Looper.myLooper()) {
                    @Override
                    public void handleMessage(Message msg) {
                        mTextView.setText("改变文字");
                    }
                };
                Looper.loop();
                handler.sendEmptyMessage(123);

                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
}
70kg

70kg commented on Dec 29, 2016

@70kg

Looper.loop(); 向下一行。
Looper.myLooper() 改为 Looper.getMainLooper()
这个 sleep 没意义 @okadaNana
handler 这套东西是为 android 事件驱动设计的,只是顺带切换了线程。
重点都在 Looper.loop(); 这里

看这个https://www.zhihu.com/question/51099935 handler 不仅仅是切换线程
看这个https://www.zhihu.com/question/34652589 彻底解决你上面的问题

JiangLi23

JiangLi23 commented on Sep 1, 2017

@JiangLi23

@okadaNana "我在子线程中创建了 Handler,也调用 Looper.prepare() 和 Looper.loop() 然后发送一条 Message,但是 Handler 的 handlerMessage 没有执行到",我也遇到这个问题,你有解决吗?

wsxyeah

wsxyeah commented on Sep 3, 2017

@wsxyeah

@JiangLi23 调用 Looper.loop() 时,线程就会在这里执行消息循环,如果不手动退出的话,后面的代码是不会被执行到的。所以 sendEmptyMessage 根本没有执行,当然也就不会执行 handleMessage 了。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @shcalm@wsxyeah@xuchao49@alvminvm@70kg

        Issue actions

          android在线程中创建handler应注意什么 · Issue #44 · android-cn/android-discuss