【问题标题】:AsyncTask and ContextsAsyncTask 和上下文
【发布时间】:2010-12-27 03:08:25
【问题描述】:

所以我正在使用带有 AsyncTask 类的 Android 开发我的第一个多线程应用程序。我正在尝试使用它在第二个线程中启动地理编码器,然后使用 onPostExecute 更新 UI,但我一直遇到正确上下文的问题。

在主线程上使用 Contexts 时我有点步履蹒跚,但我不确定 Context 是什么或如何在后台线程上使用它,而且我还没有找到任何好的例子。有什么帮助吗?这是我正在尝试做的摘录:

public class GeoCode extends AsyncTask<GeoThread, Void, GeoThread> {
  @Override
  protected GeoThread doInBackground(GeoThread... i) {
    List<Address> addresses = null;
    Geocoder geoCode = null; 
    geoCode = new Geocoder(null); //Expects at minimum Geocoder(Context context);
    addresses = geoCode.getFromLocation(GoldenHour.lat, GoldenHour.lng, 1);
  }
}

由于上下文不正确,它一直在第六行失败。

【问题讨论】:

    标签: java android android-asynctask android-context


    【解决方案1】:

    @Eugene van der Merwe

    以下代码对我有用:) -->

    public class ApplicationLauncher extends Activity {
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.applicationlauncher);
    
        LoadApplication loadApplication = new LoadApplication(this);
        loadApplication.execute(null);
    }
    
    private class LoadApplication extends AsyncTask {
    
        Context context;
        ProgressDialog waitSpinner;
        ConfigurationContainer configuration = ConfigurationContainer.getInstance();
    
        public LoadApplication(Context context) {
            this.context = context;
            waitSpinner = new ProgressDialog(this.context);
        }
    
        @Override
        protected Object doInBackground(Object... args) {
            publishProgress(null);
            //Parsing some stuff - not relevant
            configuration.initialize(context);
            return null;
        }
    
        @Override
        protected void onProgressUpdate(Object... values) {
            super.onProgressUpdate(values);
            // Only purpose of this method is to show our wait spinner, we dont
            // (and can't) show detailed progress updates
            waitSpinner = ProgressDialog.show(context, "Please Wait ...", "Initializing the application ...", true);
        }
    
        @Override
        protected void onPostExecute(Object result) {
            super.onPostExecute(result);
            waitSpinner.cancel();
        }
    }
    }
    

    干杯,

    Ready4Android

    【讨论】:

    • 此代码存在上下文泄漏。您将 Activity 保存为 AsyncTask 中的 Context,这很好,除非用户旋转设备,这会重新创建 Activity。 AsyncTask 继续运行,并引用您的 Activity 的旧副本,现在您在内存中有两个 Activity 副本。
    • @ChristopherPerry:将 Context 作为 WeakReference 保留在 AsyncTask 中会解决泄漏问题吗?还是有更好的方法来安全地调整上述解决方案?
    • 或者仅仅传递应用程序上下文就足够安全了?
    • @gcl1,WeakReference 将修复泄漏。不幸的是,轮换将导致您失去您的参考,因为它现在可以进行垃圾收集,并且 Android 非常激进的垃圾收集例程将期望您的应用程序呈现撤消凯撒的凯撒。我会避免像瘟疫一样将任何上下文传递给 AsyncTask。相反,您可以在 AsyncTask 的执行调用之前在 Activity 中启动进度对话框,然后在 Asynctask 返回时将其关闭。一个更好的解决方案(在这种情况下)是使用Otto
    • 无论@ChristopherPerry 注释如何,这段代码都有内存泄漏:因为AsyncTask 是一个内部类(不是静态的),它隐式引用了封闭的Activity。即使您根本没有通过Context,这也会造成内存泄漏。因此,WeakReference 不会解决问题!
    【解决方案2】:

    上下文是一个提供应用程序运行环境访问权限的对象。在大多数情况下,当您需要从 Android 环境中获取对象时,例如资源、视图、基础设施类等——您需要掌握 Context。

    在 Activity 类中获取 Context 实例非常简单——Activity 本身是 Context 的子类,所以你需要做的就是使用 'this' 关键字指向你当前的上下文.

    无论您创建可能需要 Context 的代码 - 您都应该注意从您的父 Activity 传递 Context 对象。在您的示例中,您可以添加接受 Context 作为输入参数的显式构造函数。

    【讨论】:

      【解决方案3】:

      我做了更多研究,有人建议将其传递给线程(不知道为什么我没有想到这一点)。我通过一个参数将它传递给 Geocoder 线程,就这样,它起作用了。

      【讨论】:

      • 请您发布一个您所做的示例并更新此问题的正确答案吗?
      • @Eugene van der Merwe 看到我的回答,我认为这是他最终所做的一个例子。
      【解决方案4】:

      从 AsyncTask 更新 UI 的问题是您需要 current 活动上下文。但是每次方向变化都会破坏并重新创建上下文。

      这是您问题的一个很好的答案:Android AsyncTask context behavior

      【讨论】:

        【解决方案5】:

        如果看起来您没有使用参数。您可以使用它来传递 Conetxt。

        public class GeoCode extends AsyncTask<Context, Void, GeoThread> {
          @Override
          protected GeoThread doInBackground(Context... params) {
            List<Address> addresses = null;
            Geocoder geoCode = null; 
            geoCode = new Geocoder(params[0]); //Expects at minimum Geocoder(Context context);
            addresses = geoCode.getFromLocation(GoldenHour.lat, GoldenHour.lng, 1);
          }
        }
        

        然后在您的活动中:

        GeoCode myGeoCode = new GeoCode();
        myGeoCode.execute(this);
        

        【讨论】:

          猜你喜欢
          • 2011-11-29
          • 1970-01-01
          • 2014-02-11
          • 2011-01-08
          • 2011-05-23
          • 2013-05-31
          • 1970-01-01
          • 2016-11-22
          • 1970-01-01
          相关资源
          最近更新 更多