Java 是否有工作线程可以在android中更新UI?

Java 是否有工作线程可以在android中更新UI?,java,android,multithreading,Java,Android,Multithreading,我假设我们不能在任何工作线程中更新任何UI视图元素TextView、EditText等,但在下面的示例中,我能够从工作线程更新视图,不是所有时间,而是有时 请参见下面的示例,其中我正在更新工作线程中的UI元素- public class AndroidBasicThreadActivity extends AppCompatActivity { public static TextView textView; @Override protected void onCrea

我假设我们不能在任何工作线程中更新任何UI视图元素TextView、EditText等,但在下面的示例中,我能够从工作线程更新视图,不是所有时间,而是有时

请参见下面的示例,其中我正在更新工作线程中的UI元素-

public class AndroidBasicThreadActivity extends AppCompatActivity
{
    public static TextView textView;
    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_android_basic_thread);

        textView = (TextView) findViewById(R.id.textview);

        MyAndriodThread myTask = new MyAndriodThread();
        Thread t1 = new Thread(myTask, "Bajrang Hudda");
        t1.start();
    }
}
这是我的工作线程-

class MyAndriodThread implements Runnable
{
    @Override
    public void run()
    {
        AndroidBasicThreadActivity.textView.setText("Hello!! Android Team :-) From child thread.");
    }
}
相信我,我不会有任何例外-

android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
我可以在emulator上看到更新UI

但是,如果我在工作线程中执行任何繁重的任务,那么我会得到预期的上述异常,为什么会发生这种情况?我是android多线程的新手,请让我摆脱这种困惑

如果我将我的工作线程更改为这个,我将得到上述异常-

class MyAndriodThread implements Runnable
{
    @Override
    public void run()
    {
        try
        {
            Thread.sleep(2000);
        } catch (InterruptedException e)
        {
            e.printStackTrace();
        }
        AndroidBasicThreadActivity.textView.setText("Hello!! Android Team :-) From child thread.");
        System.out.println("Child thread completed.");
    }
}
如果我的UI或主线程正在等待join,那么我会得到准确的输出,一点也不例外,请参见此-

MyAndriodThread myTask = new MyAndriodThread();
        Thread t1 = new Thread(myTask, "Anhad");
        t1.start();
        try
        {
            t1.join();
        } catch (InterruptedException e)
        {
            e.printStackTrace();
        }
更新 首先我认为这是一个渲染方案,然后我用ProgressBar修改了我的程序。然后我得到了意想不到的输出。。。仍然没有例外意味着我可以在工作线程中更新我的进度条。见下文-

 @Override
    public void run()
    {
        for(int i = 1; i<=10; i++)
        {
            try
            {
                Thread.sleep(2000);
            } catch (InterruptedException e)
            {
                e.printStackTrace();
            }
            activity.progressBar.setProgress(i);
        }
    }

您不能从后台线程更新ui线程中的任何内容,为此,您需要使用处理程序或使用AsyncTask.onProgressUpdate,有关更多详细信息,请查看详细信息

更新

不建议在不涉及处理程序或使用Activity.runOnUiThreadRunnable的情况下从工作线程更新UI。在您的情况下,当您从MyAndriodThread更新TextView时,您的视图处于转换状态,如果您尝试更新UI,您的视图可能会得到更新或导致崩溃,具体情况如下:

如果工作线程同时更改该对象的属性 当任何其他线程引用该对象时,结果是 未定义


您不能从后台线程更新ui线程中的任何内容,为此,您需要使用处理程序或使用AsyncTask.onProgressUpdate,有关更多详细信息,请查看详细信息

更新

不建议在不涉及处理程序或使用Activity.runOnUiThreadRunnable的情况下从工作线程更新UI。在您的情况下,当您从MyAndriodThread更新TextView时,您的视图处于转换状态,如果您尝试更新UI,您的视图可能会得到更新或导致崩溃,具体情况如下:

如果工作线程同时更改该对象的属性 当任何其他线程引用该对象时,结果是 未定义


这里的原因是线程只能对TextView对象进行更改,直到它在UI屏幕上不可见(即未呈现)。只有在视图呈现之后,除主线程外的任何线程都不能对任何UI组件进行更改

所以当你这样做的时候:

class MyAndriodThread implements Runnable
{
    @Override
    public void run()
    {
        try
        {
            Thread.sleep(2000);
        } catch (InterruptedException e)
        {
            e.printStackTrace();
        }
        AndroidBasicThreadActivity.textView.setText("Hello!! Android Team :-) From child thread.");
        System.out.println("Child thread completed.");
    }
}
您试图在视图呈现后更改文本,这会导致异常

在下面的代码片段中,线程能够在TextView对象中进行更改,因为它在UI屏幕上不可见,即未呈现

class MyAndriodThread implements Runnable
{
    @Override
    public void run()
    {
        AndroidBasicThreadActivity.textView.setText("Hello!! Android Team :-) From child thread.");
    }
}
正如@JohnnyAW所指出的,当您使用join时,您会延迟渲染,直到辅助线程准备就绪,所以即使辅助线程睡眠,也不会出现异常

当你做这个帖子的时候;TextView在这段时间内呈现,然后您试图从此workerThread中触摸视图,这导致了崩溃


你也可以试试Thread.sleep0;并确保它不会引发任何异常,您的应用程序也不会崩溃。

这里的原因是线程只能在TextView对象在UI屏幕上不可见(即未呈现)之前对其进行更改。只有在视图呈现之后,除主线程外的任何线程都不能对任何UI组件进行更改

所以当你这样做的时候:

class MyAndriodThread implements Runnable
{
    @Override
    public void run()
    {
        try
        {
            Thread.sleep(2000);
        } catch (InterruptedException e)
        {
            e.printStackTrace();
        }
        AndroidBasicThreadActivity.textView.setText("Hello!! Android Team :-) From child thread.");
        System.out.println("Child thread completed.");
    }
}
您试图在视图呈现后更改文本,这会导致异常

在下面的代码片段中,线程能够在TextView对象中进行更改,因为它在UI屏幕上不可见,即未呈现

class MyAndriodThread implements Runnable
{
    @Override
    public void run()
    {
        AndroidBasicThreadActivity.textView.setText("Hello!! Android Team :-) From child thread.");
    }
}
正如@JohnnyAW所指出的,当您使用join时,您会延迟渲染,直到辅助线程准备就绪,所以即使辅助线程睡眠,也不会出现异常

当你做这个帖子的时候;TextView在这段时间内呈现,然后您试图从此workerThread中触摸视图,这导致了崩溃


你也可以试试Thread.sleep0;并确保它不会引发任何异常,您的应用程序也不会崩溃。

这种行为确实会发生。正如android开发者门户中明确提到的那样

有一段明确提到:

非主线程上的许多任务的最终目标是更新UI对象。但是,如果其中一个线程访问视图层次结构中的对象,则可能会导致应用程序不稳定:如果工作线程在任何其他线程引用该对象的同时更改该对象的属性,则结果是未定义的

因此,这种情况可能发生,也可能未定义


这种行为真的发生了 纳什。正如android开发者门户中明确提到的那样

有一段明确提到:

非主线程上的许多任务的最终目标是更新UI对象。但是,如果其中一个线程访问视图层次结构中的对象,则可能会导致应用程序不稳定:如果工作线程在任何其他线程引用该对象的同时更改该对象的属性,则结果是未定义的

因此,这种情况可能发生,也可能未定义

巴杰朗·赫达,我猜你对这个阴暗的疯狂答案基本上是满意的。我真的同意他的观点,一旦视图被渲染并附加到窗口上,您就不能直接从工作线程访问它

为了回答您关于progressBar的更新问题,progressBar在内部使用Runnable更新其进度,然后使用其处理程序postr

为了详细解释,当您尝试从工作线程ProgressBar.setProgressi更新ProgressBar时,ProgressBar首先检查调用是否在主线程上进行,如果是,则直接更新;否则,它将创建一个新的Runnable RefreshProgressRunnable来更新进度,然后使用其处理程序对其进行postr

例如newhandler.postr

我相信你在view.postr之前也用过类似的东西

检查方法设置进度

希望这能消除你的疑虑。

那么巴杰朗·赫达,我猜你对这个阴暗的疯狂答案基本上是满意的。我真的同意他的观点,一旦视图被渲染并附加到窗口上,您就不能直接从工作线程访问它

为了回答您关于progressBar的更新问题,progressBar在内部使用Runnable更新其进度,然后使用其处理程序postr

为了详细解释,当您尝试从工作线程ProgressBar.setProgressi更新ProgressBar时,ProgressBar首先检查调用是否在主线程上进行,如果是,则直接更新;否则,它将创建一个新的Runnable RefreshProgressRunnable来更新进度,然后使用其处理程序对其进行postr

例如newhandler.postr

我相信你在view.postr之前也用过类似的东西

检查方法设置进度



希望这能消除您的疑虑。

在这个链接中,我们还说我们不能在UI线程中接触任何东西,但相信我,我们可以在emulator上看到确切的输出。最好继续阅读本文。在这个链接中,我们还说我们不能在UI线程中接触任何东西,但相信我,我们可以在emulator上看到确切的输出。确切地说,这是实际方案,但不符合巴伊朗的要求。确切地说,这是实际方案,但不符合巴伊朗的要求。在onResume方法中尝试此代码,它将不起作用。@shadygoneinsane如果我的UI线程正在等待工作线程完成该怎么办??请看我的更新问题。@Bajranghuda当您使用join时,您会延迟渲染,直到工作线程准备好,所以即使工作线程sleeps@BajrangHudda这是否回答了您的问题?哪个线程负责在此处呈现TextView。。主线程还是MyAndroidThread工作线程??我认为只有我的工作线程负责渲染,而不是主线程。因为渲染线将仅由工作线程执行。在onResume方法中尝试此代码,它将不起作用。@shadygoneinsane如果我的UI线程正在等待工作线程完成该怎么办??请看我的更新问题。@Bajranghuda当您使用join时,您会延迟渲染,直到工作线程准备好,所以即使工作线程sleeps@BajrangHudda这是否回答了您的问题?哪个线程负责在此处呈现TextView。。主线程还是MyAndroidThread工作线程??我认为只有我的工作线程负责渲染,而不是主线程。因为渲染线将只由工作线程执行。这到底是如何回答这个问题的?如果你能描述一下,那就太好了,我的朋友。等待你的答案。这到底是如何回答这个问题的?如果你能描述一下,那就太好了,我的朋友。你是说progressBar.setProgressi在内部检查它是来自UI还是工作线程?这意味着我可以随时从工作线程更新我的progressbar,没有任何问题,但我不能更新除progressbar.progressbar.setProgressi之外的其他视图您可以使用它,但不建议这样做,原因是,由于两个线程引用同一个视图,结果可能不确定。我已经浏览了Progressbar的完整源代码@Bajranghuda正如siddarth所说,它实际上是以这种方式进行的。private synchronized void refresh progressint id,int progress,boolean fromUser,boolean animate{if mUiThreadId==Thread.currentThread.getId{dorefresh progressid,progress,fromUser,true,animate;}else{如果mRefreshProgressRunnable==null{mRefreshProgressRun
nable=新的RefreshProgressRunnable;}final RefreshData rd=RefreshData.ActainID,progress,fromUser,animate;mRefreshData.addrd;如果马塔奇德&!mRefreshIsPosted{postreshprogressrunnable;mRefreshIsPosted=true;}}}}@bajranghuda我想这回答了你的问题!!你是说progressBar.setProgressi在内部检查它是来自UI还是工作线程?这意味着我可以随时从工作线程更新我的progressbar,没有任何问题,但我不能更新除progressbar.progressbar.setProgressi之外的其他视图您可以使用它,但不建议这样做,原因是,由于两个线程引用同一个视图,结果可能不确定。我已经浏览了Progressbar的完整源代码@Bajranghuda正如siddarth所说,它实际上是以这种方式进行的。private synchronized void refresh progressint id,int progress,boolean fromUser,boolean animate{if mUiThreadId==Thread.currentThread.getId{dorefresh progressid,progress,fromUser,true,animate;}else{if mRefreshProgressRunnable==null{mRefreshProgressRunnable=new RefreshProgressRunnable;}最终RefreshData rd=RefreshData.ActainID,progress,fromUser,animate;mRefreshData.addrd;if mAttached&&!mRefreshIsPosted{postRefreshProgressRunnable;mRefreshIsPosted=true;}}@BajrangHudda我想这回答了你的问题!!