In one activity of my app I make a bunch of edit text fields dynamically and then set them with some text from sharedpreferences. I realise that this is a bit much for the main thread to handle which is why there is some lagging of the app when it loads. I am quite new to the concept of threads so I was wondering what the best way was to put the loading of the strings from sharedpreferences into another thread and then just display a loading bar(or similar) in the meantime(in the main thread I guess). Please explain in great detail because threads are new to me.
Also if there are any tutorials on this that point me the the right direction they would also be useful. Thanks in advance.
AsyncTask is what you need.
Create a class that extends AsyncTask
Do your heavy work in doInBackground()
Example:
Class Example extends AsyncTask{
#Override
protected void doInBackground(Object... args){
//do ur stuff
}
#Override
protected void onPostExecute(Object arg){
//do what you wanna do after doInBackground
}
}
Call your task by new Example().execute();
Whilst only the main thread can make changes to the UI, you can you the AsyncTask class to do all the other work on another thread and then push things to the main thread as they are ready to be put on the UI.
YOu can have something like this: Just to guide you
final ProgressDialog pd = ProgressDialog.show(context, "Title", "Loading");
new Thread(new Runnable()
{
#Override
public void run()
{
//get data from shared preferences
runOnUiThread(new Runnable()
{
#Override
public void run()
{
pd.dismiss();
//set that text to your dynamic textview
}
});
}
}).start();
Related
Here is my code for Progress Dialog in Android and i am getting following error:android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views. I saw all previous post related to this error but i could not correct this error.
// Waiting screen
pleaseWaitdialog = ProgressDialog.show(PhoneBookListView.this, "Loading", "Please wait...", true);
new Thread(new Runnable() {
#Override
public void run()
{
Looper.prepare();
// do the thing that takes a long time
LoadContactFromPhoneAndSim();
PhoneBookListView.this.runOnUiThread(new Runnable() {
#Override
public void run()
{
pleaseWaitdialog.dismiss();
}
});
}
}).start();
Any help will be appreciate
Thanks.
I suggest you use an AsyncTask, as they make this sort of thing easier. In general, you want to do complex stuff on a background thread, and only update the UI from the UI thread.
public class PhonebookLoader extends AsyncTask<Void,Void,Void> {
protected Void doInBackground(Void ... params) {
LoadContactFromPhoneAndSim();
return void;
}
protected void onPostExecute(Void param) {
pleaseWaitdialog.dismiss();
}
}
To start it with this class, you just call this:
new PhonebookLoader.execute();
And you can do all kinds of things with this, like publish your progress so the user knows how far they have progressed, update the UI thread after you are done loading, etc. AsyncTask is your friend, use it.
Looking at this, I suspect that PhonebookLoader is probably both loading the data and putting it on the UI. Separating these two tasks will make your app much more responsive and easier to maintain.
I need to process some data when the user click the button in one activity, so the screen looks like the app stops for 2-3 seconds. It isn't a lot but I want to give the user information that everything is ok and IMO the best way will be the progressbar which is visible only when data are processed.
I found the code of ProgressBar and it looks like this:
<ProgressBar
android:id="#+id/loadingdata_progress"
style="?android:attr/progressBarStyle"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_alignBottom="#+id/fin2_note"
android:layout_centerHorizontal="true"
android:indeterminate="true"
android:visibility="invisible" />
and inserted it on the middle of my layout.
And to try if the progressbar works, I put this code
loadingimage= (ProgressBar) findViewById(R.id.loadingdata_progress);
loadingimage.setVisibility(View.VISIBLE);
into onCreate method and everything looks fine.
Then I recreated the code to show this progressbar only if the data is processed.
After click the user invoke this method
public void fin2_clickOnFinalization(View v)
{
loadingimage= (ProgressBar) findViewById(R.id.loadingdata_progress);
loadingimage.setVisibility(View.VISIBLE);
// code where data is processing
loadingimage.setVisibility(View.INVISIBLE);
}
and nothing appear on the screen. I don't know where is the mistake. If I found the progress bar by id, It's strange for me that I can control it in onCreate method but in onclick method it's out of my control.
Your UI thread cannot show progress bar cause it is busy due to your data processing. Try to use this kind of code :
public void fin2_clickOnFinalization(View v) {
new YourAsyncTask().execute();
}
private class YourAsyncTask extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... args) {
// code where data is processing
return null;
}
#Override
protected void onPostExecute(Void result) {
loadingimage.setVisibility(View.INVISIBLE);
super.onPostExecute(result);
}
#Override
protected void onPreExecute() {
super.onPreExecute();
loadingimage.setVisibility(View.VISIBLE);
}
}
EDIT:
AsyncTask let you run code in separate thread and make app more responsive, just put time-consuming code inside doInBackground.
You're not giving the UI time to refresh. Your "data processing" code is running on the UI thread, blocking any visible changes. By the time the system gets control to refresh the display, you've already set it back to invisible.
To fix this, move your processing code to a separate thread or AsyncTask. Then you can set the progress bar to visible, start the task, and have it turn itself invisible once it's done.
I'd recommend AsyncTask for this purpose about 90% of the time on Android, since it comes stock with useful callbacks. The developer guide for it(in the Javadoc linked above) is pretty explicit, and outlines all the steps you need to take.
AsyncTask is too heavily-weighted for such task.
A better much solution
Handler handler = new Handler(getMainLooper());
handler.post(new Runnable() {
#Override
public void run() {
loadingimage.setVisibility(View.VISIBLE);
}
});
Or even simpler (does essentially the same thing as solution above)
runOnUiThread(new Runnable() {
#Override
public void run() {
loadingimage.setVisibility(View.VISIBLE);
}
});
You can try to create a global ProgressDialog not in the layout but in your activity like:
public class MyActivity {
ProgressDialog progress = null;
protected void onCreate(...) {
progressDialog = new ProgressDialog(this);
progressDialog.setCancelable(false);
progressDialog.setTitle("Progress");
}
public void fin2_clickOnFinalization(View v)
{
progress.show();
// code where data is processing
progress.dismiss();
}
}
Hope i it helps
In my application I need to update the text in the UI depending upon the data from the network.For that I am using a AsyncTask to do work in background in Android. My code is as follows.
public class DefaultActivity extends Activity{
TextView textView;
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
textView=(TextView)findViewById(R.id.textId);
new networkFileAccess().execute("background","Progress","result");
}
private class networkFileAccess extends AsyncTask<String,String,String>{
protected String doInBackground(String... background){
return changeText();
}
private String changeText(){
//Code to Access data from the Network.
//Parsing the data.
//Retrieving the boolean Value.
if(booleanistrue){
//Displaying some text on the UI.
publishProgress("someTextOnUI");
//Send request till we get get boolean value as false.
changeText();
}else{
return "success";
}
return "";
}
protected void onProgressUpdate(String... progress){
textView.setText("Wait background work is going on");
}
protected void onPostExecute(String result){
if(result.equals("success")){
//Code to finish the activity.
}
}
}
}
In the above code I am able to run the background thread till I get boolean value as false.But the text is not updating on the UI. Can I update the text on the UI using onProgressUpdate() method by calling publishProgress method.?Any suggesstions.
Put your Ui method inside runonUiTHREAD like this
runOnUiThread(new Runnable() {
public void run() {
tv.setText("ABC");
}
});
In AsyncTask, onPostExecute() and onPreExecute() both runs on UI thread. So you can change the text in onPostExecute() method.
Or you can also call runOnUiThread in doInBackground() method which runs in thread:
runOnUiThread(new Runnable() {
public void run() {
// change text
}
});
It post runnable to run on UI thread.
I guess the short answer is, yes, you can update UI elements in the onProgressUpdate method. OnProgressUpdate is actually invoked on the UI thread itself, so you don't need to do anything fancy.
How do you know your onProgressUpdate isn't working if it's hardcoded to "Wait background work is going on"?
Also, is there any reason why you aren't using a ProgressDialog to show the "Wait background work is going on" message to your users? It's typically more intuitive if you actually want them to wait. It displays a spinner or progress bar (your choice) that lets them know work is being done. It also doubles up as a way of preventing them from doing other stuff until your application is done processing whatever it has to.
In an activity I load rows of a listview which takes much time, therefore I put this task in a separate thread to allow displaying a progressDialog.
I do the following
private void doMyStuff() {
listItems.clear();
progressDialog.show();
new Thread(new Runnable() {
#Override
public void run() {
for () {
listItems.add(something to add);
}
handler.sendEmptyMessage(0);
progressDialog.dismiss();
}
}).start();
}
private Handler handler = new Handler() {
public void handleMessage(android.os.Message msg) {
if (msg.what == 0) {
adapter.notifyDataSetChanged();
}
};
};
I have sometimes a bug which raises an IllegalStateException. First of all I was surprised, because programming thread like that is what I usually do in standard Java programs.
The bug appears only "sometimes" and it does not appear when doing step by step debugging.
This lead me to search around the web and I found some questions in SO related to this and I must admit that things are not clear to my mind.
As I call the notifyDataSetChanged() only when the thread finished why does it sometimes raises an exception.
Can someone confirm me that this way of doing is wrong, and that I MUST use async task and perhaps explain me why ???
I need to have a progressDialog displayed, can someone give me a simple example of AsyncTask populating a listview AND displaying a progressDialog of the populating progress.
Thanks
UPDATE
jtanveer gave me the answer to the asynctask question. Now the others pointed out that the dismiss is not in the handler, which I correct.
According to the article given by jtanveer on "Painless Threading" they say that
Android offers several ways to access the UI thread from other threads which one of them is HANDLER.
Does someone know why putting the dismissed in the handler did not solve my problem ? for me listItem.add has nothing to do with UI ? Am I wrong on that point ?
For me, in my code the only UI is adapter and progressdialog ? Any commentary or explanation is welcome.
FINAL ANSWER
stjom gave a working answer for my specific code. Running the runOnUiThread in the handler. It's working but I am surprised because I thought the handler was run in the Ui Thread ...
Thanx to all for all your answers.
define an inner class like below:
private class LoadListTask extends AsyncTask<String, Void, Integer> {
protected void onPreExecute() {
progressDialog.show();
}
protected Integer doInBackground(String... params) {
for () {
listItems.add(something to add);
}
return 0;
}
protected void onPostExecute(Integer result) {
progressDialog.dismiss();
if (result == 0) {
adapter.notifyDataSetChanged();
}
}
}
if you need, you can refer to this article.
whenever you call adapter.notifyDataSetChanged(); it identifies any changes to your listItems object. if any change is found, it will update the UI accordingly which I think causes your problem. you can call
runOnUiThread(new Runnable() {
public void run() {
adapter.notifyDataSetChanged();
}
});
inside your handler.
You don't need to use AsyncTask, its just a convenience.
As far as why your current implementation doesn't work sometimes -
You should dismiss your progress dialog from the UI thread, so that needs to go in your handler, not your background thread.
I use AsyncTask to change text of TextView like this:
private class LongOperation extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... urls) {
String response = "";
for (String url : urls) {
response += url;
}
return response;
}
#Override
protected void onPostExecute(String result) {
textView.setText(result);
}
}
Everything will fine if I call it in OnClick event:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
textView = (TextView) findViewById(R.id.txt);
Button button = (Button)this.findViewById(R.id.button);
button.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
new LongOperation().execute(new String[]{"Hello"});
}
});
}
But the problem when I called it in my thread, the program forced close
this.closeButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Thread t= new Thread(){
#Override
public void run(){
try{
//Do something
//Then call AsyncTask
new LongOperation().execute(new String[]{"Hello"});
}catch(Exception e){}
}
};
t.start();
}
});
Where am I wrong? I dont' understand how difference call AsyncTask in thread or not.
I recommend you consult the AsyncTask documentation and Processes and Threads for a better understanding of how it works. Essentially, you should create your AsyncTask subclass on the main thread.
When you call AsyncTask.execute(), your provided, AsyncTask.onPreExecute is called on the main thread, so you can do UI setup.
Next AsyncTask.doInBackground method is called, and runs in its own thread.
Finally, when your AsyncTask.doInBackground method completes, a call is made to AsyncTask.onPostExecute on the main thread, and you can do any UI cleanup.
If you need to update the UI from within your AsyncTask.doInBackground method, call AsyncTask.publishProgress, which will invoke onProgressUpdate in the main thread.
When you call it from the UI thread, the associated Context is the running Activity. When you call it from a regular thread, there is no valid Context associated with that thread. AsyncTask executes in its own thread, you shouldn't be creating its own thread. If that is actual code, then you have missunderstood the point of AsyncTask. Search for tutorials on how to use it.
Adding to what the others have said: I think you can use AsyncTask to launch off a task in another thread, even if you start the AsyncTask from a different thread than the UI already.
But in that case, the only way you'll only be able to modify the UI indirectly, for example: pass the handler of the current Activity somehow to this AsyncTask instance, and send messages to it (handler messages get processed on the UI thread). Or use broadcast intents that the Activity catches and updates the UI accordingly, etc. These solutions seem to be overkills though.