Java 是否有工作线程可以在android中更新UI?
我假设我们不能在任何工作线程中更新任何UI视图元素TextView、EditText等,但在下面的示例中,我能够从工作线程更新视图,不是所有时间,而是有时 请参见下面的示例,其中我正在更新工作线程中的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
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我想这回答了你的问题!!