Android - 无法确定锁屏类型应用程序中的内存泄漏

时间:2014-06-21 16:18:48

标签: android android-intent memory-leaks android-event android-bitmap

我觉得我的问题与this非常相似,但并不完全相同。

我有一个应用程序,其中活动在接收事件时加载图像。用户在图像上滑动,活动结束。下次用户关闭屏幕并重新打开时,会触发相同的事件,并再次加载活动。

这很好用,但每次活动加载时,都会增加内存(4MB到8MB到11MB到14MB等)。它高达30MB左右,任何一个应用程序崩溃和重启或手机开始变得迟钝等。

我尝试过很多东西: - 清算&设置图像相关变量&使用后查看 - 使用reuseBitmap

但它没有帮助。

有人可以建议我缺少什么吗?

此外,finish()似乎没有完成我的活动。它保持在后台。如果我长按HOME,我可以看到我在那里的活动,我不想发生。有没有办法解决这个问题?这是我问题的原因吗?

我的启动活动(运行一次)启动服务:

    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_settings); 
    startService(new Intent(this.getApplicationContext(),myService.class));
}

我的服务启动了活动广播公司:

    public void onCreate() {
    KeyguardManager.KeyguardLock k1;
     KeyguardManager km =(KeyguardManager)getSystemService(KEYGUARD_SERVICE);
     k1= km.newKeyguardLock("IN");
     k1.disableKeyguard();
    Log.i("event", "ServiceStarted");
    IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
    filter.addAction(Intent.ACTION_SCREEN_OFF);
    mReceiver = new EventsReciever();
    registerReceiver (mReceiver, filter);
    super.onCreate();
}

当事件发生时,它会启动我的主要活动:

        public void onReceive(Context context, Intent recievedIntent) {

        Log.i("Check","[BroadCastReciever] onRecieve()");

        if (recievedIntent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
            wasScreenOn = false;
            Log.i("Check","[BroadCastReciever] Screen went OFF");
            Intent intent11 = new Intent(context,MainActivity.class);
            intent11.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            context.startActivity(intent11);
        } else if (recievedIntent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
            wasScreenOn = true;
            Log.i("Check","[BroadCastReciever] Screen went ON");

            Intent intent11 = new Intent(context, MainActivity.class);
            intent11.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        }
        else if(recievedIntent.getAction().equals(Intent.ACTION_BOOT_COMPLETED))
        {
            Intent intent11 = new Intent(context, MainActivity.class);
            intent11.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            context.startActivity(intent11);
        }
    }

}

这是一个更复杂的活动代码。我觉得问题可能在某处,但我无法弄清楚:

public class MainActivity extends Activity {

  private static Bitmap reusedBitmap;

@Override
protected void onCreate(Bundle savedInstanceState) {
    Log.i("event", "activity onCreate");
    requestWindowFeature(Window.FEATURE_NO_TITLE);
    this.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
    super.onCreate(savedInstanceState);
    getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON|WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED|WindowManager.LayoutParams.FLAG_FULLSCREEN);

    setContentView(R.layout.activity_main);

   if (getIntent()!=null&&getIntent().hasExtra("kill")&&getIntent().getExtras().getInt("kill")==1){
      // Toast.makeText(this, "" + "kill activity", Toast.LENGTH_SHORT).show();
            finish();
        }       

   try{

    setTime();
    ImageView img2 = (ImageView)findViewById(R.id.imageView);
    changeImage(false);
    img2.setOnTouchListener(new OnSwipeTouchListener(this) {

        @Override
        public void onSwipeLeft() {
            changeImage(true);
            Log.i("event","onSwipeLeft");
        }
        @Override
        public void onSwipeRight() {
            TextView tvDisplayDate = (TextView)findViewById(R.id.date1);
            CustomDigitalClock cdc = (CustomDigitalClock)findViewById(R.id.dc1);
            if (tvDisplayDate.getVisibility()==View.VISIBLE) {
                tvDisplayDate.setVisibility(View.GONE);
                cdc.setVisibility(View.GONE);
            } else {
                tvDisplayDate.setVisibility(View.VISIBLE);
                cdc.setVisibility(View.VISIBLE);
            }
        }
        @Override           
        public void onSwipeUp() {
//          MainActivity.this.moveTaskToBack(true);
            vCounter = 0;
            reusedBitmap = null;
            finish();
        }
        @Override           
        public void onSwipeDown() {
        }
    });

    img2.destroyDrawingCache();
    img2 = null;
} catch (Exception e) {
}
}


public void setTime() {
    TextView tvDisplayDate = (TextView)findViewById(R.id.date1);
    final Calendar c = Calendar.getInstance();
    int yy = c.get(Calendar.YEAR);
    int mm = c.get(Calendar.MONTH);
    int dd = c.get(Calendar.DAY_OF_MONTH);
    SimpleDateFormat dayFormat = new SimpleDateFormat("E", Locale.getDefault());
    String weekDay = dayFormat.format(c.getTime());;


    // set current date into textview
    tvDisplayDate.setText(new StringBuilder()
    // Month is 0 based, just add 1
            .append(yy).append(" ").append("-").append(" ").append(mm + 1).append(" ")
            .append("-").append(dd).append("     ").append(weekDay));
}

@Override
public void onBackPressed() {
    // Don't allow back to dismiss.
    return;
}

//only used in lockdown mode
@Override
protected void onPause() {
    super.onPause();
    Log.i("event","onPause");
}

@Override
protected void onResume() {
    super.onResume();
    Log.i("event", "onResume");
}

@Override
protected void onStart() {
    Log.i("event", "activity onStart");
    super.onStart();
}

@Override
protected void onStop() {
    Log.i("event","onStop");
    reusedBitmap = null;
}

@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
    Log.i("event", "key pressed " + keyCode);
    if ((keyCode == KeyEvent.KEYCODE_VOLUME_DOWN)||(keyCode == KeyEvent.KEYCODE_POWER)||(keyCode == KeyEvent.KEYCODE_VOLUME_UP)||(keyCode == KeyEvent.KEYCODE_CAMERA)) {
        return true; //because I handled the event
    }
   if((keyCode == KeyEvent.KEYCODE_HOME)){
       Toast.makeText(this, "You pressed home button", Toast.LENGTH_LONG).show();
       return true;
    }
    if ( keyCode == KeyEvent.KEYCODE_MENU ) {
        // do nothing
        return true;
    }
    return false;
}      

 public void onDestroy(){
     super.onDestroy();
 }    

public boolean dispatchKeyEvent(KeyEvent event) {
    if (event.getKeyCode() == KeyEvent.KEYCODE_POWER ||(event.getKeyCode() == KeyEvent.KEYCODE_VOLUME_DOWN)||(event.getKeyCode() == KeyEvent.KEYCODE_POWER)) {
        return false;
    }
     if((event.getKeyCode() == KeyEvent.KEYCODE_HOME)){

       System.out.println("home key press event sent");
       return true;
     }
return false;
}    

public void changeImage(Boolean vForce) {
    String pathV = null;
    SharedPreferences pref = getApplicationContext().getSharedPreferences("MyPref", 0); // 0 - for private mode
    Boolean vPicChosen;
    vPicChosen = pref.getBoolean("PicChosen", false);
    if (vPicChosen == true) {
        pathV = pref.getString("PicURL", "NOPIC");
    } else pathV = "NOPIC";
    if (pathV == "NOPIC" || vForce == true) {
        pathV = randomPic();
    }
    File imgFile = new File(pathV);
    if(imgFile.exists()) {
        ImageView img1 = (ImageView)findViewById(R.id.imageView);
        Display display = getWindowManager().getDefaultDisplay();
        int width = display.getWidth();
        int height = display.getHeight();
        Bitmap bmp2 = decodeSampledBitmapFromPath(pathV, width, height); 
        img1.destroyDrawingCache();
        img1.setImageBitmap(bmp2);
        img1.destroyDrawingCache();
        bmp2 = null;
        img1 = null;
        imgFile = null;
    }
    else
        Toast.makeText(this,  "no Image present", Toast.LENGTH_SHORT).show();

}

public static Bitmap decodeSampledBitmapFromPath(String Path,
        int reqWidth, int reqHeight) {

    // First decode with inJustDecodeBounds=true to check dimensions
    final BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    options.inBitmap = reusedBitmap;
    BitmapFactory.decodeFile(Path, options);

    // Calculate inSampleSize
    options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

    // Decode bitmap with inSampleSize set
    options.inJustDecodeBounds = false;
    return BitmapFactory.decodeFile(Path, options);
}


public class OnSwipeTouchListener implements OnTouchListener {

    private final GestureDetector gestureDetector;

    public OnSwipeTouchListener(Context context) {
        gestureDetector = new GestureDetector(context, new GestureListener());
    }

    public void onSwipeLeft() {
    }

    public void onSwipeRight() {
    }

    public void onSwipeUp() {

    }

    public void onSwipeDown() {

    }

    public boolean onTouch(View v, MotionEvent event) {
        return gestureDetector.onTouchEvent(event);
    }

    private final class GestureListener extends SimpleOnGestureListener {

        private static final int SWIPE_DISTANCE_THRESHOLD = 100;
        private static final int SWIPE_VELOCITY_THRESHOLD = 100;

        @Override
        public boolean onDown(MotionEvent e) {
            return true;
        }

        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
            float distanceX = e2.getX() - e1.getX();
            float distanceY = e2.getY() - e1.getY();
            if (Math.abs(distanceX) > Math.abs(distanceY) && Math.abs(distanceX) > SWIPE_DISTANCE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) {
                if (distanceX > 0)
                    onSwipeRight();
                else
                    onSwipeLeft();
                return true;
            }
            if (Math.abs(distanceY) > Math.abs(distanceX) && Math.abs(distanceY) > SWIPE_DISTANCE_THRESHOLD && Math.abs(velocityY) > SWIPE_VELOCITY_THRESHOLD) {
                if (distanceY < 0)
                    onSwipeUp();
                else
                    onSwipeDown();
                return true;
            }
            return false;
        }
    }
}
public String randomPic(){
    File dir = new File(path4);
    File childfile[] = dir.listFiles();
    Integer numFiles = childfile.length;
    Random r1=new Random();
    Integer selFile = r1.nextInt(numFiles);
    SharedPreferences pref = getApplicationContext().getSharedPreferences("MyPref", 0); // 0 - for private mode
    Editor editor = pref.edit();
    editor.putBoolean("PicChosen", true);
    editor.putString("PicURL", childfile[selFile].getPath());
    editor.commit();
    dir = null;
    return childfile[selFile].getPath();
}
}

有关我可能遗失的任何线索吗?

编辑1:

这是导致问题的原因:

Bitmap bmp2 = decodeSampledBitmapFromPath(pathV, width, height); 

我将此更改为以下,以重用静态位图变量:

//          reusedBitmap.recycle();
        reusedBitmap = decodeSampledBitmapFromPath(pathV, width, height); 

如果我在重复使用之前回收变量(如Gabe建议的那样),那么图像根本就没有加载,这甚至更奇怪。

编辑2:

如果我尝试在changeImage方法中回收reusedBitmap,我的imageview根本不会加载图像。如果我在onSwipeUp中回收reusedBitmap(就在完成之前),它不会产生任何积极的影响。在这种情况下,内存消耗保持不变。

0 个答案:

没有答案