2017-10-30 13 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); 
    } 
} 

지금 좋아 내가 자신에 응답 리스너를 이동 내가 온라인으로 읽을 때 뭔가를 기반으로하는 별도의 수업을 통해 문제가 해결 될 것이라고 생각합니다. eak 그러나 그것을하지 않았다. 보류중인 모든 요청을 취소하는 코드를 추가했습니다. onDestroy() 요청의 태그를 기반으로했지만 여전히 메모리 누수가있었습니다.

이것은 내 스플래시 활동이며 여기 누수가 작기 때문에 finish()를 호출했기 때문에 느낌이 들지만 요청이 성공적으로 완료된 후에 호출하기 때문에 이해가되지 않습니다. 내 모든 다른 활동은 비슷한 코드를 가지고 있지만 11mb만큼 많은 메모리를 누출합니다.

제 질문은 발리 라이브러리로 작업 한 사람이 있습니까? 어떻게 사용하고 메모리 누수를 피할 수 있습니까?

이 버전을 사용 :

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

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

+0

나는 이것이 즉시 도움이되지 않는다는 것을 알고 있지만, Volley를 끄는 것이 좋습니다.역사적으로 문서화되지 않았습니다. 다른 사람이 같은 라이브러리를 만든 경우 아무도 라이브러리를 사용하지 않습니다. RxJava는 HTTP 요청뿐만 아니라 모든 비동기 데이터에 대해 안드로이드에 대한 더 나은 추상성을 입증했으며, 더 많은 메모리 누수가 없도록 모든 데이터에서 탈퇴 할 수있는 기능을 제공합니다. 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) 요청 중에 누출을 소개합니다. 요청이 진행되는 동안 Activity가 가비지 수집 될 수 없음을 의미합니다. 이것은 실제로 발리의 잘못이 아니라 오히려 자연스러운 방법입니다.

당신은 귀하의 경우 옵션이 몇 가지있다 :

1) 당신의 청취자에 WeakReference<Context>, 문맥에 대신 강한 참조를 전달합니다. 이 방법을 사용하면 누수가 발생하지 않으므로 액세스하려고 할 때이 참조 된 Context가 아직 null이 아닌지 확인해야합니다. 하지만 차라리 두 번째 옵션을 선택하겠습니다.

2) Activity의 onDestroy()이 호출되면 수신자의 mContext에서 null으로 설정하십시오. 또한 리스너에서 Context를 사용하여 무언가를하려고 할 때 null 확인을 수행하십시오. 따라서 Activity가 파괴되자 마자 다른 강력한 참조가 제거되어 GC가 정상적으로 수집 할 수있게됩니다.

+0

시간 내 주셔서 감사합니다. 시도해보고 도움이되는지 확인해보십시오. – user3718908

+0

하나의 질문이지만, 변수에 컨텍스트를 저장하지 않고 대신에'MainActivity.this'를 사용하면 어떻게됩니까? 왜냐하면 나는'MainActivtiy.this'를 null로 설정할 수 없기 때문입니다. 용서 해줘. 나는 안드로이드 개발자에게 아주 새로운 사람이다. – user3718908

+0

@ user3718908 내부 (또는 내부 익명) 클래스에 항상 암시 적 참조가 있으므로 Context에 대한 참조를 저장하는 것과 사실상 동일합니다. 그러지 마라. – Dimezis