Baj*_*dda 1 java multithreading android
我想,我们不能更新任何UI view元素(TextView,EditText在任何工作线程等),但在下面的例子中,我能够更新views从辅助线程,不是所有的时间,但只是偶尔.
请参阅以下示例我在工作线程中更新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();
}
}
Run Code Online (Sandbox Code Playgroud)
这是我的工作线程 -
class MyAndriodThread implements Runnable
{
@Override
public void run()
{
AndroidBasicThreadActivity.textView.setText("Hello!! Android Team :-) From child thread.");
}
}
Run Code Online (Sandbox Code Playgroud)
相信我,我不会说任何例外 -
android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
Run Code Online (Sandbox Code Playgroud)
我可以在模拟器上看到更新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.");
}
}
Run Code Online (Sandbox Code Playgroud)
如果我的UI或主线程正在等待(join()),那么我得到的确切输出完全没有异常,请看 -
MyAndriodThread myTask = new MyAndriodThread();
Thread t1 = new Thread(myTask, "Anhad");
t1.start();
try
{
t1.join();
} catch (InterruptedException e)
{
e.printStackTrace();
}
Run Code Online (Sandbox Code Playgroud)
更新
首先我认为它是渲染方案然后我通过使用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);
}
}
Run Code Online (Sandbox Code Playgroud)
所以Bajrang Hudda我猜你很满意ShadyGoneInsane的回答.我真的同意他的看法,一旦视图被渲染并附加到Window,你就无法直接从工作线程访问它.
为了回答有关progressBar的更新问题,ProgressBar在内部使用Runnable更新其进度,然后post(r)使用其处理程序.
为了详细解释,当您尝试从工作线程更新ProgressBar时,progressBar.setProgress(i)progressBar首先检查是否在MainThread上进行了调用,如果是,则直接更新; 否则它会创建一个新的Runnable RefreshProgressRunnable来更新进度,然后post(r)使用它的处理程序.
例如 new Handler().post(r)
而且我相信你之前也曾经使用过类似的东西 view.post(r)
ProgressBar源代码检查方法setProgress()
希望这能清除你的怀疑.
这里的原因是线程只能在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.");
}
}
Run Code Online (Sandbox Code Playgroud)
您正试图在视图渲染后更改文本,从而导致异常
而在下面的代码片段中,线程能够在TextView对象中进行更改,因为它在UI屏幕上不可见,即未呈现.
class MyAndriodThread implements Runnable
{
@Override
public void run()
{
AndroidBasicThreadActivity.textView.setText("Hello!! Android Team :-) From child thread.");
}
}
Run Code Online (Sandbox Code Playgroud)
正如@JohnnyAW所指出的那样 - 当你使用join()时,你会延迟渲染,直到工作者准备好,所以即使工作线程休眠也不会出现异常
当你这样做Thread.sleep(2000);的TextView是在之间,然后你想从这个的WorkerThread这导致崩溃触摸你的观点呈现
您也可以尝试Thread.sleep(0);看到它不会引发任何异常,您的应用程序也不会崩溃.