【问题标题】:Advantage over using inner or nested class in AsynTask在 AsyncTask 中使用内部或嵌套类的优势
【发布时间】:2018-04-22 02:21:56
【问题描述】:

无论是在 Android 还是 Java 中,当我们调用 AsyncTaskSwingWorker 时,它可以使用内部类或嵌套类。我最担心 Android 设备中的内存泄漏问题。如果您采用内部类,则会自动传递活动引用。通过采用嵌套类,您必须手动传递活动引用,因此内部/嵌套基本上做同样的工作。

我遇到的一个问题是活动终止,当AsyncTask 结束时,它会破坏应用程序。我知道并且使用过无头片段,但这里我的问题是关于在 Android 和 Java 中使用内部/嵌套类,你推荐哪一个?例如,我在JFrame 中执行这个任务,当然我想使用一个特定的类来执行特定的任务(每个任务一个类),而不是放置内联代码。

new SwingWorker<Void, Void>() {
        private Exception exception = null;

        @Override
        protected Void doInBackground() throws Exception {
            try {
                callback.login();
            } catch(SQLException e) {
                exception = e;
            }

            return null;                
        }

        @Override
        protected void done() {
            if(exception != null) {
                // show fail
            } else {
                update();
            }
        }
    }.execute();
}

【问题讨论】:

    标签: java android multithreading android-asynctask swingworker


    【解决方案1】:

    如果类没有父类没有身份,我会将一个类设为内部类,并将内部类标记为静态以避免您提到的问题。

    在 Android 中,您可以传递父 Activity 的 Weak reference 以避免泄漏并确保在 onStop 中取消 AsyncTask。一般尽量避免使用AsyncTask。将它用于琐碎的用例。对于主要用例,请依赖 Services/IntentService。

    从程序员的角度来看,创建一个内部类并让该类访问父类的数据非常方便。但这会给编译器带来一些工作量。内部编译器生成 getter 方法并在生成 .class 文件之前将其添加到您的代码中。这不是一个好主意,因为它会影响父类的封装

    【讨论】:

      【解决方案2】:

      在 Android 中,您可以通过实现 interface 来处理这种情况。让我们有一个interface,如下所示。

      public interface HttpResponseListener {
          void httpResponseReceiver(String result);
      }
      

      现在从您的Activity 通过AsyncTask 调用登录函数,只需将接口从活动类传递给AsyncTask。请记住,您的 AsyncTask 也应该具有该侦听器的实例变量。所以整体实现应该如下所示。

      public abstract class HttpRequestAsyncTask extends AsyncTask<Void, Void, String> {
      
          public HttpResponseListener mHttpResponseListener;
          private final Context mContext;
      
          HttpRequestAsyncTask(Context mContext, HttpResponseListener listener) {
              this.mContext = mContext;
              this.mHttpResponseListener = listener;
          }
      
          @Override
          protected String doInBackground(Void... params) {
              String result = null;
      
              try {
                  result = login(mContext); // use the context if necessary
              } catch (Exception e) {
                  e.printStackTrace();
              }
      
              return result;
          }
      
          @Override
          protected void onPostExecute(final String result) {
              mHttpResponseListener.httpResponseReceiver(result);
          }
      
          @Override
          protected void onCancelled() {
              mHttpResponseListener.httpResponseReceiver(null);
          }
      }
      

      现在您需要在调用 Activity 时实现 httpResponseReceiver 函数。所以示例活动应该是这样的。

      public class YourActivity extends AppCompatActivity implements HttpResponseListener {
          // ... Other code and overriden functions 
      
          public void callAsyncTaskForLogin() {
              // Pass the listener here
              HttpRequestAsyncTask loginTask = new HttpRequestGetAsyncTask(
                  YourActivity.this, this);
                  loginTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
          }
      
          @Override
          public void httpResponseReceiver(String result) {
              // Get the response callback here
              // Do your changes in UI elements here. 
          }
      }
      

      这是避免潜在内存泄漏的方法,因为您正在使用 Activity 中的 Activity 上下文更改 UI 元素。当后台AsyncTask完成后,它会将职责传递给回调函数,并且不持有上下文的引用。

      如果应用程序完成,AsyncTask 将执行并将引用传递给调用活动,在这种情况下,活动将无法接收。但是,这也不会产生任何内存泄漏。

      【讨论】:

        猜你喜欢
        • 2013-05-01
        • 1970-01-01
        • 2020-01-29
        • 1970-01-01
        • 1970-01-01
        • 2014-12-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多