I'm working on downloading a html source from website and displaying it on TextView. It's being downloaded in another thread and I want to display it when it'll be finished. So. i have to pause main thread until it finish. Right now i do it like this:
MyAsyncTask task = new MyAsyncTask(this);
task.execute();
Thread.sleep(6000);
((TextView) findViewById(R.id.textView1)).setText(task.result);
But as you see it's not the best way to do this. I need something like "sleepUntil(boolean is MyTaskCompleated)". Is there something like this in Java. Or is there any better way to do it?
Having the UI thread sleep is no different than performing the actual work in the UI thread itself. Both cases will end up with a UI that is not responsive, and can cause an "Application Not Responding" message.
It seems like your goal is to not allow the user to perform any other actions while this work is being performed. One alternative approach to do this would be to block the UI with a progress dialog, and dismiss() the dialog in the onPostExecute() method of your AsyncTask subclass.
I use callbacks.
MyCallback.java
public interface MyCallback<T> {
public void onComplete(T result);
}
MyAsyncTask.java
public class MyAsyncTask extends AsyncTask<Void, Void, Boolean> {
private MyCallback<Boolean> mCallback;
public MyAsyncTask(MyCallback<Boolean> callback) {
mCallback = callback;
}
#Override
protected void onProgressUpdate(Void... progress) {
super.onProgressUpdate(progress);
// ...
}
#Override
protected Boolean doInBackground(Void... params) {
// ...
}
#Override
protected void onPostExecute(Boolean result) {
if (mCallback != null) {
mCallback.onComplete(result); // will call onComplete() on MyActivity once the job is done
}
}
}
In this example, this callback will take nothing as argument and return a Boolean.
Now all you have to do is to let your calling class (MyActivity for example) implements MyCallback:
public class MyActivity extends Activity implements MyCallback<Boolean> {
// ...
xxx {
MyAsyncTask myAsyncTask = new MyAsyncTask(this); // the callback
myAsyncTask.execute();
}
// ...
#Override
protected void onComplete(Boolean result) {
// ...
}
}
This is what I do and it works very well.
I would suggest creating a class that extends Asynctask and then perform your work in the overload methods. This will give you the ability to run your task on another thread and have it execute code after the result is completed.
http://developer.android.com/reference/android/os/AsyncTask.html
Look at the example under Usage. The overloads for onPreExecute and onPostExecute run on the UI thread so you can do something like show a progress dialog onPreExecute and dismiss it onPostExecute.
doSomeWork();
new MyAsyncTask().execute(url);
The AsyncTask:
private class MyAsyncTask extends AsyncTask<URL, Void, Void> {
protected void doInBackground(URL... urls) {
downloadHtml(urls[0]);
}
protected void onPostExecute(Long result) {
continueWorkHere();
}
}
Related
I'am trying to implement an AsyncTask in Android that will load all my data from the database. Therefore I used the onPreExecute method to start a ProgressDialog
public class DataLoader extends AsyncTask<Void, Void, Void> {
private LoginActivity activity;
private ProgressDialog nDialog;
public DataLoader (LoginActivity act){
this.activity = act;
nDialog = new ProgressDialog(activity);
}
protected void onPreExecute() {
System.out.print("Start AsyncTask");
nDialog.setMessage("Loading data..");
nDialog.setTitle("Starting the application");
nDialog.setIndeterminate(false);
nDialog.setCancelable(true);
nDialog.show();
}
#Override
protected Void doInBackground(Void ... params) {
System.out.println("Starting doInBackground");
loadDashboardData();
return null;
}
protected void onPostExecute() {
nDialog.dismiss();
Intent i = new Intent();
i.setClass(activity.getApplicationContext(), DashboardActivity.class);
activity.startActivity(i);
}
The I use the doInBackground method to load call a function to load the data. This method is called from an visible activity. The task is called with:
public class LoginActivity extends Activity {
public void onClick(View v) {
DataLoader dl = new DataLoader(this);
dl.execute();
}
}
And the code for the doInBackground is:
protected Void doInBackground(Void ... params) {
System.out.println("Starting doInBackground");
loadDashboardData();
return null;
}
Now the problem is that my doInBackground method will not finish. I tried to implement the loadDashboardData() call in the onPreExecute method. This will not show my dialog box but it will load the data correctly. In this case the UI Thread is not responding and will response after all the data has been loaded.
What can hinder the doInBackground method to execute correctly and load the data properly? The called method works (because I can call it and get the correct data). Also I'am not seeing the println in my run console.
In the frontend I can see the progressbar spinning, but in the backend I can see that no data is loaded.
Your problem is that you are overriding the wrong method name : )
It should be
#Override
protected void onPostExecute(Void result) {
// your code
}
as in your case the variable which doInBackground return is Void.
You can check the documentation about AsyncTask .
class TestAsync extends AsyncTask<Void, Void, Void> {
#Override
protected void onPreExecute() {
v.findViewById(R.id.loadinglayout).setVisibility(View.VISIBLE);
v.findViewById(R.id.wholecontentlayout).setVisibility(View.INVISIBLE);
super.onPreExecute();
}
#Override
protected Void doInBackground(Void... voids) {
callAPI();
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
v.findViewById(R.id.loadinglayout).setVisibility(View.INVISIBLE);
v.findViewById(R.id.wholecontentlayout).setVisibility(View.VISIBLE);
}
}
public void callAPI ()
{
RequestInterface requestInterface = new RequestImplementation();
requestInterface.setUrl("https://api.myjson.com/bins/vl9pp");
ConnectionExecutor connectionExecutor = new
ConnectionImplementation();
ResponseInterface temp = null;
try {
temp = connectionExecutor.executeConnection(requestInterface);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
rangeText.setText(temp.getPayload());
}
Call API function will call a method of another class where HttpConnection is done.
If the function is directly called from onViewCreated() in fragment then it works. If I call it from another async task it returns nothing.
I am actually trying to show a progress bar when the callApi function is called.
It is not allowed to start an AsyncTask outside the UI thread. doInBackground is outside the UI thread.
From https://developer.android.com/reference/android/os/AsyncTask.html:
Threading rules
...
The AsyncTask class must be loaded on the UI thread.
call it on onPostExecute method
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
v.findViewById(R.id.loadinglayout).setVisibility(View.INVISIBLE);
v.findViewById(R.id.wholecontentlayout).setVisibility(View.VISIBLE);
callAPI();
}}
From this SO answer
only inside onProgressUpdate() or onPostExecute() since these methods
runs on the UI thread. Therefore, start the second AsyncTask on the UI
thread by choosing one of the two methods listed above.
Simply put, if you're in need of firing up AsyncTask within another AsyncTask, it must be called from either onProgressUpdate() or onPostExecute() since they resides in UI thread.
To show the ProgressBar to illumilate the task is running, you should show your progress bar in onPreExecute() and hide it in onPostExecute(Result).
AsyncTask<Void, Void, Void> yourTask = new AsyncTask<Void, Void, Void>() {
#Override
protected void onPreExecute() {
super.onPreExecute();
/**
* Show your progress bar:
*/
yourProgressBar.setVisibility(View.VISIBLE);
}
#Override
protected Void doInBackground(Void... params) {
/**
* Do your stuffs in background thread
*/
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
/**
* Hide your progress bar:
*/
yourProgressBar.setVisibility(View.GONE);
}
};
Run the task: yourTask.execute();
onPostExecute(Result) method will get called when the task completed.
hi i have AsyncTask in my app but i am unable to change its setMessage
for example :-
private class ProgressTask1 extends AsyncTask<String, Void, Boolean> {
private ProgressDialog dialog;
public ProgressTask1(MainActivity mainActivity) {
context = mainActivity;
dialog = new ProgressDialog(context);
}
private Context context;
protected void onPreExecute() {
this.dialog.setMessage("Checking system...");
this.dialog.setCancelable(false);
this.dialog.setTitle("Please Wait...");
this.dialog.setIcon(R.drawable.ic_launcher);
this.dialog.show();
}
now i want that setmessage to change i tried adding it in doinbackground
protected Boolean doInBackground(final String... args) {
dothis1();
this.dialog.setMessage("one done...");
dothis2();
this.dialog.setMessage("two done...");
but this is making app force close and do not rate it low because i tried my best and searched forum but could able to fix this so asked for hand at this nice community :)
anybody can help ? :)
ERROR
05-13 23:36:34.899: E/AndroidRuntime(2454): Caused by:
android.view.ViewRootImpl$CalledFromWrongThreadException: Only the
original thread that created a view hierarchy can touch its views.
ohmm, you should not update UI from background thread. To update UI, you can do by two ways:
1) Using publishProgress (Progress... values) and onProgressUpdate(...). To do that, you must change your AsynTask class:
private class ProgressTask1 extends AsyncTask<String, String, Boolean> {
//.......... //your init
#Override
protected Boolean doInBackground(String... params) {
//your background handle
//publish to change UI
String toShow = "your_string_here";
publishProgress(toShow);
//return ...; //your return value
}
#Override
protected void onProgressUpdate(String... values) {
super.onProgressUpdate(values);
//detect message and show it.
//this.dialog.setMessage(values[0]);
}
}
2) Using onPostExecute(....):
private class ProgressTask1 extends AsyncTask<String, Void, Boolean> {
//.......... //your init
#Override
protected Boolean doInBackground(String... params) {
//your background handle
//return ...;//your return value
}
#Override
protected void onPostExecute(Boolean aBoolean) {
super.onPostExecute(aBoolean);
String toShow = "your_string_here";
//this.dialog.setMessage(toShow);
}
}
You cannot update the UI from the background.
See AsyncTask.onProgressUpdate to update the UI based on your background progress. :D
My problem is this;
I have a AsyncTask that works fine, and on doInBackground() it calls a new class that sync my data to a web service using REST service, i don't have everything on a unique class because i need the same content sync for different activitys and it's easier this way.
What i need is, on the sync procedure, i can get the number of "contacts" and everytime it downloads a contact, removes 1 from the "contacts" lenght, so, i nedd to show on the progress dialog the length of contact and refresh everytime it downloads a new "contact"
hre's my code for the AsyncTask:
public class syncContentTask extends AsyncTask<String, String, Boolean> {
private ProgressDialog mprogress;
private Context context;
//token for JSON header to authenticate
String authToken;
public syncContentTask(Context cxt, String token) {
this.context = cxt;
mprogress = new ProgressDialog(context);
authToken = token;
}
protected void onPreExecute() {
mprogress = ProgressDialog.show(context, "Sync", "Sync in progress...");
}
#Override
protected Boolean doInBackground(String... params) {
syncData syncData = new syncData();
syncData.syncData(context, authToken);
publishProgress(progress);
return true;
}
protected void onProgressUpdate(String... progress) {
//mprogress.setProgress(Integer.parseInt(progress[0]));
}
protected void onPostExecute(Boolean result) {
if (result) {
mprogress.dismiss();
}
}
}
In the Sync Data class i have functions that handles the HttpRequest and database stuff...
can anyone help??
You need to create a listener for your data progress and have it update the progress bar. Right now it looks like this line:
syncData.syncData(context, authToken);
blocks and no updates are provided to your progress indicator until it is done. So, you need something like:
MyListener listener = new MyListener(context);
SyncData syncData = new syncData(listener);
And in your listener have callback methods like myListener.downloadStarted() , myListener.updateProgressBar(int progress) and myListener.downloadCompleted() that your syncData class calls as the download progresses.
For example:
public abstract class SDScanAdapter implements SDScanListener {
public void startScan() {
}
public void updateScanProgress(int scanItemsTotal, int scanItemsCompleted) {
}
public void scanComplete() {
}
}
Then create a listener class:
public class ScanListener extends SDScanAdapter {
#Override
public void scanComplete(String contactName, String action) {
runOnUiThread(scanComplete);
}
#Override
public void startScan() {
runOnUiThread(startScan);
}
#Override
public void updateScanProgress(int scanItemsTotal,
int scanItemsCompleted) {
if (scanCountTotal != scanItemsTotal) {
scanCountTotal = scanItemsTotal;
progressBar.setMax(scanCountTotal);
}
if (scanCountUpdate != scanItemsCompleted) {
scanCountUpdate = scanItemsCompleted;
runOnUiThread(updateScanProgress);
}
}
}
And then for this example you need Runnables (startScan, scanComplete and updateScanProgress) that perform UI tasks, like updating the progress bar. In your case, you may also want to load some of the results, etc.
Then in your AsyncTask you do:
ScanListener listener = new ScanListener();
SyncData syncData = new syncData(listener);
Assuming the SDScanListener class and AsyncTask are all in your Activity. Also, your SyncData calss will need to have a SDScanListener variable that is set when it instantiates. Then, while it does its job, calls are made to the listener methods like:
scanListener.startScan();
And while it progresses, it calls the other methods (and corresponding parameters are passed in).
I recently needed to use AsyncTask in an activity in my android app. So I made a class inside the activity and extended AsyncTask in that class.
But now, whenever I launch that particular activity, my app immediately crashes. I tried putting the whole onCreate() of the activity in a try, catch block, but no exceptions were raised. The app just crashes immediately when I launch that activity, without any explanation in the LogCat.
This started happening after I added the AsyncTask class mentioned above. Also, the AsyncTask part is NOT executed when the activity is launched, it executes on pressing a button. What could be going wrong? I have added the relevant code below:
public class ListViewA extends Activity{
public void onCreate(Bundle savedInstanceState) {try{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
ListView lv= (ListView)findViewById(R.id.listview);
//computation
}
private String[] top() {
new RetreiveFeedTask().execute(ctr,ctz);
return er;
}
public class RetreiveFeedTask extends AsyncTask<Context, Void, String[]> {
String[] q;
protected String[] doInBackground(Context... params) {
//computation
}
protected void onPostExecute() {
er=q;
gff=true;
}
}
EDIT:
I found an error in LogCat which looks important:
java.lang.RuntimeException: Unable to instantiate activity ComponentInfo{com.example.exampleapp/com.example.exampleapp.ListViewA}: java.lang.NullPointerException
Your edit is interesting and suggests that there is a problem in the instantiation of the Activity, in which case I would look at the variable declarations quite carefully. However, in the absence of any of that code (or more onCreate code), or the surrounding lines from the logcat, it's hard to be more specific.
As #Raghunandan says, the way your AsynTask is constructed is incorrect, it should be something like:
public class RetreiveFeedTask extends AsyncTask<Context, Void, String[]> {
String[] q;
#Override
protected String[] doInBackground(Context... params) {
//computation
return result; // result is of type String[]
}
protected void onPostExecute(String[] result) {
// do something with result ...
er=q;
gff=true;
}
}
A secondary point is your top() function, which returns er. I am guessing that you want it to wait until the AsyncTask is complete and then return er, which has been calculated by the AsyncTask. However, what it will do at present is to set the AsyncTask and then immediately return er: it won't wait for the AsyncTask to complete.
To achieve that, you probably need to split the button press action into two phases:
Create and run the AsyncTask
OnPostExecute in the AsyncTask calls the code which currently uses the er returned by top.
public class ListViewA extends Activity{
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
ListView lv= (ListView)findViewById(R.id.listview);
//computation
new RetreiveFeedTask().execute(ctr,ctz);
}
...
public class RetreiveFeedTask extends AsyncTask<Context, Void, String[]>{
#Override
protected String[] doInBackground(Context... fileName) {
//computation
String[] q;
//Know that fileName is an Array
return q
}
protected void onPostExecute(String[] result) {
//do something with the result
}
}
...
}
I have a private class ReadFilesTask extends AsyncTask<String, Void, String> in my program. Under that, I have: protected void onPreExecute(),
protected String doInBackground(String... params), and
protected Void onPostExecute(String result).
The first two have #Override above them. The only one I'm ACTUALLY using though, is doInBackground. I'd first really just try adding #Override to doInBackground(). Next, try changing Context to String.
EDIT:
You are also missing the function to grab an activity. Again, this is simply what I'm doing in my code and a few examples I saw online:
public RetreiveFeedTask(Activity activity) {
this.activity = activity;
}
Something like that.