[英]If any worker thread can update UI in 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();
}
}
這是我的工作線程-
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.
我可以在模擬器上看到更新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);
}
}
因此,我猜Bajrang Hudda對ShadyGoneInsane的回答很滿意。 我真的同意他的觀點,即一旦渲染視圖並將其附加到Window后,您將無法直接從輔助線程訪問它。
為了回答有關progressBar的更新問題,ProgressBar在內部使用Runnable更新其進度,然后使用其處理程序過帳post(r)
。
詳細解釋一下,當您嘗試從工作線程progressBar.setProgress(i)
更新ProgressBar時,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.");
}
}
您試圖在視圖渲染后更改導致異常的文本
在下面的代碼段中,線程能夠在TextView對象中進行更改,因為它在UI屏幕上不可見,即未呈現。
class MyAndriodThread implements Runnable
{
@Override
public void run()
{
AndroidBasicThreadActivity.textView.setText("Hello!! Android Team :-) From child thread.");
}
}
正如@JohnnyAW所指出的那樣-當您使用join()時,延遲渲染直到工作器准備好為止,因此即使工作器線程處於睡眠狀態,也不會出現異常
當您執行此操作時Thread.sleep(2000);
TextView
在兩者之間呈現,然后您嘗試從此workerThread觸摸視圖,從而導致崩潰
您也可以嘗試Thread.sleep(0);
並且看到它不會引發任何異常,並且您的應用程序不會崩潰。
此行為確實發生。 正如在android的開發人員門戶網站上明確提到的那樣。
有一個帶有顯式引用的段落,其中指出:
非主線程上的許多任務的最終目標是更新UI對象。 但是,如果這些線程之一訪問視圖層次結構中的對象,則可能導致應用程序不穩定:如果輔助線程在任何其他線程引用該對象的同時更改了該對象的屬性,則結果是不確定的。
因此,這可能會發生並且是不確定的。
https://developer.android.com/topic/performance/threads.html
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.