If any workflow can update the user interface in Android?

I assume that we cannot update the UI view elements ( TextView , EditText , etc.) in any workflow, but in the example below, I can update the views from the workflow, not always, but only sometimes.

Below is an example where I am updating user interface elements in a workflow -

 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(); } } 

Here is my workflow -

 class MyAndriodThread implements Runnable { @Override public void run() { AndroidBasicThreadActivity.textView.setText("Hello!! Android Team :-) From child thread."); } } 

Believe me, I will not get any exception saying:

 android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views. 

And I can see the UI updates on the emulator.

But if I am doing a heavy task (sleeping) in a workflow, then I got the exception expected above, why is this happening? I'm a new guy on a multi-threaded android, please get me out of this confusion.

If I change my workflow to this, I will get the above exception -

 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."); } } 

And if my user interface or main thread is waiting (join ()), then I get the exact output without exception at all, see this -

 MyAndriodThread myTask = new MyAndriodThread(); Thread t1 = new Thread(myTask, "Anhad"); t1.start(); try { t1.join(); } catch (InterruptedException e) { e.printStackTrace(); } 

Update
At first I thought it was a rendering scheme, and then I changed my program using the ProgressBar. Then I got a really unexpected result ... However, an exception means that I can update my progress bar in the workflow. See below -

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

So Bajrang Hudda I assume you are mostly satisfied with ShadyGoneInsane 's answer. I really agree with him that after viewing and joining a window, you cannot access it directly from the workflow.

To answer your updated question about progressBar, ProgressBar internally uses Runnable to update its move, which then post(r) uses its handler.

To explain in detail when you try to update the ProgressBar from the progressBar.setProgress(i) workflow, the progressBar first checks to see if the call is being made to MainThread if it is being updated directly; otherwise, it creates a new Runnable RefreshProgressRunnable to update the progress, which then post(r) uses its handler.

For example new Handler().post(r)

and I'm sure you also used something like this before view.post(r)

ProgressBar source code check the setProgress () method

Hope this clears your doubts.

+5
source

The reason here is that the stream was only able to make changes to the TextView object until it was visible on the ie not rendered user interface screen. Only after rendering a view can any thread, except the main thread, be able to make changes to any components of the user interface.

So when you do this:

 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."); } } 

you are trying to change the text after rendering the view, which throws an exception

and in the code snippet below, the stream was able to make changes to the TextView object because it was not visible on the user interface screen, but was not displayed.

 class MyAndriodThread implements Runnable { @Override public void run() { AndroidBasicThreadActivity.textView.setText("Hello!! Android Team :-) From child thread."); } } 

As @JohnnyAW pointed out - when using join (), you defer rendering until the worker is ready, so you won't get an exception even if the worker thread is sleeping

when did you do this Thread.sleep(2000); , a TextView was displayed, and then you tried to touch your view from this workingThread, which caused the crash

you can also try Thread.sleep(0); and see that this does not cause any exceptions, and your application does not fail.

+4
source

This behavior does occur. As clearly stated on the Android developer portal.

There is a couple with explicit references that states that

Many tasks for non-core threads have the ultimate goal of updating user interface objects. However, if one of these threads accesses an object in the hierarchy of views, application instability can occur: if a workflow changes the properties of this object at the same time that any other thread refers to the object, the results are undefined.

So, this can happen and undefined.

https://developer.android.com/topic/performance/threads.html

+4
source

You can’t update anything in the ui thread from the background thread, to do this, you need to use Handler or use AsyncTask.onProgressUpdate , see AsyncTask for more details.

Update

It is not recommended to update your user interface from a workflow without the participation of Handler or to use Activity.runOnUiThread(Runnable) . In your case, when you update your TextView from MyAndriodThread , your view is in a transition state, if you try to update your interface, your view may receive an update or crash according to the documentation :

If a worker thread changes the properties of this object at the same time when any other thread references the object, the results are undefined

-1
source

You should try using BroadcastReceiver to update your user interface . For example, Once your workflow completes this task, it should send a broadcast using:

 Intent intent = new Intent(); intent.setAction("com.example.harshil.charotarexplore.android.action.broadcast"); sendBroadcast(intent); 

In your class:

 private static final String BROADCAST = "com.example.harshil.charotarexplore.android.action.broadcast"; private BroadcastReceiver locationReceiver; @Override protected void onCreate(Bundle savedInstanceState) { ... locationReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if (intent.getAction().matches(BROADCAST)) { onLocationAvailable(); } } }; 

In onStart :

 registerReceiver(locationReceiver, new IntentFilter(BROADCAST)); 
-3
source

Source: https://habr.com/ru/post/1264287/


All Articles