您的位置:首页 > 移动开发 > Android开发

使用反射技术在Android平台上实现本进程内Activity切换时的拦截

2014-05-26 23:08 537 查看
有需求需要统计本应用内各Activity切换的次数与频度等,由于之前架构设计并未让所有Activity共同继承于一个基础类,同时TabActivity、FragmentActivity等的使用也没法让它们使用同一个父类,因此在本着不想改动每个Activity的目的下,我们摸索出了一个使用反射的方式来实现本应用内部Activity切换时的拦截,具体说来就是拦截本应用中每一个Activity的onPause和onResume事件。

基本思路:

访问ActivityThread的静态方法currentActivityThread拿到当前ActivityThread的实例,再通过反射拿到其private的mInstrumentation对象,并设置一个新的对象给此Field。该新的对象继承自Instramentation,重写了callActivityonPause和callActivityonResume方法,并在方法体内调用了之前旧的Instrumentation对象的同名方法。

ActivityThreadHooker.java

package com.testme.testinstr;

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

import android.app.Instrumentation;
import android.util.Log;

public class ActivityThreadHooker {

private static final String TAG = "ATHOOK";

private static ActivityThreadHooker instance = null;

private HookInstrumentation mHookInstr = null;

private Instrumentation mOldInstr = null;

private static boolean mHooked = false;

public static boolean getHooked()
{
return mHooked;
}

public ActivityThreadHooker() throws Throwable
{
synchronized (ActivityThreadHooker.class)
{
if (instance != null)
throw new Exception("Only one ActivityThreadHooker instance can

be created.");
instance = this;
}
mHookInstr = new HookInstrumentation();

try
{
initHook();
} catch (NoSuchFieldException ensf)
{
ensf.printStackTrace();
return;
} catch (IllegalArgumentException eilar)
{
eilar.printStackTrace();
return;
} catch (IllegalAccessException eilac)
{
eilac.printStackTrace();
return;
} catch (ClassNotFoundException ecnf)
{
ecnf.printStackTrace();
return;
} catch (NoSuchMethodException ensm)
{
ensm.printStackTrace();
return;
}

mHooked = true;
}

private void initHook() throws NoSuchFieldException, IllegalArgumentException,
IllegalAccessException, ClassNotFoundException, NoSuchMethodException
{
Class<?> atClass = Class.forName("android.app.ActivityThread");
Method cat = atClass.getMethod("currentActivityThread");

Object at = null;
try
{
at = cat.invoke(atClass, new Object[0]);
}
catch (InvocationTargetException eit)
{
return;
}

if (at == null)
return;

Field instrField = atClass.getDeclaredField("mInstrumentation");
instrField.setAccessible(true);
mOldInstr = (Instrumentation) instrField.get(at);

boolean res = mHookInstr.initOldInstr(mOldInstr);
if (!res)
{
Log.e(TAG, "Error process Old Instrumentation.");
return;
}

instrField.set(at, mHookInstr);

Log.d(TAG, "Hook success!");
}
}


HookInstrumentation.java

package com.testme.testinstr;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import android.app.Activity;
import android.app.Instrumentation;
import android.util.Log;

public class HookInstrumentation extends Instrumentation {

private static final String TAG = "ATHOOK";

private Instrumentation mOldInstr = null;

private Method methodResume = null;
private Method methodPause = null;

private void obtainMethods() throws NoSuchMethodException
{
if ( mOldInstr == null )
return;
Class<?> inClass = mOldInstr.getClass();
methodResume = inClass.getMethod("callActivityOnResume", Activity.class);
methodPause = inClass.getMethod("callActivityOnPause", Activity.class);
}

@Override
public void callActivityOnPause(Activity activity) {
Log.d(TAG, "OnPause Intercept here.");

if ( methodPause != null )
{
try {
methodPause.invoke(mOldInstr, activity);
} catch (IllegalArgumentException e) {
e.printStackTrace();
return;
} catch (IllegalAccessException e) {
e.printStackTrace();
return;
} catch (InvocationTargetException e) {
e.printStackTrace();
return;
}
}
else
super.callActivityOnPause(activity);
}

@Override
public void callActivityOnResume(Activity activity) {
if ( methodResume != null )
{
try {
methodResume.invoke(mOldInstr, activity);
} catch (IllegalArgumentException e) {
e.printStackTrace();
return;
} catch (IllegalAccessException e) {
e.printStackTrace();
return;
} catch (InvocationTargetException e) {
e.printStackTrace();
return;
}

Log.d(TAG, "OnResume Intercept here.");
}
else
super.callActivityOnResume(activity);
}

public boolean initOldInstr(Instrumentation oldInstr) {
mOldInstr = oldInstr;
try {
obtainMethods();
return true;
} catch (NoSuchMethodException e) {
e.printStackTrace();
return false;
}
}

}


使用时只需要在Application初始化时,new一个ActivityThreadHooker即可。切换Activity时,会在logcat中打印出“OnPause Intercept here.”以及“OnResume Intercept here.”等信息。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐