【问题标题】:How should I implement my AsyncTask class?我应该如何实现我的 AsyncTask 类?
【发布时间】: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 也支持协程。

标签: android kotlin android-asynctask


【解决方案1】:

这个 AsyncTask 类应该是静态的,否则可能会发生泄漏

MainActivity 中,有2 个AsyncTask 类带有inner 修饰符,这意味着内部类将保持对外部类的强引用。警告告诉您,当AsyncTask 在后台执行其工作时,如果用户离开当前活动(按返回键或调用finish() 方法),那么活动实例将被泄露,因为AsyncTask 仍然保留强烈引用它。

解决方案

使用WeakReferenceAsyncTask 保持对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;
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-17
    • 1970-01-01
    • 2016-07-19
    • 1970-01-01
    • 1970-01-01
    • 2011-06-01
    相关资源
    最近更新 更多