AsyncTask nested calls - android

Supposing I'm using the following AsycTask (called A) for sending data over internet:
private class A extends AsyncTask<Void, Void, Void>{
#Override
protected void onPreExecute() {
// TODO Auto-generated method stub
super.onPreExecute();
pd = ProgressDialog.show(context, "Notification", "Sending message...");
}
#Override
protected Void doInBackground(Void... params) {
// TODO Auto-generated method stub
sendMessage();
return null;
}
#Override
protected void onPostExecute(Void result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
if(pd!=null && pd.isShowing())
pd.dismiss();
}
}
Inside the doInbackground is called the my method sendMessage(). I will not go into details of this method, just immagine that this method executes a Thread (suppouse that it is called B).
So, the question is:
The code inside the onPostExecute() of AsyncTask A will be executed after the end of the Thread B?
If not, how can make possible that the onPostExecute will be executed only when the AsyncTask inside the sendMessage() will be terminated?

you could let the sendMessage() return the Thread object and then call
Thread.join()
This will cause the doInBackground to wait until the thread is finished.

Well it is pretty simple. Just call that AsyncTask B in onPostExecute of AsyncTask A.
Edit : Thread inside thread is not possible from ICS onwards. It will not give you any error, but it will not work too and your app will stuck there.

Related

Android - creating ListView content in AsyncTask causes random crash

I create the content of a ListView in the background and when each item is added I update the ListView adapter.Usually it works ok but some times I get this error. And strangely enough it happens 10 times more often in my Galaxy s4 mini than in my HTC Sensation. I don't understand why this happens since I clearly notify the adapter through the UI thread. Any thoughts ?
java.lang.IllegalStateException: The content of the adapter has changed but ListView
did not receive a notification. Make sure the content of your adapter is not modified
from a background thread, but only from the UI thread. Make sure your adapter calls
notifyDataSetChanged() when its content changes. [in ListView(2131100779, class
util.TouchInterceptor) with Adapter(class com.bill.deuterh.ListActivity$ListAdapter)]
AsyncTask:
private class AsyncCaller extends AsyncTask<Void,Void,Void>{
#Override
protected void onPostExecute(Void result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
ListActivity.this.runOnUiThread(new Runnable(){
#Override
public void run() {
findViewById(R.id.progress_bar).setVisibility(View.GONE);
}
});
}
#Override
protected Void doInBackground(Void... params) {
// TODO Auto-generated method stub
for (int i=0;i<table.length;i++){
if(isCancelled()){break;}
myList.add(createObject(table[i])));
ListActivity.this.runOnUiThread(new Runnable(){
#Override
public void run() {
ListAdapter.notifyDataSetChanged();
}
});
}
return null;
}
}
(If it matters, I cast the Listview as TouchInterceptor which is a modified google class for supporting the rearrangement of the listview items with drag and drop.)
Try this: If everything else has correct set up. Then this code will Show every update from your doInBackground immediatly in the listview = good user experience!
private class AsyncCaller extends AsyncTask<Void,Void,Void>{
#Override
protected void onPostExecute(Void result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
findViewById(R.id.progress_bar).setVisibility(View.GONE);
}
#Override
protected Void doInBackground(Void... params) {
// TODO Auto-generated method stub
for (int i=0;i<table.length;i++){
if(isCancelled()){break;}
myList.add(createObject(table[i])));
publishProgress();
}
return null;
}
protected void onProgressUpdate(Void.. values) {
ListAdapter.notifyDataSetChanged();
}
}
OnPreExecute, onPostExecute and onProgressUpdate are already running on the UIThread. Maybe you don't execute the asynctask the right way. That's why no data has been updated?
This should be run only once at the end of onpostexecute without the need of runonuithread.
ListAdapter.notifyDataSetChanged();
remove this:
ListActivity.this.runOnUiThread(new Runnable(){
#Override
public void run() {
ListAdapter.notifyDataSetChanged();
}
});
and put this:
#Override
protected void onPostExecute(Void result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
findViewById(R.id.progress_bar).setVisibility(View.GONE);
ListAdapter.notifyDataSetChanged();
}
Don't write any code in doInBackground(Void... params) which relates or update the UI. For updation on UI Async's onPostExecute(Void result) method is used.
So remove the adatper's notification from doInbackGround(Void... params){}

Refreshing custom List withing AsyncTask android

I have a custom List which I want to refresh when a action bar button is clicked.
This List is within a Fragment.
I want to show a ProgressBar until the List is refreshed.
Currently Iam doing this:-
private class RefreshList extends AsyncTask<Void, Void, Void>
{
#Override
protected void onPostExecute(Void result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
if(refDialog!=null)
{
refDialog.dismiss();
}
}
#Override
protected void onPreExecute() {
// TODO Auto-generated method stub
super.onPreExecute();
if(refDialog!=null)
{
refDialog =null;
}
refDialog = WaitProgressFragment.newInstance();
refDialog.show(getFragmentManager(), "Wait");
}
#Override
protected Void doInBackground(Void... params) {
// TODO Auto-generated method stub
//stagAdaper.notifyDataSetChanged();
itemsAdapter.notifyDataSetChanged();
return null;
}
}
But I get this error
Caused by: android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
How can I refresh the List while showing the progress dialog?
Put
itemsAdapter.notifyDataSetChanged();
Inside onPostExecute.
notifyDataSetChanged is an UI operation and doInBackground does not work on UI thread, whereas onPostExecute does.
You have to move the portion of the background task to the UI thread,so notify itemsAdapter in onPostExecute method as
#Override
protected void onPostExecute(Void result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
itemsAdapter.notifyDataSetChanged()
if(refDialog!=null)
{
refDialog.dismiss();
}
}

how to start the same asynctask on again clicking on the button [duplicate]

This question already has answers here:
Execute AsyncTask several times
(5 answers)
Closed 9 years ago.
I am new to Android and am now working on the counter thing using the AsyncTask.
So the thing is I'm having one button and with that button OnClickListener.
button.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
boolean check;
check=check_button_status();
if(check==true){
rec_forward_task.execute();
}
else
{
rec_forward_task.cancel();
}
}
});
So here the rec_forward_task is the class that extends the AsyncTask. The AsyncTask class is here.
//
private class CounterForwardTask extends AsyncTask<Void, Integer, Integer>
{
TextView record_counter_display;
int rec_counter,count;
int last_value;
#Override
protected void onPreExecute() {
// TODO Auto-generated method stub
record_counter_display=(TextView) findViewById(R.id.rec_voice_counter);
rec_counter=0;
record_counter_display.setText(String.valueOf(rec_counter));
count=0;
}
public void cancel() {
// TODO Auto-generated method stub
onCancelled();
}
#Override
protected Integer doInBackground(Void... params) {
// TODO Auto-generated method stub
while(rec_status)
{
publishProgress(count);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
last_value=count;
count=count+1;
}
return 1;
}
#Override
protected void onCancelled() {
// TODO Auto-generated method stub
record_counter_display.setText(String.valueOf(0));
}
#Override
protected void onProgressUpdate(Integer... values) {
// TODO Auto-generated method stub
runOnUiThread(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
record_counter_display.setText(String.valueOf(count));
}
});
}
#Override
protected void onPostExecute(Integer result) {
// TODO Auto-generated method stub
record_counter_display.setText(String.valueOf(last_value));
}
}
I'm making the object for that class in the oncreate method only so now the question is.
When user press first time the counter is starting and displaying in the textview and again pressing that same button the counter progress is stop due to oncancel method is called.but if user again pressing the same button app force closing and exception that u can't start the task which is already started.so what will be the way to perform this kind of operation.Thanks for any reply.
if(check==true){
rec_forward_task = new CounterForwardTask();
rec_forward_task.execute();
}
else
{
rec_forward_task.cancel();
}
Instead of instantiating AsyncTask in onCreate instaniate it when you need to start it. Hope this helps.
You will have to create a new AsyncTask object.
AsyncTasks are meant to run only once.
Check this answer.
The async task is designed to run only once. But you can run it by creating new instances of the asynctask class. See the answer of Passionate Androiden
Threading rules
There are a few threading rules that must be followed for this class to work properly:
The AsyncTask class must be loaded on the UI thread. This is done automatically as of JELLY_BEAN.
The task instance must be created on the UI thread.
execute(Params...) must be invoked on the UI thread.
Do not call onPreExecute(), onPostExecute(Result), doInBackground(Params...), onProgressUpdate(Progress...) manually.
The task can be executed only once (an exception will be thrown if a second execution is attempted.)
pls findout more in Developer site

Two background service android

In my acivity, i need to run two background service.
main background service:
class loadingTask extends AsyncTask<Void, Void,Void> {
#Override
protected void onPreExecute() {
// TODO Auto-generated method stub
pd = ProgressDialog.show(context, "", "Chargement en cours..", true, false);
super.onPreExecute();
}
#Override
protected void onPostExecute(Void result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
pd.dismiss();
}
...
#Override
protected Void doInBackground(Void... params) {
// TODO Auto-generated method stub
getxml = Util.CallWebService("");
return null;
}
}
Second background service.
class mloadingTask extends AsyncTask<String, Void, String> {
protected String doInBackground(String... urls) {
SAXHelper sh = null;
try {
sh = new SAXHelper(urls[0]);
} catch (MalformedURLException e) {
e.printStackTrace();
}
sh.parseContent("");
return "";
}
protected void onPostExecute(String s) {
pd.dismiss();
}
}
In my onCreate() method I want to call the first background and when it finished loading the second background service starts. Part of my background service is as follows.
AsyncTask<Void, Void,Void> loadTask = new loadingTask().execute();
if(loadTask.getStatus()==AsyncTask.Status.FINISHED){
new mloadingTask().execute(getxml);
System.out.println("getxml: "+getxml);
}
However the second background service doesn't seem to start. i am not getting the a print also. I think I miss a step or android doesn't allow more than one background service in the same activity. A help please.
AsyncTask<Void, Void,Void> loadTask = new loadingTask().execute();
if(loadTask.getStatus()==AsyncTask.Status.FINISHED){
new mloadingTask().execute(getxml);
System.out.println("getxml: "+getxml);
}
there is a 99% chance that the if() block will never pass.
You first execute the first asyncTask named loadTask and RIGHT after check if it finished.
Small chance that it actually finishes by then.
The easy approach:
Use only one async task. You want to finish asyncTask 1 and then fire asyncTask 2, its exactly the same as having only one asyncTask doing both operations.
class loadingTask extends AsyncTask<Void, Void,Void> {
#Override
protected void onPreExecute() {
// TODO Auto-generated method stub
pd = ProgressDialog.show(context, "", "Chargement en cours..", true, false);
super.onPreExecute();
}
#Override
protected void onPostExecute(Void result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
pd.dismiss();
}
...
#Override
protected Void doInBackground(Void... params) {
// TODO Auto-generated method stub
getxml = Util.CallWebService("");
SAXHelper sh = null;
try {
sh = new SAXHelper(urls[0]);
} catch (MalformedURLException e) {
e.printStackTrace();
}
sh.parseContent("");
return null;
}
}
The difficult approach:
How I solve this kind of thing is(our situation is different, but it should do)
Create an interface, with one method. for example:
public interface OnDataChangedListner {
void dataChanged(Class listener);
}
Then somewhere (i use my repository classes)
write a method to add and remove entires to a list of OnDataChangedListener interfaces
private ArrayList<OnDataChangedListner> mOnDataChangedListners;
public void addOnDataChangedListner(OnDataChangedListner onDataChangedListner){
synchronized (mOnDataChangedListners){
mOnDataChangedListners.add(onDataChangedListner);
}
}
public void removeOnDataChangedListner(OnDataChangedListner onyDataChangedListner){
if (mOnDataChangedListners != null){
synchronized (mOnDataChangedListners){
for (Iterator<OnDataChangedListner> it = mOnDataChangedListners.iterator(); it.hasNext();) {
OnDataChangedListner listener = it.next();
if (listener .equals(onDataChangedListner))
it.remove();
}
}
}
}
This might be overkill. But this example should help you with updating the UI while your tasks are running. A free extra! :))
With the above code in place, create an onDataChanged() method in the same class where u defined the add and remove listener methods.
In that code call a handler
// Need handler for callbacks to the UI thread
final static Handler mHandler = new Handler();
// Create runnable for posting
final Runnable mNotifyDataChanged = new Runnable() {
public void run() {
if (mOnDataChangedListners != null){
synchronized (mOnDataChangedListners){
for (Iterator<OnDataChangedListner> it = mOnDataChangedListners.iterator(); it.hasNext();) {
OnDataChangedListner listener = it.next();
if (listener != null)
listener.dataChanged(this.getClass());
else
it.remove();
}
}
}
}
};
/**
* will notify registerred delegates on the main (UI) thread
*/
public void notifyDataChanged(){
mHandler.post(mNotifyDataChanged);
}
Ok, so I ended up giving out an entire sample.
Where you place this code is upto you. But when you call notifyDataChanged() it will fire the handler, which in turn will loop trough all current registered listeners for this class
then in turn it will call the listeners datachanged method.
To make this all work, all you have to do is have a class implement the interface
call addOnDataChangedListener(this);
and implement the method provided in the interface.
Note that this is deffinetly not the easiest way to do things.
I don't know what the easiest way to do what you want is. I never have been in that situation before.
but you can execute the second task in the implemented method. Should work..
AsyncTask is Asynchronous as its name suggest. You need to call your 2nd AsyncTask in onPostExecute of your 1st AsyncTask
OR
Loop and wait till AsyncTask is finished in your activity, but it may take more time and you can get Application Not Responding message.
As soon as you call execute() method, control comes to next statement which loadTask.getStatus(). As task is just started, loadTask.getStatus() will not return FINISH and your 2nd task is never getting executed.

outofmemoryerror in android

I have one running some methods in doInBackground in AsyncTask ,which is calling webservices and inserting number of records into the database , at the same user click on other screen then outOfmemoryError is coming I want to stop the background thread temporarily till the screen loads and then thread has to resume from it stopped such that the memory will release. can anybody tell me how to achieve this.
Thanks in Advance.
The Asynctask can be executed only once (an exception will be thrown if a second execution is attempted.).. so to pause and resume .. i think you should use a backgroundthread instead...
//decleration
ProgressDialog dialog;
//onCreate
dialog = new ProgressDialog(ActivityName.this);
public class BackGroundTask extends AsyncTask<String, String, String> {
#Override
protected String doInBackground(String... params) {
// TODO Auto-generated method stub
//perform background task
return null;
}
#Override
protected void onPreExecute() {
// TODO Auto-generated method stub
super.onPreExecute();
dialog.setMessage("Please wait.....");
dialog.setIndeterminate(true);
dialog.setCancelable(false);
dialog.show();
}
#Override
protected void onPostExecute(String sResponse) {
if (dialog.isShowing())
{
dialog.dismiss();
}
}

Categories

Resources