如何使 AsyncTask 是静态的并与 activity 分开?
How to make AsyncTask is static and Separate from activity?
我正在使用从 AsyncTask 下载的列表。
一切都很好,只有当我退出应用程序并重新启动它时,列表增加了 2 倍 = AsyncTask 在我启动时工作了两次 Activity。
我能以某种方式 运行 它 1 次并通常将其设为静态以便它不附加到 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 应该是静态的,该怎么做?
当activity 进入onDestroy() 时退出应用程序时应取消AsyncTask。在 asynctask 的 doInBackground() 中,你应该检查 isCancelled() 并在情况下停止它。通过这种方式,您将始终只有 1 个 asyncTask 运行.
I also read that AsyncTask should be static, how to do that?
没有任何地方说 AsyncTask
应该是静态的。但确实如此,因为您已将 DataLoader
class 设为 SpecialtyListActivity
的内部 class,您可以通过将内部 DataLoader [=] 设为 slight performance edge 43=] 静态 class。只需添加静态修饰符:
static class DataLoader extends AsyncTask<String, Void, Void>
像这样对 class 定义使其静态。
您似乎认为 DataLoader
AsyncTask 触发两次的原因是因为它以某种方式 "attached" 到您的 activity。您可以参考 Activity lifecycle 了解更多信息。
Can I somehow run it 1 time and generally make it static so that it is not attached to Activity?
您可以将 AsyncTask 设为单独的 class 而不是内部 class 或 activity。 (但这并不能解决它触发两次的问题,因为它触发两次的原因不是因为它是 "attached to the activity")。使用以下模式使您的 AsyncTask 与 activity.
松耦合
从你的 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 方法中添加一个断点并调试应用程序。查看调用堆栈以找出它被调用两次的原因。
我正在使用从 AsyncTask 下载的列表。
一切都很好,只有当我退出应用程序并重新启动它时,列表增加了 2 倍 = AsyncTask 在我启动时工作了两次 Activity。 我能以某种方式 运行 它 1 次并通常将其设为静态以便它不附加到 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 应该是静态的,该怎么做?
当activity 进入onDestroy() 时退出应用程序时应取消AsyncTask。在 asynctask 的 doInBackground() 中,你应该检查 isCancelled() 并在情况下停止它。通过这种方式,您将始终只有 1 个 asyncTask 运行.
I also read that AsyncTask should be static, how to do that?
没有任何地方说 AsyncTask
应该是静态的。但确实如此,因为您已将 DataLoader
class 设为 SpecialtyListActivity
的内部 class,您可以通过将内部 DataLoader [=] 设为 slight performance edge 43=] 静态 class。只需添加静态修饰符:
static class DataLoader extends AsyncTask<String, Void, Void>
像这样对 class 定义使其静态。
您似乎认为 DataLoader
AsyncTask 触发两次的原因是因为它以某种方式 "attached" 到您的 activity。您可以参考 Activity lifecycle 了解更多信息。
Can I somehow run it 1 time and generally make it static so that it is not attached to Activity?
您可以将 AsyncTask 设为单独的 class 而不是内部 class 或 activity。 (但这并不能解决它触发两次的问题,因为它触发两次的原因不是因为它是 "attached to the activity")。使用以下模式使您的 AsyncTask 与 activity.
松耦合从你的 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 方法中添加一个断点并调试应用程序。查看调用堆栈以找出它被调用两次的原因。