我应该如何实现我的 AsyncTask class?
How should I implement my AsyncTask class?
我正在制作一个天气应用程序,我在其中使用 AsyncTask 从 API 获取响应,然后设置 UI。在 simplyfing 之后,现在我的代码看起来像这样:
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()
}
})
}
}
}
有效,但我收到警告:
This AsyncTask class should be static or leaks might occur
我想以正确的方式制作它。我试图在 MainActivity class 之外实现它,将 Context 作为参数传递,但是 setUI 函数呢?我想让它成为 public 是个坏主意。
以下是制作方法 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;
}
}
This AsyncTask class should be static or leaks might occur
在MainActivity
中,有2个AsyncTask
class带有inner
修饰符,也就是说里面的class会保持强引用外部 class。该警告告诉您,当 AsyncTask
在后台执行其工作时,如果用户离开当前 activity(按返回键或调用 finish()
方法),则 activity 实例将被泄露,因为 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()
}
}
})
}
}
使用来自 activity
val weatherByNameTask = WeatherByNameTask(this)
val weatherByCoordTask = WeatherByCoordTask(this)
我正在制作一个天气应用程序,我在其中使用 AsyncTask 从 API 获取响应,然后设置 UI。在 simplyfing 之后,现在我的代码看起来像这样:
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()
}
})
}
}
}
有效,但我收到警告:
This AsyncTask class should be static or leaks might occur
我想以正确的方式制作它。我试图在 MainActivity class 之外实现它,将 Context 作为参数传递,但是 setUI 函数呢?我想让它成为 public 是个坏主意。
以下是制作方法 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;
}
}
This AsyncTask class should be static or leaks might occur
在MainActivity
中,有2个AsyncTask
class带有inner
修饰符,也就是说里面的class会保持强引用外部 class。该警告告诉您,当 AsyncTask
在后台执行其工作时,如果用户离开当前 activity(按返回键或调用 finish()
方法),则 activity 实例将被泄露,因为 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()
}
}
})
}
}
使用来自 activity
val weatherByNameTask = WeatherByNameTask(this)
val weatherByCoordTask = WeatherByCoordTask(this)