Android基础:在UI线程中运行代码
从在UI线程中运行代码的角度来看,以下两者之间是否有任何区别:Android基础:在UI线程中运行代码,android,android-asynctask,android-view,android-ui,Android,Android Asynctask,Android View,Android Ui,从在UI线程中运行代码的角度来看,以下两者之间是否有任何区别: MainActivity.this.runOnUiThread(new Runnable() { public void run() { Log.d("UI thread", "I am the UI thread"); } }); 或 及 私有类BackgroundTask扩展了AsyncTask{ 受保护的void onPostExecute(位图结果){ Log.d(“UI线程”,“我是UI线
MainActivity.this.runOnUiThread(new Runnable() {
public void run() {
Log.d("UI thread", "I am the UI thread");
}
});
或
及
私有类BackgroundTask扩展了AsyncTask{
受保护的void onPostExecute(位图结果){
Log.d(“UI线程”,“我是UI线程”);
}
}
尽管它们都具有相同的净效应,但没有一个是完全相同的
第一个线程与第二个线程的区别在于,如果在执行代码时恰好位于主应用程序线程上,第一个线程(runOnUiThread()
)将立即执行Runnable
。第二个(post()
)始终将Runnable
放在事件队列的末尾,即使您已经在主应用程序线程上
第三个,假设您创建并执行一个
BackgroundTask
实例,将浪费大量时间从线程池中抓取一个线程,以执行默认的no opdoInBackground()
,然后最终执行一个post()
。这是三者中效率最低的。如果您在后台线程中确实有工作要做,请使用AsyncTask
,而不仅仅是使用onPostExecute()
还有第四种方法使用
我喜欢来自的,它可以在任何地方使用,无需任何参数:
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
Log.d("UI thread", "I am the UI thread");
}
});
Pomber的回答是可以接受的,但是我不太喜欢反复创建新对象。最好的解决方案总是那些试图减轻内存占用的方案。是的,有自动垃圾收集功能,但移动设备中的内存保护属于最佳实践的范围。 下面的代码更新服务中的TextView
TextViewUpdater textViewUpdater = new TextViewUpdater();
Handler textViewUpdaterHandler = new Handler(Looper.getMainLooper());
private class TextViewUpdater implements Runnable{
private String txt;
@Override
public void run() {
searchResultTextView.setText(txt);
}
public void setText(String txt){
this.txt = txt;
}
}
它可以在任何地方使用,如下所示:
textViewUpdater.setText("Hello");
textViewUpdaterHandler.post(textViewUpdater);
从Android p开始,您可以使用
getMainExecutor()
:
从:
返回将在与此上下文关联的主线程上运行排队任务的执行器。这是用于向应用程序组件(活动、服务等)分派调用的线程
从:
您可以在上下文中调用getMainExecutor(),以获取将在主应用程序线程上执行其作业的执行器。还有其他方法可以实现这一点,使用Looper和自定义执行器实现,但这更简单
如果需要在片段中使用,则应使用
private Context context;
@Override
public void onAttach(Context context) {
super.onAttach(context);
this.context = context;
}
((MainActivity)context).runOnUiThread(new Runnable() {
public void run() {
Log.d("UI thread", "I am the UI thread");
}
});
而不是
getActivity().runOnUiThread(new Runnable() {
public void run() {
Log.d("UI thread", "I am the UI thread");
}
});
因为在某些情况下会出现空指针异常,例如寻呼机片段使用处理程序
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
// Code here will run in UI thread
}
});
还要注意,
AsyncTask.execute()
要求您无论如何都要从UI线程调用,这使得此选项对于从后台线程在UI线程上运行代码的用例毫无用处,除非您将所有后台工作移到doInBackground()中
并正确使用AsyncTask
。@kabuko我如何检查我是否从UI线程调用AsyncTask
?@NeilGaliaskarov这看起来是一个可靠的选项:@NeilGaliaskarov布尔isUiThread=(Looper.getMainLooper().getThread()=thread.currentThread())
@NeilGaliaskarov对于大于或等于M的版本,请使用Looper.getMainLooper().isCurrentThread
来澄清我的问题:我认为这些代码是从服务线程调用的,通常是侦听器。我还认为,在AsynkTask的doInBackground()函数中,或者在前两个代码片段之前调用的新任务(…)中,都需要完成繁重的工作。无论如何,AsyncTask的onPostExecute()将被放在事件队列的末尾,对吗?您应该注意这一点。因为如果在非UI线程中创建处理程序,您将向非UI线程发布消息。默认情况下,处理程序将消息发布到创建它的线程。要在主UI线程上执行,请执行新处理程序(Looper.getMainLooper()).post(r)
,这是首选的方式,因为Looper.getMainLooper()
对main进行静态调用,而postOnUiThread()
必须在作用域中有一个MainActivity
的实例。@HPP我不知道这个方法,当您既没有活动也没有视图时,这将是一个很好的方法。很好!非常感谢你@lujop与AsyncTask的onPreExecute回调方法的情况相同。+1用于提及GC和对象创建。然而,我并不一定同意最好的解决方案总是那些试图减轻内存占用的解决方案。最佳
还有许多其他标准,这有点过早优化的味道。也就是说,除非你知道你对它的调用足够多,以至于创建的对象数量是一个问题(与你的应用程序创建垃圾的一万种其他方式相比),否则最好的方法是编写最简单(最容易理解)的代码,然后继续执行其他任务。顺便说一句,textViewUpdaterHandler
最好命名为uiHandler
或mainHandler
,因为它通常对任何发布到主UI线程都很有用;它与TextViewUpdater类没有任何关联。我将把它从代码的其余部分移开,并明确表示它可以在其他地方使用。。。代码的其余部分是可疑的,因为为了避免动态创建一个对象,可以将单个调用分为两个步骤setText
和post
,这两个步骤依赖于用作临时对象的长期对象。不必要的复杂性,而且不是线程安全的。不容易维护。如果您确实遇到了这样一种情况,即它被多次调用,因此值得缓存uiHandler
和textViewUpdater
,那么可以通过更改为public void setText(String txt,Handler uiHandler)
并添加方法行uiHandler.post(this)来改进您的类代码>然后调用方可以一步完成:textViewUpdater.setText(“Hello”,uiHandler)代码>。然后在将来,若需要线程安全,该方法可以
getMainExecutor().execute(new Runnable() {
@Override public void run() {
// Code will run on the main thread
}
});
private Context context;
@Override
public void onAttach(Context context) {
super.onAttach(context);
this.context = context;
}
((MainActivity)context).runOnUiThread(new Runnable() {
public void run() {
Log.d("UI thread", "I am the UI thread");
}
});
getActivity().runOnUiThread(new Runnable() {
public void run() {
Log.d("UI thread", "I am the UI thread");
}
});
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
// Code here will run in UI thread
}
});