2012-08-16 5 views
0

내 Android 앱에 스플래시 화면이 있으며 로그인 화면이 표시됩니다. 사용자가 로그인하면 시작 화면에 나타납니다. 삼성 갤럭시 S3에 내 응용 프로그램이 많이 충돌하므로 MAT에서이 기능을 살펴보기로했습니다. 시작 화면에서 힙 덤프를 가져 와서 스플래시 개체를 메모리에 표시하고 있습니다. 나는 아래의 코드를 게시 한 누군가가 나에게이 메모리 누수 원인을 알려 수 있다면, 나는 대단히 감사합니다 :Android Memory Leak - 내부 클래스

import java.io.InputStream; 
import java.net.HttpURLConnection; 
import java.net.URL; 

import android.app.AlertDialog; 
import android.content.Context; 
import android.os.Handler; 

public class ConnectionCheckThread extends Thread{ 

    private static final String TAG = ConnectionCheckThread.class.getSimpleName(); 
    private ConnectionCallBack callback; 
    //private HttpURLConnection http = null; 
    //private InputStream is; 
    //private boolean isFirstTime = true; 
    public static int CONNECTION_TIMEOUT = 200; 
    public static int UNKNOWN_HOST = 201; 
    public static int UNKNOWN_ERROR = 202; 
    public static int CONNECTION_SUCCESS = 203; 
    public static int CONNECTION_FAILURE = 204; 
// private int returnCode; 
// private int retryCount = 0; 
    Context context; 

    public ConnectionCheckThread(Context con){ 
     this.context = con; 
     this.callback = (ConnectionCallBack)con; 
    } 


    public void run(){ 
     HttpURLConnection http = null; 
     boolean isFirstTime = true; 
     String urlString = "http://www.google.com/"; 
     int returnCode = 0; 
     int retryCount = 0; 

     do{ 

      try { 
       URL urls = new URL(urlString); 

       http = (HttpURLConnection)urls.openConnection(); 

       int responsecode = http.getResponseCode(); 
       System.out.println("responsecode = "+responsecode); 

       if(isFirstTime){ 
        http.setConnectTimeout(30000); 
       }else{ 
        http.setConnectTimeout(15000); 
       } 

       http.connect(); 
       InputStream is = http.getInputStream(); 

       returnCode = CONNECTION_SUCCESS; 
      } catch (java.net.SocketException ex) { 
       ex.printStackTrace(); 
       Utils.log(TAG, "caught SocketException[" + ex.getMessage() + "]"); 
       returnCode = CONNECTION_TIMEOUT; 
      } catch (java.net.SocketTimeoutException ex) { 
       ex.printStackTrace(); 
       Utils.log(TAG, "caught SocketTimeoutException[" + ex.getMessage() + "]"); 
       returnCode = CONNECTION_TIMEOUT; 
      } catch (java.net.UnknownHostException ex) { 
       ex.printStackTrace(); 
       Utils.log(TAG, "caught UnknownHostException[" + ex.getMessage() + "]"); 
       returnCode = UNKNOWN_HOST; 
      } catch (Exception e) { 
       e.printStackTrace(); 
       Utils.log(TAG, "Exception in WebRequest Thread :" + e.getMessage()); 
       returnCode = UNKNOWN_ERROR; 
      } finally { 
       try { 
        if (http != null) { 
         http.disconnect(); 
         http = null; 
        } 
       } catch (Exception e) { 
        e.printStackTrace(); 
       } 

       callback.onReceivedConnection(returnCode); 
       if(retryCount == 0){ 
        isFirstTime = false; 
       } 
       retryCount++; 
      } 
     }while(retryCount <= 1 && returnCode != CONNECTION_SUCCESS); 
    } 

    Handler handler2 = new Handler(){ 
     public void handleMessage(android.os.Message msg) { 
      if(msg.what == CONNECTION_FAILURE){ 
       AlertDialog.Builder alert = new AlertDialog.Builder(context); 
       alert.setTitle(context.getResources().getString(R.string.login_no_network_title)); 
       alert.setMessage(context.getResources().getString(R.string.login_no_network_content)); 
       alert.show(); 
      } 

     }; 
    }; 
} 

I : 여기

import java.util.ArrayList; 
import java.util.List; 
import java.util.Timer; 
import java.util.TimerTask; 

import android.app.AlertDialog; 
import android.content.DialogInterface; 
import android.content.Intent; 
import android.hardware.Camera; 
import android.os.Bundle; 
import android.os.Handler; 
import android.os.Message; 
import android.util.Log; 
import android.view.KeyEvent; 
import android.view.View; 
import android.widget.TextView; 

public class SplashActivity extends CoreActivity implements ConnectionCallBack{ 

    private static final String TAG = SplashActivity.class.getSimpleName(); 
    private static final int LOGIN_SCREEN = 0; 
    protected static final String SPL = SplashActivity.class.getSimpleName(); 
    private int SHOW_MESSAGE = 1; 
    private Timer timer; 
    private TextView connectionNotificationTV; 
    private int notificationCount = 0; 
    private Handler handler; 
    TimerTask timerTask; 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.splashscreen); 
     Globals.appContext = getApplicationContext(); 

     connectionNotificationTV = (TextView) findViewById(R.id.splash_screen_connection_notification_TV); 

     handler = new Handler(){ 
      public void handleMessage(Message msg) { 
       if(msg.what == SHOW_MESSAGE){ 
        if(notificationCount == 0){ 
         connectionNotificationTV.setVisibility(View.VISIBLE); 
        }else if(notificationCount == 1){ 
         confirmationDialog(); 
        } 
        notificationCount++; 
       }else if(msg.what == LOGIN_SCREEN){ 
        loadNext(LOGIN_SCREEN); 
       } 
      }; 
     }; 
     LocationDisplay location = new LocationDisplay(getApplicationContext()); 

     ConnectionCheckThread newConnectionThread = new ConnectionCheckThread(this); 
     newConnectionThread.start(); 

     timer = new Timer(); 
     timer.schedule(new TimerTask() { 

      @Override 
      public void run() { 
       if(notificationCount == 0){ 
        handler.sendEmptyMessage(SHOW_MESSAGE); 
       } 
      } 
     }, 30000); 

    } 

    @Override 
    protected void onDestroy() { 
     // TODO Auto-generated method stub 
     super.onDestroy(); 
     Utils.unbindDrawables(findViewById(R.id.root)); 
    } 

    private void setScreenDimension(){ 
     int screenHeight = getWindowManager().getDefaultDisplay().getHeight(); 
     int screenWidth = getWindowManager().getDefaultDisplay().getWidth(); 
     GeneralSettings.getInstance().setScreenHeight(screenHeight); 
     GeneralSettings.getInstance().setScreenWidth(screenWidth); 
    } 

    @Override 
    public boolean onKeyDown(int keyCode, KeyEvent event) { 
     if(keyCode == KeyEvent.KEYCODE_BACK){ 
      System.exit(0); 
      return true; 
     } 
     return super.onKeyDown(keyCode, event); 
    } 

    public void confirmationDialog() { 

     AlertDialog.Builder builder = new AlertDialog.Builder(this); 
     builder.setTitle(R.string.connection_error_title); 
     builder.setMessage(R.string.connection_error_message); 

     builder.setPositiveButton(R.string.connection_error_close_btn, new DialogInterface.OnClickListener() { 

      public void onClick(DialogInterface dialog, int which) { 
       System.exit(0); 
      } 
     }); 

     builder.setCancelable(false); 
     builder.show(); 
    } 

    @Override 
    public void loadNext(int code) { 
     if(code == LOGIN_SCREEN){ 
      Intent intent = new Intent(SplashActivity.this,LoginActivity.class); 
      startActivity(intent); 
      finish(); 
     } 
    } 

    @Override 
    public void loadPrev() { 
    } 

    @Override 
    public void onReceivedConnection(int returnCode) { 
     if(returnCode == ConnectionCheckThread.CONNECTION_TIMEOUT || 
      returnCode == ConnectionCheckThread.UNKNOWN_HOST || 
      returnCode == ConnectionCheckThread.UNKNOWN_ERROR){ 
      handler.sendEmptyMessage(SHOW_MESSAGE); 
     }else if(returnCode == ConnectionCheckThread.CONNECTION_SUCCESS){ 
      handler.sendEmptyMessage(LOGIN_SCREEN); 
     } 
    } 

} 

스레드 클래스의 코드를 이 문제를 해결할 수있는 도움을 주시면 감사하겠습니다. 사전에

감사합니다.

+0

로그를 넣을 수도 있습니다 –

+0

System.exit (0)이 필요합니까? finish()를 사용하지 않는 이유는 무엇입니까? 스레드에 컨텍스트 변수를 저장하고 있기 때문에 활동이 누출되었을 수 있습니다. 실행하자마자 스레드의 문맥을 null로 만들면 시도 할 수 있습니까 – nandeesh

+0

Sunny - logcat 또는 MAT 출력을 볼 필요가 있습니까? – user881148

답변

0

처리기를 익명 클래스 대신 정적 클래스로 설정하십시오. SplashActivity는 android.os.Message와 Handler에 의해 보관되어야한다고 생각합니다. Handler는 둘러싸는 SplashActivity에 대한 참조를 유지합니다. 문제가 아닌 경우 'select * from instanceof android.app.Activity'및 'path to GC'쿼리 후 스냅 샷을 붙여 넣으십시오.