1. 程式人生 > >Android 獲取最近應用的縮圖

Android 獲取最近應用的縮圖

最近有項需求是獲取應用的縮略,用於在動畫時顯示。因此就對此塊知識簡要了解了一下。

在android中獲取視訊檔案的縮圖有三種方法:

1.從媒體庫中查詢
新視訊增加後需要SDCard重新掃描才能給新增加的檔案新增縮圖,靈活性差,而且不是很穩定,適合簡單應用
2. android 2.2以後使用ThumbnailUtils類獲取
實現簡單,但2.2以前的版本不支援
3.呼叫jni檔案,實現MediaMetadataRetriever類

實現複雜,但比較靈活,推薦使用

那麼Android 中如何獲取最近應用的縮圖,這塊也有現成的函式,不過都被 @hide 掉了,所以需要利用java reflect 反射才能使用

核心程式碼如下:

package com.example.testondraw;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

import android.app.ActivityManager;
import android.graphics.Bitmap;
import android.util.Log;

/**
 * 呼叫隱藏方法的助手類
 */
public class HideExploder {
	static final String TAG = "HideExploder";
	private final static Object refLock = new Object();

	private static Method getTaskThumbnails = null;
	private static Field taskThumbnailsBitmap = null;

	@SuppressWarnings("rawtypes")
	public static void listAllObject(String classFullName) {
		try {
			Log.i(TAG, "listAllObject classFullName: " + classFullName);
			Class<?> clazz = Class.forName(classFullName);

			// 反射屬性欄位
			Field[] fields = clazz.getDeclaredFields();

			// 反射方法欄位
			Method[] methods = clazz.getDeclaredMethods();

			// 反射構造器
			Constructor[] constuctors = clazz.getDeclaredConstructors();

			Log.i(TAG, "FIELD========");
			for (Field f : fields) {
				Log.i(TAG, "TYPE: " + f.getType() + " NAME: " + f.getName());
			}

			Log.i(TAG, "METHOD========");
			for (Method m : methods) {
				Log.i(TAG, "METHOD NAME: " + m.getName());
			}

			Log.i(TAG, "CONSTUCTOR========");
			for (Constructor c : constuctors) {
				Log.i(TAG, "NAME:" + c.getName());

				Class[] clss = c.getParameterTypes();
				Object o = null;

				// 產生例項
				try {
					if (clss.length == 0)
						o = c.newInstance();
					else if (clss.length > 0) {
						// TODO
					}
					Log.i(TAG, "object: " + o);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

/**
 * 呼叫邏輯
 * 
 * TaskThumbnails o = am.getTaskThumbnails(id)
 * Bitmap b = o.mainThumbnail;
 * 
 * @param am ActivityManager 類例項
 * @param id 標識值
 * @return
 */

	public static Bitmap getTaskThumbnailsBitmap(ActivityManager am, int id) {
		synchronized (refLock) {
			try {
				if (getTaskThumbnails == null) {
					getTaskThumbnails = am.getClass().getDeclaredMethod(
							"getTaskThumbnails", int.class);
				}
				if (getTaskThumbnails != null) {
					Object thumbnails = getTaskThumbnails.invoke(am,
							Integer.valueOf(id));
					if (thumbnails != null) {
						if (taskThumbnailsBitmap == null)
							taskThumbnailsBitmap = thumbnails.getClass()
									.getField("mainThumbnail");
						if (taskThumbnailsBitmap != null) {
							return (Bitmap) taskThumbnailsBitmap
									.get(thumbnails);
						}
					}
				}
			} catch (Exception e) {
				Log.w(TAG, "getTaskThumbnailsBitmap error:" + e);
				e.printStackTrace();
			}
		}
		return null;
	}
}

測試用例如下:
// 應用縮圖測試
	static final int MAX_RECENT_TASKS = 64;

	Bitmap loadThumbnail(int index) {
		ActivityManager am = (ActivityManager) this
				.getSystemService(Context.ACTIVITY_SERVICE);
		List<ActivityManager.RecentTaskInfo> recentTasks = am.getRecentTasks(
				MAX_RECENT_TASKS, ActivityManager.RECENT_IGNORE_UNAVAILABLE);
		int numTasks = recentTasks.size();

		if (index < numTasks) {
			final ActivityManager.RecentTaskInfo info = recentTasks.get(index);
			if (info != null) {
				Bitmap b = HideExploderX.getTaskThumbnailsBitmap(am,
						info.persistentId);
				return b;
			}
		}
		return null;
	}

呼叫 loadThumbnail(X) 【索引值為0就是上一次的縮圖】拿到Bitmap物件,利用 SurfaceView 方法畫出來即可:
public void drawBitmap() {
		// 鎖定畫布,得到canvas
		if (mSurfaceHolder == null || this.mBitmap == null)
			return;

		Canvas canvas = mSurfaceHolder.lockCanvas();
		if (canvas == null) {
			return;
		}

		// 繪圖
		Paint paint = new Paint();
		paint.setAntiAlias(true);
		paint.setColor(Color.BLUE);

		canvas.drawBitmap(this.mBitmap, 0, 0, paint);

		// 繪製後解鎖,繪製後必須解鎖才能顯示
		mSurfaceHolder.unlockCanvasAndPost(canvas);
	}

注意點:

1、新增應用許可權

    <uses-permission android:name="android.permission.GET_TASKS"/>
    <uses-permission android:name="android.permission.READ_FRAME_BUFFER"/>

   否則會報:

W/System.err( 3314): Caused by: java.lang.SecurityException: Permission Denial: getTaskThumbnails() from pid=3314, uid=10040 requires android.permission.READ_FRAME_BUFFER

2、有 eclipse 上除錯執行時,即使加上許可權了也還是會報上述錯誤,有兩個方法解決,要麼進行系統簽名,要不放到linux上編譯,利用platform 簽名,Android.mk 如下:

LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)

LOCAL_MODULE_TAGS := optional

# Only compile source java files in this apk.
LOCAL_SRC_FILES := $(call all-java-files-under, src)

$(warning build apk)

LOCAL_PACKAGE_NAME := test

LOCAL_CERTIFICATE := platform

include $(BUILD_PACKAGE)

include $(call all-makefiles-under,$(LOCAL_PATH))
下一篇文章將針對其系統程式碼及原理分析清楚,用於新需求開發使用。