论坛首页 移动开发技术论坛

工具类:用于监听Activity的创建和内存级回收情况,防止Activity Leaking

浏览 5000 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2011-10-25  

import java.io.BufferedOutputStream;
import java.io.Closeable;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;

import android.app.Activity;
import android.content.Context;

public final class ActivityMemoryMonitor
{
	private final static ReferenceQueue<Activity> referenceQueue = new ReferenceQueue<Activity>();
	private final static Map<PhantomReference<Activity>, String> phantomReferenceMap = new HashMap<PhantomReference<Activity>, String>();

	private final static String logFile = "activity_memory_monitor.log";

	private static Timer memoryMonitorTimer = null;

	public static void setActivityToMonitoringQueue(Activity activity)
	{
		String activityInfo = activity.toString() + "." + activity.hashCode();
		phantomReferenceMap.put(new PhantomReference<Activity>(activity, referenceQueue), activityInfo);
		writeLogToFile(activity, "Activity Created: " + activityInfo);

		startMonitoringIfNeeded(activity.getApplicationContext());
	}

	private static void startMonitoringIfNeeded(Context context)
	{
		if (memoryMonitorTimer != null)
		{
			return;
		}
		memoryMonitorTimer = new Timer();
		memoryMonitorTimer.schedule(new MemoryMonitorTask(context), 0, 2000);
	}

	private static synchronized void writeLogToFile(Context context, String message)
	{
		FileOutputStream fos = null;
		BufferedOutputStream out = null;
		try
		{
			fos = context.openFileOutput(logFile, Context.MODE_APPEND);
			out = new BufferedOutputStream(fos);
			String log = new Date().toString() + "  " + message + "\n";
			out.write(log.getBytes());
		} catch (IOException e)
		{
		} finally
		{
			close(out);
			close(fos);
		}
	}

	private static void close(Closeable c)
	{
		if (c == null)
		{
			return;
		}

		try
		{
			c.close();
		} catch (IOException e)
		{
		}

	}

	private static class MemoryMonitorTask extends TimerTask
	{
		private Context context;

		MemoryMonitorTask(Context context)
		{
			this.context = context;
		}

		@Override
		public void run()
		{
			System.gc();

			Object o = ActivityMemoryMonitor.referenceQueue.poll();
			if (o != null)
			{
				writeLogToFile(context, "GC Cllected: " + phantomReferenceMap.get(o));
				phantomReferenceMap.remove(o);
			}
		}
	}

}
 
   发表时间:2011-10-25  
使用时只要在Activity的onCreate方法里写一句:ActivityMemoryMonitor.setActivityToMonitoringQueue(this);

日志会写到data/data/程序包名/files目录下
0 请登录后投票
   发表时间:2011-10-25  
ReferenceQueue  Activity,2秒做一个 object == null 检测
0 请登录后投票
   发表时间:2011-10-25  
嗯,是2秒做一个object != null的检测。
重点在PhantomReference,被内存级回收的对象才会加到ReferenceQueue里。
0 请登录后投票
   发表时间:2011-10-26  
请问在什么样的情况下才会出现Activity Leaking ?
0 请登录后投票
   发表时间:2011-10-26  
我特意去测试了,好像没有效果啊,还是报错。

10-26 02:06:33.311: ERROR/WindowManager(953): Activity com.mzba.im.ui.LoginActivity has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView@405e48a8 that was originally added here
10-26 02:06:33.311: ERROR/WindowManager(953): android.view.WindowLeaked: Activity com.mzba.im.ui.LoginActivity has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView@405e48a8 that was originally added here
0 请登录后投票
   发表时间:2011-10-26  
好吧,这个类只是监听Activity的内存回收情况,并写到日志中。所谓的防止,是你去看日志里看哪个Activity没有被回收,然后去找问题。
0 请登录后投票
论坛首页 移动开发技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics