0

在我的 Android 应用程序中,我有一个启动屏幕,然后是一个登录屏幕。用户登录后,他们会进入欢迎屏幕。我的应用程序在三星 Galaxy S3 上经常崩溃,所以我决定在 MAT 中查找。

我在欢迎屏幕上进行了堆转储,它显示了内存中的启动对象。我已经发布了下面的代码。什么可能导致此内存泄漏?

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);
        }
    }

}

这是线程类的代码:

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();
            }

        };
    };
}
4

1 回答 1

0

请使 Handler 成为静态类而不是匿名类。我认为 SplashActivity 必须由 android.os.Message 和 Handler 保存。处理程序保留对封闭 SplashActivity 的引用。如果不是问题,请在查询“select * from instanceof android.app.Activity”和“GC 路径”后粘贴快照。

于 2013-11-21T04:21:42.367 回答