Unpredictable behavior when accessing a view from another stream

I tried to create an application that uses a thread. While working, I found unpredictable behavior when trying to access a TextView from a stream. I know that android forbids us to get images directly from another thread. I also know how to access views of the main thread from another thread using AsyncTask, Handler, Activity.runOnUiThread (Runnable), View.post (Runnable), View.postDelayed (Runnable, long), etc.

Here is my code snippet -

public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); final TextView tv = (TextView) findViewById(R.id.tv); Thread t = new Thread(new Runnable() { @Override public void run() { /*try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); }*/ /*for(int i= 0 ; i<10000000 ;i++){ Log.i("logger"," i ="+i); tv.setText("i = "+i); }*/ tv.setText("This is the new text"); } }); t.start(); } 

When I run this code, no failure occurs, but as soon as I uncomment Thread.sleep () or for part of the loop, a failure will occur. Can anyone explain this behavior, why it happens this way, and why the crash does not happen with this code. Please do not post answers explaining how to do this.

Thanks in advance.

This is a crash log when I uncomment a section of the Thread.sleep () section -

 05-26 21:11:47.244: E/AndroidRuntime(14310): FATAL EXCEPTION: Thread-13346 05-26 21:11:47.244: E/AndroidRuntime(14310): android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views. 05-26 21:11:47.244: E/AndroidRuntime(14310): at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:5225) 05-26 21:11:47.244: E/AndroidRuntime(14310): at android.view.ViewRootImpl.requestLayout(ViewRootImpl.java:1062) 05-26 21:11:47.244: E/AndroidRuntime(14310): at android.view.View.requestLayout(View.java:15316) 05-26 21:11:47.244: E/AndroidRuntime(14310): at android.view.View.requestLayout(View.java:15316) 05-26 21:11:47.244: E/AndroidRuntime(14310): at android.view.View.requestLayout(View.java:15316) 05-26 21:11:47.244: E/AndroidRuntime(14310): at android.view.View.requestLayout(View.java:15316) 05-26 21:11:47.244: E/AndroidRuntime(14310): at android.view.View.requestLayout(View.java:15316) 05-26 21:11:47.244: E/AndroidRuntime(14310): at android.view.View.requestLayout(View.java:15316) 05-26 21:11:47.244: E/AndroidRuntime(14310): at android.widget.RelativeLayout.requestLayout(RelativeLayout.java:292) 05-26 21:11:47.244: E/AndroidRuntime(14310): at android.view.View.requestLayout(View.java:15316) 05-26 21:11:47.244: E/AndroidRuntime(14310): at android.widget.TextView.checkForRelayout(TextView.java:6659) 05-26 21:11:47.244: E/AndroidRuntime(14310): at android.widget.TextView.setText(TextView.java:3670) 05-26 21:11:47.244: E/AndroidRuntime(14310): at android.widget.TextView.setText(TextView.java:3528) 05-26 21:11:47.244: E/AndroidRuntime(14310): at android.widget.TextView.setText(TextView.java:3503) 05-26 21:11:47.244: E/AndroidRuntime(14310): at com.example.sampleproject.MainActivity$1.run(MainActivity.java:33) 05-26 21:11:47.244: E/AndroidRuntime(14310): at java.lang.Thread.run(Thread.java:864) 05-26 21:11:47.284: D/memalloc(14310): ion: Mapped buffer base:0x5432a000 size:2088960 offset:0 fd:66 
+6
source share
4 answers

Due to the state of the race.

Essentially, a failure occurs when a view tries to invalidate itself in the wrong thread. setText() does not invalidate the view if the view has not been measured at least once and the TextView has a non-empty mLayout .

When you create a new hierarchy of views using setContentView() , the message that measures the views is placed in the UI thread queue, but the likelihood that your thread will be started before the transmission skip creates a layout for the text view.

See the source for more details.

+4
source

You cannot update the interface from another thread, use this instead

 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); final TextView tv = (TextView) findViewById(R.id.tv); Thread t = new Thread(new Runnable() { @Override public void run() { runOnUiThread(new Runnable() { @Override public void run() { tv.setText("This is the new text"); } }); } }); t.start(); } 

If you want to know more about a good article:

http://android-developers.blogspot.co.uk/2009/05/painless-threading.html

0
source

Try to execute any code that interacts with the user interface like this

 runOnUiThread(new Runnable() { @Override public void run() { // Put your UI interactions here } }); 
0
source

below code works fine for me:

 public class MainActivity extends Activity { Handler handler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); Bundle data = msg.getData(); String result=data.getString("key"); textview.setText(result); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); final TextView tv = (TextView) findViewById(R.id.tv); Thread t = new Thread(new Runnable() { @Override public void run() { Bundle bundle=new Bundle(); bundle.putString("key","you data"); Message message=new Message(); message.setData(bundle); handler.sendMessage(message); } }); t.start(); } } 
0
source

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


All Articles