How to change TextView text persistently in Android? - android

I've tried using Thread, but it was unsuccessful, the textView didn't changed after I change the TextView text using EditText as input. Help me, please!
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
//shared is SharedPreferences object that I define as an instance variable
String inp = shared.getString("input", def);
textView.setText(inp);
Log.d("input",inp);
});
thread.start();

try this:
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
//shared is SharedPreferences object that I define as an instance variable
String inp = shared.getString("input", def);
runOnUiThread(new Runnable() {
#Override
public void run() {
textView.setText(inp);
Log.d("input",inp);
}
});
});
thread.start();
for updating UI you should use the main ui thread. take a look at :
Android runOnUiThread explanation

Why are you doing it in a separate thread. Even if you want to, you cannot update the any UI component such as textView in a non UI thread.

Related

Difference between setting text on a text view

What is the difference between
textView.setText("hello")
and
textView.post(new Runnable() {
#Override
public void run() {
mTxtTimer.setText(time);
}
});
If i have to set text in a loop which is beneficial for me.
textView.post(new Runnable() {
#Override
public void run() {
mTxtTimer.setText(time);
}
});
This is creating new child thread of working in UI(parent thread)
This will run in the UI thread, no matter who calls it.

Why does Handler that have set a looper of HandlerThread can interact with UI Objects?

why this code works?
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.i("onCreate", Thread.currentThread().toString());
textView = (TextView) findViewById(R.id.textView);
imageView = (ImageView) findViewById(R.id.imageView);
HandlerThread thread = new HandlerThread("myHandlerThread");
thread.start();
mUiHandler = new Handler(thread.getLooper());
mUiHandler.post(new Runnable() {
#Override
public void run() {
Log.i("Thread: ", Thread.currentThread().toString());
Toast.makeText(getApplicationContext(), "Hello Cats!", Toast.LENGTH_SHORT).show();
textView.setText("Hello Cats");
imageView.setImageResource(R.mipmap.ic_launcher);
}
});
}
i read from somewhere that the only thread that can communicate with UI objects is UI thread, or i miss something
i have some research but not found the answer yet, please help, thank you so much guys.
this is what i got from log
10-13 18:47:42.888 23841-23841/th.co.me.sampleapp I/onCreate: Thread[main,5,main]
10-13 18:47:42.891 23841-24041/th.co.me.sampleapp I/Thread:: Thread[myHandlerThread,5,main]
UPDATE 1
i tried this code from #nshmura and the error occurs it is so confusing to me now
textView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
HandlerThread thread = new HandlerThread("myHandlerThread");
thread.start();
mUiHandler = new Handler(thread.getLooper());
mUiHandler.post(new Runnable() {
#Override
public void run() {
Log.i("Thread: ", Thread.currentThread().toString());
Toast.makeText(getApplicationContext(), "Hello Cats!", Toast.LENGTH_SHORT).show();
textView.setText("Hello Cats");
imageView.setImageResource(R.mipmap.ic_launcher);
}
});
}
});
android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
the exception android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views. will be thrown only if:
called from non ui thread
the call requires a layout change. For example if the size (width and height) of a TextView should be extended, because of the too long string
So if your ui operation doesn't lead to a layout change (create or recreate), the exception may not be thrown.
A Handler object registers itself with the thread in which it is created. It provides a channel to send data to this thread. For example, if you create a new Handler instance in the onCreate()method of your activity, it can be used to post data to the main thread. The data which can be posted via the Handler class can be an instance of the Message or the Runnable class.
So based on the below line, your handler should be belongs to HandlerThread.
mUiHandler = new Handler(thread.getLooper());
One thing I understand OnCreate() is main thread but OnClick Listener is separate Class. That means there is context difference.
for example:
// onCreate() we are writing like this
Toast.makeText(this, "Hello Cats!", Toast.LENGTH_SHORT).show();
// but in Onclick method we are writing like this
Toast.makeText(MainActivity.this, "Hello Cats!", Toast.LENGTH_SHORT).show();
Check like this:
textView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
HandlerThread thread = new HandlerThread("myHandlerThread");
thread.start();
mUiHandler = new Handler(thread.getLooper());
mUiHandler.post(new Runnable() {
#Override
public void run() {
Log.i("Thread: ", Thread.currentThread().toString());
Toast.makeText(getApplicationContext(), "Hello Cats!", Toast.LENGTH_SHORT).show();
textView.setText("Hello Cats");
imageView.setImageResource(R.mipmap.ic_launcher);
}
});
}
});
Exception will happen:
android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:6556)
at android.view.ViewRootImpl.invalidateChildInParent(ViewRootImpl.java:942)
at android.view.ViewGroup.invalidateChild(ViewGroup.java:5081)
at android.view.View.invalidateInternal(View.java:12719)
at android.view.View.invalidate(View.java:12683)
at android.view.View.invalidate(View.java:12667)
at android.widget.TextView.checkForRelayout(TextView.java:7156)
at android.widget.TextView.setText(TextView.java:4347)
at android.widget.TextView.setText(TextView.java:4204)
at android.widget.TextView.setText(TextView.java:4179)
Maybe the ViewRootImpl.checkThread() is not called at Activity.onCreate()
Try this code
mHandler = new Handler();
new Thread(new Runnable() {
#Override
public void run () {
// Perform long-running task here
// (like audio buffering).
// you may want to update some progress
// bar every second, so use handler:
mHandler.post(new Runnable() {
#Override
public void run () {
// make operation on UI - on example
// on progress bar.
}
});
}
}).start();

Android: Handler with MainLooper : "only the original thread that created a view hierarchy can touch its views."

From my generic fragment, I have this method:
protected void loadDataListWithDelay() {
Handler handler = new Handler(Looper.getMainLooper());
handler.postDelayed(new Runnable() {
#Override
public void run() {
loadDataList();
}
}, DELAY_START_LOADING);
}
This method allows to start a new loading data from server (with Volley networking).
In my loadDataList() method there are some views visibility setting:
protected void loadDataList(String url, ArrayList<BaseFilters> filters,
String query, boolean byPassSearchMode) {
...
mLoadingDataListView.setVisibility(View.INVISIBLE);
mListContainer.setVisibility(View.VISIBLE);
...
This code runs perfectly, but I have this crash this morning on mobile with Android 6.0.1.
Could you help me guys?
I will give you a good advice, if you want to do postDelayed, take a view in your fragment (or any view), and do postDelayed with it. i.e. textView.postDelayed(.. This way you can be sure you are on the ui thread.
Why not use runOnUiThread instead of creating a new handler ?
runOnUiThread(new Runnable() {
#Override
public void run() {
loadDataList();
}
});
If you need a delay, then you can use a handler inside the runOnUiThread
runOnUiThread(new Runnable() {
#Override
public void run() {
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
loadDataList();
}
}, DELAY);
}
});

Updating UI In Android

I want to Update UI from background thread and if user wants to interact with UI while updating then the UI should not blocked by background thread.
Please Help me out.
This can be done using handlers to post UI updates from background thread. You can refer https://developer.android.com/training/multiple-threads/communicate-ui.html for code sample.
Using this you can update UI from backgorund thread
runOnUiThread()
runOnUiThread(new Runnable() {
#Override
public void run() {
//ui update stuff
}
});
You can use handler to serve this purpose.
A simple example:
Create a class:
class Task implements Runnable {
#Override
public void run() {
for (int i = 0; i <= 20; i++) {
final int value = i;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
handler.post(new Runnable() {
#Override
public void run() {
progressBar.setProgress(value);
}
});
}
}
}
Then call it from where you want to update the UI like this:
new Thread(new Task()).start();
Complete Example can be found here.
Or you can also go with different approach. Using runOnUiThread method will also allow you to achieve your expected result.
Example:
runOnUiThread(new Runnable() {
#Override
public void run() {
btn.setText("#" + i);
}
});

why I load long text in textView does not show me?¿

I use this new thread from a method called from onCreate().
info is a textView().
new Thread(new Runnable() {
public void run() {
info.post(new Runnable(){
public void run() {
info.setText(panel.getInfo());
}
});
}
}).start();
If info.setText(panel.getInfo()); call without creating the thread take 3-4 seconds being blocked application but showing it,
then how can I show the text without being blocked the app¿?
new Thread(new Runnable() {
public void run() {
String text = panel.getInfo();
info.post(new Runnable(){
public void run() {
info.setText(text);
}
});
}
}).start();
Actually what is taking long is your panel.getInfo() call. And your a making this call in the info.post, so you're doing it in the UI thread.
First of all, I think you should move code String text = panel.getInfo(); from info.post method, because it will be executed at UI thread. Do something like this:
new Thread(new Runnable() {
public void run() {
String text = panel.getInfo();
info.post(new Runnable(){
public void run() {
info.setText(text);
}
});
}
}).start();
Secondly, I think you should save your thread in class member, because GC may destroy your Thread, before it be in time to do something. So, do something like this:
mThread = new Thread(new Runnable() {
public void run() {
String text = panel.getInfo();
info.post(new Runnable(){
public void run() {
info.setText(text);
}
});
}
}).start();
Where mThread is a class member:
public abstract class MyActivity extends ActionBarActivity{
private Thread mThread;
/*Other code*/
}

Categories

Resources