打点利器——ActivityLifecycleCallbacks

来源:互联网 发布:沈阳贵德软件电话 编辑:程序博客网 时间:2024/06/01 09:51

1.什么是ActivityLifecycleCallbacks?他有什么用?

ActivityLifecycleCallbacks是一个定义在Application类中的接口,API level 14。这个接口可以监控App进程中所有的Activity,在生命周期收到回调。Application提供了注册和反注册接口:
void registerActivityLifecycleCallbacks (Application.ActivityLifecycleCallbacks callback)
void unregisterActivityLifecycleCallbacks (Application.ActivityLifecycleCallbacks callback)
代码样例:

registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {            @Override            public void onActivityCreated(Activity activity, Bundle savedInstanceState) {            }            @Override            public void onActivityStarted(Activity activity) {            }            @Override            public void onActivityResumed(Activity activity) {            }            @Override            public void onActivityPaused(Activity activity) {            }            @Override            public void onActivityStopped(Activity activity) {            }            @Override            public void onActivitySaveInstanceState(Activity activity, Bundle outState) {            }            @Override            public void onActivityDestroyed(Activity activity) {            }        });

可以看到里面实现了Activity所有的生命周期。虽然Android中一般不需要集中式管理Activity,但这个接口仍然为那些需要所有Activity都实现的业务逻辑,在自己实现一个Activity子类作为App中所有Activity的基类这样的方案之外,提供了另外一种选择。而根据减低代码耦合度的准则,在同样能满足需求的前提下,这样的方案比增加Activity继承关系更好,更轻量级。
譬如页面打点这样的需求,就可以使用ActivityLifecycleCallbacks实现。

2.框架层是怎么实现的?

在Activity找一个回调,譬如onResume:

    protected void onResume() {        if (DEBUG_LIFECYCLE) Slog.v(TAG, "onResume " + this);        getApplication().dispatchActivityResumed(this);        mActivityTransitionState.onResume();        mCalled = true;    }

看到getApplication().dispatchActivityResumed(this);
接着看Application:

    /* package */ void dispatchActivityResumed(Activity activity) {        Object[] callbacks = collectActivityLifecycleCallbacks();        if (callbacks != null) {            for (int i=0; i<callbacks.length; i++) {                ((ActivityLifecycleCallbacks)callbacks[i]).onActivityResumed(activity);            }        }    }

在自己的回调对象集合中执行所有回调对象的回调方法。

    private Object[] collectActivityLifecycleCallbacks() {        Object[] callbacks = null;        synchronized (mActivityLifecycleCallbacks) {            if (mActivityLifecycleCallbacks.size() > 0) {                callbacks = mActivityLifecycleCallbacks.toArray();            }        }        return callbacks;    }

collectActivityLifecycleCallbacks()通过线程安全的方法取到当前的回调对象集合。mActivityLifecycleCallbacks是一个ArrayList:

    private ArrayList<ActivityLifecycleCallbacks> mActivityLifecycleCallbacks =            new ArrayList<ActivityLifecycleCallbacks>();

所以,实际上collectActivityLifecycleCallbacks()返回的方法是通过toArray()得到的一个副本:

    /**     * Returns a new array containing all elements contained in this     * {@code ArrayList}.     *     * @return an array of the elements from this {@code ArrayList}     */    @Override public Object[] toArray() {        int s = size;        Object[] result = new Object[s];        System.arraycopy(array, 0, result, 0, s);        return result;    }

当然,通过System.arraycopy()得到的数组,里面的对象引用是相同的,对象并没有被拷贝,并非深拷贝。
再看注册和反注册方法:

    public void registerActivityLifecycleCallbacks(ActivityLifecycleCallbacks callback) {        synchronized (mActivityLifecycleCallbacks) {            mActivityLifecycleCallbacks.add(callback);        }    }    public void unregisterActivityLifecycleCallbacks(ActivityLifecycleCallbacks callback) {        synchronized (mActivityLifecycleCallbacks) {            mActivityLifecycleCallbacks.remove(callback);        }    }

结合起来看,就是注册/反注册回调对象集合、获取当前回调对象集合这些操作在原始数据集mActivityLifecycleCallbacks上面被同一把锁保护,获取当前回调对象集合是原始数据集的一个副本(对象成员相同,并非副本),用他来脱离锁区域并处理回调。同时,因为已经释放锁,且并非在原始数据集上操作,所以不影响此时再有注册/反注册动作。
因为这个回调分发方法是Activity在自身的回调中同步调用的,所以在主线程执行。

3.有没有默认的回调对象?

由于Application没有给出接口直接访问已注册回调对象集合,所以用反射测一下:

package com.example.mi.myapplication;import android.app.Activity;import android.app.Application;import android.os.Bundle;import android.util.Log;import java.lang.reflect.Field;import java.util.ArrayList;public class MyApplication extends Application {    public void testActCBs() {        Class app = Application.class;        try {            Field field = app.getDeclaredField("mActivityLifecycleCallbacks");            field.setAccessible(true);            Log.i("MyApplication", "callbacks - " +                    ((ArrayList<ActivityLifecycleCallbacks>) field.get(this)).size());            registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {                @Override                public void onActivityCreated(Activity activity, Bundle savedInstanceState) {}                @Override                public void onActivityStarted(Activity activity) {}                @Override                public void onActivityResumed(Activity activity) {}                @Override                public void onActivityPaused(Activity activity) {}                @Override                public void onActivityStopped(Activity activity) {}                @Override                public void onActivitySaveInstanceState(Activity activity, Bundle outState) {}                @Override                public void onActivityDestroyed(Activity activity) {}            });            Log.i("MyApplication", "callbacks - " +                    ((ArrayList<ActivityLifecycleCallbacks>) field.get(this)).size());        } catch (IllegalAccessException e) {            Log.i("MyApplication", e.getMessage());        } catch (NoSuchFieldException e) {            Log.i("MyApplication", e.getMessage());        }    }}

在Activity中调用:

package com.example.mi.myapplication;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;public class MainActivity extends AppCompatActivity {    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        ((MyApplication)getApplication()).testActCBs();    }}

Log显示:

06-10 14:08:59.545 20696 20696 I MyApplication: callbacks - 006-10 14:08:59.545 20696 20696 I MyApplication: callbacks - 1

可见,框架层并无默认回调逻辑,这是一个完全给App的机制。