2017-10-30 26 views
6

私はGoogleのボレーライブラリを使用しています。私は弱点のために自分のアプリでメモリリークを戦っています。私は多くの研究を行い、すでに多くの研究をしていますが、今は何をすべきかわかりません。これはサンプルコードです:Android Volley Memory Leaks

SplashActivity.java

public class SplashActivity extends AppCompatActivity { 

    Context mContext; 
    AuthRequest mAuthRequest; 
    GetTokenOnSuccessListener mGetTokenOnSuccessListener; 
    GetTokenOnErrorListener mGetTokenOnErrorListener; 
    private ConfigTable mConfigTable; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     initialiseViewsAndComponents(); 
    } 

    @Override 
    protected void onStart() { 
     super.onStart(); 
     getAuthToken(); 
    } 

    private void initialiseViewsAndComponents() { 
     mContext = SplashActivity.this; 
     mAuthRequest = new AuthRequest(mContext); 
     mGetTokenOnSuccessListener = new GetTokenOnSuccessListener(mContext); 
     mGetTokenOnErrorListener = new GetTokenOnErrorListener(mContext); 
     mConfigTable = new ConfigTable(mContext); 
    } 

    private void getAuthToken() { 
     if (!mConfigTable.get("INITIALISED").equals("")) { 
      mAuthRequest.guest(mGetTokenOnSuccessListener, mGetTokenOnErrorListener); 
     } else { 
      Intent mainIntent = new Intent(mContext, MainActivity.class); 
      startActivity(mainIntent); 
     } 
    } 

} 

GetTokenOnSuccessListener.java

public class GetTokenOnSuccessListener implements Response.Listener<JSONObject> { 

    //private Activity mActivity; 
    private Context mContext; 
    private ConfigTable mConfigTable; 
    private int mSuccess = 0; 
    private String mMessage = ""; 

    public GetTokenOnSuccessListener(Context context) { 
     //this.mActivity = context; 
     this.mContext = context; 
     this.mConfigTable = new ConfigTable(this.mContext); 
    } 

    @Override 
    public void onResponse(JSONObject response) { 
     try { 
      mSuccess = Integer.parseInt(response.get("success").toString()); 
      mMessage = response.get("message").toString(); 

      if (mSuccess == 1) { 
       mConfigTable.setAuthToken(response.get("message").toString()); 
       Intent mainIntent = new Intent(mContext, MainActivity.class); 
       mContext.startActivity(mainIntent); 
       ((SplashActivity) mContext).finish(); 
      } else { 
       Toast.makeText(mContext, "Lol access denied, could not retrieve token from server.", Toast.LENGTH_SHORT).show(); 
      } 


     } catch (JSONException e) { 
      e.printStackTrace(); 
      Toast.makeText(mContext, "Lol access denied, could not retrieve token from server.", Toast.LENGTH_SHORT).show(); 
     } 
    } 
} 

GetTokenOnErrorListener.java

public class GetTokenOnErrorListener implements Response.ErrorListener { 

    private Context mContext; 

    public GetTokenOnErrorListener(Context context) { 
     this.mContext = context; 
    } 

    @Override 
    public void onErrorResponse(VolleyError error) { 
     Utils.showNetworkResponse(mContext, error); 
    } 
} 

今わかりました、私は自分自身に応答リスナーを移動私はオンラインでそれを解決すると思った何かに基づいて別のクラスそれはできませんでした。すべての保留中のリクエストをキャンセルするコードを追加しましたonDestroy()リクエストのタグに基づいていますが、まだメモリリークがありました。

これはちょうど私のスプラッシュアクティビティであり、ここでのリークは小さいですが、私はfinish()を呼び出すためだと感じていますが、要求が正常に完了した後に呼び出すので、私の他のすべての活動は同様のコードを持っていますが、11mbのように多くのメモリをリークします。

私の質問は、誰もがボレーライブラリで働いていますか?どのように使用してメモリリークを回避するのですか?

compile 'com.android.volley:volley:1.0.0' 
+0

https://github.com/google/volley/issues/81 –

+0

これはすぐには役立ちませんが、私はVolleyをオフに切り替えることを強くお勧めします。歴史的には文書化されていません。他の人が同じライブラリを作った場合、誰もそれを使うことはありません。 RxJavaは、HTTP要求だけでなく、すべての非同期データに対して、Android上での優れた抽象化であることが証明されており、メモリリークがなくなるようにデータのストリームから脱退する機能を提供します。 RxJava + RetrofitはVolleyと比較してはるかに良いフィット感です。移行を強くお勧めします。 – spierce7

+0

@ spierce7定期的なリクエストでもコアの原則を理解できない場合、Rxをどのように使用しますか?このリークは、使用するライブラリに関係なく回避できます。 – Dimezis

答えて

-2

あなたは、常に新しいアクティビティを作成しています。代わりにこれを試してください。ここではそれについての詳細を読む:https://developer.android.com/reference/android/content/Intent.html#FLAG_ACTIVITY_CLEAR_TOP

Intent mainIntent = new Intent(mContext, MainActivity.class); 
mainIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); 
mContext.startActivity(mainIntent); 
+2

MainActivityはスプラッシュ画面から一度しか表示されないので、これは何の違いもありません。また、メモリリークを作成するコードがない限り、同じアクティビティを複数回起動してもメモリリークは発生しません。 –

3

それはちょうど、「自分の別のクラスに応じてリスナーを移動」するのに十分ではありません。 リスナーは、アクティビティ(mContext)への強い参照を持ち、リクエスト中にリークが発生します。これは、リクエストが進行中の間に、アクティビティがガベージコレクションできないことを意味します。 それは本当にボレーのせいではなく、むしろ自然な方法です。

あなたはあなたのケースのオプションのカップルがあります

1)コンテキストへの強い参照の代わりに、あなたのリスナーにWeakReference<Context>を渡します。この方法では、リークを導入しないで、アクセスしようとすると、この参照されたContextがまだヌルでないかどうかをチェックする必要があります。しかし、私はむしろ第2の選択肢に行くだろう。

2)ActivityのonDestroy()が呼び出されたときに、リスナーのmContextnullと設定します。また、リスナーでコンテキストを使用して何かをしようとしているときにも、ヌルチェックを実行します。アクティビティが破棄されるとすぐに、他の強力な参照が削除され、GCが正常に収集できるようになります。

+0

あなたの時間をありがとう、それを試して、それが役立つかどうかを確認します。 – user3718908

+0

私は変数にコンテキストを格納せず、その代わりに 'MainActivity.this'を使って、私はそれについて何をしますか?私は 'MainActivtiy.this'をnullに設定することはできません。私を許して、私はアンドロイドの開発者にはかなり新しいです。 – user3718908

+0

@ user3718908内部(または内部匿名)クラスには常に暗黙の参照があるため、これはContextへの参照を格納することと事実上同じです。そうしないでください – Dimezis