子线程中使用Handler

1 篇文章 0 订阅
1 篇文章 0 订阅
在子线程中使用Handler
  • 在子线程中使用handler就意味着handler的实例是在子线程中去创建的。
Looper.prepare();
mHandler = new Handler(){
    @Override
  public void handleMessage(Message msg) {
            Log.d(TAG," mHandler is coming");
  handler_main.sendEmptyMessage(1);
  }
};
mHandler.sendEmptyMessage(1);
Looper.loop();
  • 如果在调用之前必须调用Looper.prepare()方法,这个是在当前线程中创建一个looper出来,如果是普通的应用场景可以直接使用HandlerThread,其中是带有Looper的。
  • 第二点值得注意的就是,Looper.loop()这个方法是无限循环的,所以在Looper.loop()后边的程序代码块是无法执行到的。loop()方法的主要作用是一直不断的通过queue.next()方法来读取来自messagequeue中的msg,这个方法是block的状态,如果queue中没有消息的话会一直阻塞在这里。
  • 关于Looper还有一个方法,当我们需要获取Looper实例时,可以直接在对应线程调用Looper looper = Looper.myLooper();来获取,默认情况下,系统只会给MainT
    hread分配一个looper。
在子线程中更新UI
  • 这个听上去好像有点问题,其实不然,这句话是可以实现的。方法就是在子线程中获取UI线程的looper,然后再创建handler实例,在handlerMessage()方法中去更新UI。
handler_main = new Handler(getMainLooper()){
    @Override
  public void handleMessage(Message msg) {
  helloTextView.setText("getMainLooper");
  }
};

今天写这篇文章主要是前几天被一个问题疑惑住了,如何在没有上下文的情况下使用子线程去更新UI,其实就是getMainLooper()获取UI线程的looper就可以了。关于Handler还有很多可以写的,下次有空再补上。

这个报错通常是因为在线程尝试关闭`tkinter`的窗口或者更新`tkinter`的控件,而`tkinter`的操作必须在主线程执行。 解决方法是,在线程不直接操作`tkinter`控件,而是通过`Queue`将操作请求发送到主线程,由主线程执行相应的操作。具体实现可以参考以下代码: ```python import tkinter as tk import threading import queue class App: def __init__(self): self.root = tk.Tk() self.label = tk.Label(self.root, text='Hello World') self.label.pack() self.queue = queue.Queue() def run(self): threading.Thread(target=self.worker).start() self.root.mainloop() def worker(self): while True: try: cmd, args = self.queue.get(timeout=0.1) if cmd == 'update_label': self.update_label(*args) elif cmd == 'close_window': self.close_window() return except queue.Empty: pass def update_label(self, text): self.label.config(text=text) def close_window(self): self.root.destroy() def on_button_click(self): self.queue.put(('update_label', ('New Text',))) def on_close(self): self.queue.put(('close_window', ())) if __name__ == '__main__': app = App() button = tk.Button(app.root, text='Update Label', command=app.on_button_click) button.pack() app.root.protocol('WM_DELETE_WINDOW', app.on_close) app.run() ``` 在上面的代码,`App`类增加了一个`queue`属性,用于存放需要在主线程执行的操作请求。`update_label`和`close_window`方法分别表示更新`Label`控件和关闭窗口的操作,将对应的操作请求通过`queue`发送到主线程执行。`worker`方法在线程运行,循环从`queue`获取操作请求,根据请求类型执行相应的操作。`on_button_click`和`on_close`方法表示按钮点击和窗口关闭事件的回调函数,在这些方法将需要执行的操作请求放入`queue`。最后,在`run`方法启动线程,并在主线程运行`mainloop`循环,等待操作请求的执行。 这样,就可以在线程调用`update_label`和`close_window`方法,而不会出现`async handler deleted by the wrong thread`的错误。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值