如何使AsyncTask是静态的并与活动分开?

时间:2018-07-26 12:59:21

标签: android android-asynctask adapter

我正在列出从AsyncTask下载的文件。

一切都很好,只有当我退出应用程序并重新启动它时,列表才会增加2倍=当我启动Activity时,AsyncTask会工作两次。 我可以以某种方式运行它一次并通常使其静态以使其不附加到Activity吗?

public class SpecialtyListActivity extends AppCompatActivity {
private static final String URL = "URL..";
public static ArrayList<Specialty> specialtyList = new ArrayList<>();
public static ArrayList<Worker> workerList = new ArrayList<>();
ListView listView;
EmployeesListFragment employeesListFragment;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.specialty_list);
listView = findViewById(R.id.spec_list);
employeesListFragment = new EmployeesListFragment();
if (Utils.isNetworkAvailable(this)) {
    new DataLoader(this).execute(URL);
} else {
    Toast.makeText(this, "No Network Connection", Toast.LENGTH_LONG).show();
}
}

@SuppressLint("StaticFieldLeak")
class DataLoader extends AsyncTask<String, Void, Void> {

@SuppressLint("StaticFieldLeak")
private Context mContext;
private ProgressDialog pdialog;
private final String TAG = getClass().getSimpleName();

DataLoader(Context context) {
    mContext = context;
}

@Override
protected void onPreExecute() {
    super.onPreExecute();
    pdialog = ProgressDialog.show(mContext, "__", "___");
}

@Override
protected void onPostExecute(Void result) {
    super.onPostExecute(result);
    if (mContext != null) {
        SpecialtyListAdapter adapter = new SpecialtyListAdapter(this.mContext, R.layout.specialty_list, specialtyList);
        listView.setAdapter(adapter);
        adapter.notifyDataSetChanged();
        pdialog.dismiss();
        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {

            }
        });
    }
}

@Override
protected Void doInBackground(String... params) {
    try {
        HttpHandler sh = new HttpHandler();
        String jsonStr = sh.makeServiceCall(params[0]);
        try {
            JSONObject reader = new JSONObject(jsonStr);
            JSONArray response = reader.getJSONArray("response");

            for (int i = 0; i < response.length(); i++) {
                String workerFName = response.getJSONObject(i).getString("f_name");
                String workerLName = response.getJSONObject(i).getString("l_name");
                String workerBithday = response.getJSONObject(i).getString("birthday");
                String workerAvatarUrl = response.getJSONObject(i).getString("avatr_url");
                int workerSpecialtyId = response.getJSONObject(i)
                        .getJSONArray("specialty")
                        .getJSONObject(0)
                        .getInt("specialty_id");
                String specialtyName = response.getJSONObject(i)
                        .getJSONArray("specialty")
                        .getJSONObject(0)
                        .getString("name");
                Specialty specialty = new Specialty(workerSpecialtyId, specialtyName);
                if (!specialtyList.contains(specialty)) {
                    specialtyList.add(specialty);
                }
                Worker worker = new Worker(workerFName, workerLName);
                worker.setBithday(workerBithday);
                worker.setAvatarLink(workerAvatarUrl);
                worker.setSpecialty(workerSpecialtyId);
                workerList.add(worker);
            }
        } catch (final JSONException e) {
            Log.e(TAG, "Json parsing error: " + e.getMessage());
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
    return null;
}
}

我还读到AsyncTask应该是静态的,该怎么做?

2 个答案:

答案 0 :(得分:2)

  

我还读到AsyncTask应该是静态的,该怎么做?

没有任何地方说AsyncTask应该是静态的。但是,确实如此,因为您已经将DataLoader类设为SpecialtyListActivity的内部类,所以可以通过将内部DataLoader类设为静态类来拥有slight performance edge。只需添加static修饰符:

static class DataLoader extends AsyncTask<String, Void, Void>

喜欢类定义使其静态。

您似乎对DataLoader AsyncTask触发两次的印象是因为它以某种方式“附加”到您的活动上。您可以参考Activity lifecycle以获得更多信息。

  

我可以以某种方式将其运行1次并通常使其静态以使其不附加到Activity吗?

您可以将AsyncTask设置为单独的类,而不是内部类或活动。 (但是,这不会解决您触发两次的问题,因为触发两次的原因不是因为它“附加到活动”。)使用以下模式使AsyncTask与活动松散耦合。

根据AsyncTask的结果,将您想要的类型的DataLoader设为第三个通用类型,在您的情况下为ArrayList<Worker>

//Third generic type is ArrayList<Worker>, this is what you want 
//to return to your activity once your AsyncTask completes.
class DataLoader extends AsyncTask<String, Void, ArrayList<Worker>> {

    private DataLoadListener mListener;

    DataLoader(Context context, DataLoadListener listener) {
        mContext = context;
        mListener = listener;
    }

    @Override
    protected ArrayList<Worker> doInBackground(String... params) {

         //download data...

         ArrayList<Worker> workersToReturn = new ArrayList<>();

         for (int i = 0; i < response.length(); i++) {
             //build worker object...
             workersToReturn.add(worker);
         }

         return workersToReturn;
    }

    @Override
    protected void onPostExecute(ArrayList<Worker> result) {
        listener.onDataLoaded(billItem);
    }

    //Your activity should implement this interface and override onDataLoaded() to
    //to receive the result when this AsyncTask completes.
    public interface DataLoadListener { 
        void onDataLoaded(ArrayList<Worker> workers);          
    }
}

public class SpecialtyListActivity extends AppCompatActivity implements DataLoader.DataLoadListener{

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        //Pass both context and DataLoadListener to the constructor
        new DataLoader(this, this).execute(URL);
    }

    @Override
    public void onDataLoaded(ArrayList<Worker> workers) {
         listView.setAdapter(new SpecialtyListAdapter(context, layout, specialtyList));
         listView.setAdapter(adapter);
         adapter.notifyDataSetChanged();
         //Do other stuff
    }

}

另请参见How to get the result of OnPostExecute() to main activity because AsyncTask is a separate class?

至于您的AsyncTask触发两次,您可以在doInBackground方法中添加一个断点并调试应用程序。查看调用堆栈以弄清楚为什么调用了两次。

答案 1 :(得分:0)

当活动进入onDestroy()时,退出应用程序时应取消AsyncTask。在asynctask的doInBackground()内部,您应该检查isCancelled(),如果为true则停止它。这样,您将始终只运行1个asyncTask。