Pregunta

I have an Activity 'A' with it's child fragment, Activity 'B' and GetTask class. User launches the application and gets to Activity A. While user looks at ListView, AsyncTask is loading data for Activity B. But it may take a while and user can move to Activity B with no data for a ListView yet. So he have to wait. I'm creating a ProgressDialog here and want to check somehow when AsyncTask is completed.

Now I use static variable instance with a static method getInstance() which set to '1' in PostExecute method and then I take it in my Activity B

int instance = GetTask.getInstance();

Then I create a ProgressDialog, but I can't get AsyncTask status to know when dismiss my dialog. task.getStatus() always show RUNNING status.

I tried to make it with OnComplete listener, sample code below public class GetForeignToursTask extends AsyncTask implements OnTaskCompleteListener {

ActivityA just launches an AsyncTask:

GetTask task = new GetTask(this, null);
task.execute(url);

GetTask class sample:

    private Context context;
    OnTaskCompleteListener listener;

    private static int instance = 0;

    public GetTask(Context context, OnTaskCompleteListener listener) {
        this.listener = listener;
        this.context = context;
    }

    @Override
    public void onTaskCompleted(int status) {
        Log.d("log", status); // I don't get here at all
    }

ActivityB code:

GetTask task = new GetTask();
task.getStatus(); // here is always RUNNING
int instance = GetTask.getInstance();

if (instance != 1) {
    final ProgressDialog dialog = new ProgressDialog(ToursListActivity.this);
    dialog.setMessage("Loading...");
    dialog.show();
    // I also need to pause here until AsyncTask is done.
}

listener.onTaskCompleted(1); // error here

OnTaskCompleteListener interface:

public interface OnTaskCompleteListener {
void onTaskCompleted(int status);
}

I'm not sure I'm doing it right with all there CompleteListener. As I understood, to make CompleteListener work it should be started with an Activity which I'm going to listen, but my AsyncTask already running and I don't execute it from ActivityB. How to make it better? Or why I don't get into onTaskCompleteListener method?

I changed GetTask executing code in ActivityA to listener.onTaskCompleted(1); and getting the same error at line listener.onTaskCompleted(1); in ActivityB.

NullPointerException

Upd

ActivityB ListView dependens on ListItem which user will tap. So I think I can't load ListView before AsyncTask completed.

Solution

Well, I made it using BroadcastReceiver and static method in my AsyncTask to find out if AsyncTask completed before ActivityB is started.

Here is my code about it. In GetTask class I added method:

static boolean taskStatus = false;
public static boolean GetTaskStatus() {
    return taskStatus;
}

in onPostExecute()

Intent intent = new Intent("ru.myapp.asynctaskcompleted");
context.sendBroadcast(intent);

ActivityB

private ProgressDialog dialog;

protected void onCreate(Bundle savedInstanceState) {
    ...
    dialog = new ProgressDialog(ActivityB.this);
    taskStatus = GetTask.GetTaskStatus();
    ...
    if (!taskStatus) { // check if AsyncTask already completed
        dialog.setMessage("Loading...");
        dialog.show();
        dialog.setCancelable(false);
        dialog.setCanceledOnTouchOutside(false);
    } else {
        items = datasource.getSelectedItems(cid);
        setUpView(context, items);
        taskStatus = false; // in case of reloading data this should be returned to false I think
}

private BroadcastReceiver asynctaskcompleted = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        Log.d(TAG, "AsyncTask completed");
        datasource = new ItemsListDataSource(context);
        datasource.open();
        items = datasource.getSelectedItems(cid);
        setUpView(context, items);
        dialog.dismiss();
    }
};

public void onResume() {
    super.onResume();
    IntentFilter filter = new IntentFilter();
    filter.addAction("ru.myapp.asynctaskcompleted");
    filter.addCategory("android.intent.category.DEFAULT");
    registerReceiver(asynctaskcompleted, filter);
}

public void onPause() {
    super.onPause();
    unregisterReceiver(asynctaskcompleted);
}

Here is the link to another question I used; That's it. Thank you for your help.

¿Fue útil?

Solución

You don't need to call getStatus(), you don't need to create a new interface OnTaskCompleteListener, and you don't need getInstance()

Here's how you should do it.

mProgressDialog.show();
new GetTask()
{
    @Override
    protected void onPostExecute(Void result)
    {
        mProgressDialog.dismiss();

        //this means the task is done.
    }
}.execute(this, null);

Otros consejos

Load ListView in background AsyncTask Refer to the old exercise "ListView with icon loaded from internet", it's a time-consume task to load bitmap from internet. So the code is modified in this exercise, a AsyncTask is implemented to handle the ListView: the bitmap is loaded in background thread, and setListAdapter() in onPostExecute().

row.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<ImageView
android:id="@+id/icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/icon"/>
<TextView
android:id="@+id/weekofday"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>

AndroidList.java

import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;

import android.app.ListActivity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

public class AndroidList extends ListActivity {

public class backgroundLoadListView extends
  AsyncTask<Void, Void, Void> {

 @Override
 protected void onPostExecute(Void result) {
  // TODO Auto-generated method stub
  setListAdapter(new MyCustomAdapter(AndroidList.this, R.layout.row, month));
  Toast.makeText(AndroidList.this,
    "onPostExecute \n: setListAdapter after bitmap preloaded",
    Toast.LENGTH_LONG).show();
 }

 @Override
 protected void onPreExecute() {
  // TODO Auto-generated method stub
  Toast.makeText(AndroidList.this,
    "onPreExecute \n: preload bitmap in AsyncTask",
    Toast.LENGTH_LONG).show();
 }

 @Override
 protected Void doInBackground(Void... params) {
  // TODO Auto-generated method stub
  preLoadSrcBitmap();
  return null;
 }

}

String image_URL=
 "http://4.bp.blogspot.com/_C5a2qH8Y_jk/StYXDpZ9-WI/AAAAAAAAAJQ/sCgPx6jfWPU/S1600-R/android.png";

public class MyCustomAdapter extends ArrayAdapter<String> {
 Bitmap bm;

 public MyCustomAdapter(Context context, int textViewResourceId,
   String[] objects) {
  super(context, textViewResourceId, objects);
  // TODO Auto-generated constructor stub

  bm = srcBitmap;
 }

 @Override
 public View getView(int position, View convertView, ViewGroup parent) {
  // TODO Auto-generated method stub
  //return super.getView(position, convertView, parent);

  View row = convertView;

  if(row==null){
   LayoutInflater inflater=getLayoutInflater();
   row=inflater.inflate(R.layout.row, parent, false);
  }

  TextView label=(TextView)row.findViewById(R.id.weekofday);
  label.setText(month[position]);
  ImageView icon=(ImageView)row.findViewById(R.id.icon);

  icon.setImageBitmap(bm);

  return row;
 }
}

Bitmap srcBitmap;
private void preLoadSrcBitmap(){
 BitmapFactory.Options bmOptions;
 bmOptions = new BitmapFactory.Options();
 bmOptions.inSampleSize = 1;
 srcBitmap = LoadImage(image_URL, bmOptions);
}

String[] month = {
  "January", "February", "March", "April",
  "May", "June", "July", "August",
  "September", "October", "November", "December"
  };

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 //setContentView(R.layout.main);

 /*setListAdapter(new ArrayAdapter<String>(this,
       R.layout.row, R.id.weekofday, DayOfWeek));*/
 new backgroundLoadListView().execute();
}

@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
 // TODO Auto-generated method stub
 //super.onListItemClick(l, v, position, id);
 String selection = l.getItemAtPosition(position).toString();
 Toast.makeText(this, selection, Toast.LENGTH_LONG).show();
}

private Bitmap LoadImage(String URL, BitmapFactory.Options options)
{     
 Bitmap bitmap = null;
 InputStream in = null;     
 try {
  in = OpenHttpConnection(URL);
  bitmap = BitmapFactory.decodeStream(in, null, options);
  in.close();
 } catch (IOException e1) {
 }

 return bitmap;               
}

private InputStream OpenHttpConnection(String strURL) throws IOException{
 InputStream inputStream = null;
 URL url = new URL(strURL);
 URLConnection conn = url.openConnection();

 try{
  HttpURLConnection httpConn = (HttpURLConnection)conn;
  httpConn.setRequestMethod("GET");
  httpConn.connect();

  if (httpConn.getResponseCode() == HttpURLConnection.HTTP_OK) {
   inputStream = httpConn.getInputStream(); 
  } 
 }
 catch (Exception ex){
 }

 return inputStream;
}
}

[Reference] [Load ListView in background AsyncTask]1

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top