我应该如何实现我的 AsyncTask 类?
Posted
技术标签:
【中文标题】我应该如何实现我的 AsyncTask 类?【英文标题】:How should I implement my AsyncTask class? 【发布时间】:2021-03-24 14:21:22 【问题描述】:我正在制作一个天气应用程序,我使用 AsyncTask 从 API 获取响应,然后设置 UI。经过简单处理后,我的代码如下所示:
class MainActivity : AppCompatActivity()
/*
SOME INSIGNIFICANT CODE HERE
*/
private fun setUI(currentWeather: Root)
tv_city.text = "$currentWeather.name, $currentWeather.sys.country"
/*
...
*/
inner class WeatherByNameTask: AsyncTask<String, Unit, Unit>()
override fun doInBackground(vararg p0: String?)
val city: String? = p0[0]
val call = weatherApi.getCurrentWeatherByCityName(city!!, API_KEY, "metric")
call.enqueue(object: Callback<Root>
override fun onResponse(call: Call<Root>, response: Response<Root>)
if (!response.isSuccessful)
Toast.makeText(this@MainActivity, "Code: $response.code()", Toast.LENGTH_LONG).show()
else
val currentWeather = response.body()
setUI(currentWeather!!)
override fun onFailure(call: Call<Root>, t: Throwable)
Toast.makeText(this@MainActivity, "Code: $t.message", Toast.LENGTH_LONG).show()
)
inner class WeatherByCoordTask: AsyncTask<Location, Unit, Unit>()
override fun doInBackground(vararg p0: Location?)
val lat: String = p0[0]?.latitude.toString()
val lon: String = p0[0]?.longitude.toString()
val call = weatherApi.getCurrentWeatherByCoordinates(lat, lon, API_KEY, "metric")
call.enqueue(object: Callback<Root>
@SuppressLint("SetTextI18n")
override fun onResponse(call: Call<Root>, response: Response<Root>)
if (!response.isSuccessful)
Toast.makeText(this@MainActivity, "Code: $response.code()", Toast.LENGTH_LONG).show()
else
val currentWeather = response.body()
setUI(currentWeather!!)
override fun onFailure(call: Call<Root>, t: Throwable)
Toast.makeText(this@MainActivity, "Code: $t.message", Toast.LENGTH_LONG).show()
)
它有效,但我收到警告:
这个 AsyncTask 类应该是静态的,否则可能会发生泄漏
我想以正确的方式制作它。我试图在 MainActivity 类之外实现它,将 Context 作为参数传递,但是 setUI 函数呢?我想公开它是个坏主意。
【问题讨论】:
既然你已经在使用 Kotlin,你应该迁移到包括远程接口在内的协程,因为 Retrofit 也支持协程。 【参考方案1】:这个 AsyncTask 类应该是静态的,否则可能会发生泄漏
在MainActivity
中,有2 个AsyncTask
类带有inner
修饰符,这意味着内部类将保持对外部类的强引用。警告告诉您,当AsyncTask
在后台执行其工作时,如果用户离开当前活动(按返回键或调用finish()
方法),那么活动实例将被泄露,因为AsyncTask
仍然保留强烈引用它。
解决方案
使用WeakReference 让AsyncTask
保持对MainActivity
的弱引用。
class WeatherByNameTask (activity: MainActivity): AsyncTask<String, Unit, Unit>()
private val activityRef = WeakReference<MainActivity>(activity)
override fun doInBackground(vararg p0: String?)
val city: String? = p0[0]
val call = weatherApi.getCurrentWeatherByCityName(city!!, API_KEY, "metric")
call.enqueue(object: Callback<Root>
override fun onResponse(call: Call<Root>, response: Response<Root>)
if (!response.isSuccessful)
activityRef.get()?.let
Toast.makeText(it, "Code: $response.code()", Toast.LENGTH_LONG).show()
else
val currentWeather = response.body()
activityRef.get()?.setUI(currentWeather!!)
override fun onFailure(call: Call<Root>, t: Throwable)
activityRef.get().let
Toast.makeText(it, "Code: $t.message", Toast.LENGTH_LONG).show()
)
class WeatherByCoordTask (activity: MainActivity): AsyncTask<Location, Unit, Unit>()
private val activityRef = WeakReference<MainActivity>(activity)
override fun doInBackground(vararg p0: Location?)
val lat: String = p0[0]?.latitude.toString()
val lon: String = p0[0]?.longitude.toString()
val call = weatherApi.getCurrentWeatherByCoordinates(lat, lon, API_KEY, "metric")
call.enqueue(object: Callback<Root>
@SuppressLint("SetTextI18n")
override fun onResponse(call: Call<Root>, response: Response<Root>)
if (!response.isSuccessful)
activityRef.get()?.let
Toast.makeText(it, "Code: $response.code()", Toast.LENGTH_LONG).show()
else
val currentWeather = response.body()
activityRef.get()?.setUI(currentWeather!!)
override fun onFailure(call: Call<Root>, t: Throwable)
activityRef.get().let
Toast.makeText(it, "Code: $t.message", Toast.LENGTH_LONG).show()
)
从活动中使用
val weatherByNameTask = WeatherByNameTask(this)
val weatherByCoordTask = WeatherByCoordTask(this)
【讨论】:
为了让它工作,我需要公开“setUI()”方法。公开这些方法是一种好习惯吗? 您可以控制活动并知道在哪里以正确的方式调用公共方法,因此可以这样做。【参考方案2】:以下是AsyncTask
的制作方法:
private class AsyncTaskGetPlaces extends AsyncTask<Void, Void, AsyncTaskResult<Object>>
@Override
protected void onPreExecute()
super.onPreExecute();
@Override
protected AsyncTaskResult<Object> doInBackground(Void... params)
try
LibHttp libHttp = new LibHttp();
String res = libHttp.listBusiness("21","test@ns.com");
return new AsyncTaskResult<Object>(res);
catch (Exception e)
e.printStackTrace();
return new AsyncTaskResult<Object>(e);
@Override
protected void onPostExecute(AsyncTaskResult<Object> result)
if(result.getError()!= null)
showOKAlertMsg("App",getResources().getString(R.string.txt_data_not_found), false);
else
String res = result.getResult().toString();
try
JSONObject resObj = new JSONObject(res);
if(resObj.getString("status_code").equals("1"))
//parse
// Do your task here
catch (JSONException e)
e.printStackTrace();
showOKAlertMsg("",getResources().getString(R.string.txt_internal_server_error), false);
AsyncTaskResult 在哪里
public class AsyncTaskResult<T>
private T result;
private Exception error;
public T getResult()
return result;
public Exception getError()
return error;
public AsyncTaskResult(T result)
this.result = result;
public AsyncTaskResult(Exception error)
this.error = error;
【讨论】:
以上是关于我应该如何实现我的 AsyncTask 类?的主要内容,如果未能解决你的问题,请参考以下文章
处理 AsyncTask 警告类应该是静态的,否则可能会发生泄漏
Android:如何将参数传递给AsyncTask的onPreExecute()?