Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/200.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android基础:在UI线程中运行代码_Android_Android Asynctask_Android View_Android Ui - Fatal编程技术网

Android基础:在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线

从在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 op
doInBackground()
,然后最终执行一个
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
    }
});