我觉得我的问题与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(就在完成之前),它不会产生任何积极的影响。在这种情况下,内存消耗保持不变。