Application解析と内部のコールバック関数
12767 ワード
このクラスはプログラムのタグとしてandroidを始めたばかりの頃、直接4つのコンポーネントの作成に着手した.その後、一般的には自分でクラスを書いて自分で継承し、onCreateでいくつかのタスクを限定的に処理し、グローバルな異常をキャプチャしていることがわかりました.今日apiを見ていると、とても役に立つ方法がいくつかあります.
まず継承構造を見ます.
彼はContextWrapperクラスを継承して、その名の通り、Contextの包装クラス、ContextWrapperの中でこの正真のContextを維持して、mBaseと定義されて、彼は抽象クラスContextの実現クラスで、ContextImplと呼ばれています.
ContextWrapperのmBaseにContextImplオブジェクトを添付するには、次の2つの方法があります.
アプリケーションの作成:
やはりApplicationの作成から言えば、Applicationがなくて、ContextImplを設定する方法はありません(ここではデスクトップのiconをクリックして新しいアプリケーションを起動する方法からApplicationの作成について話します).
デスクトップ上のアプリケーションをクリックすると、最終的にActivity ThreadのperformLaunchActivityメソッドが呼び出されます.前の手順は「羅さんのブログ」を参考にすることができます.
2128:ここでアプリケーションの作成の開始です
ActivityThread.class
LoadedApk.class
そしてappContextを利用する.init(this, null, mActivityThread);をクリックしてContextImplのオブジェクトを初期化します.
ContextImpl .class
Instrumentation.class
Application.class
方法が多すぎると一つ一つリストされません.次に、Applicationが登録できる3つのコールバックを見てみましょう.
これは4.0後に入ったのでしょうか?
1.最初のコールバックはComponentCallbacksタイプであり、ComponentCallbacksまたはComponentCallbacks 2であってもよい.ComponentCallbacksコールバックインタフェースは2つの方法しか提供していない.
Applicationでは、ComponentCallbacks 2インタフェースが実装されているため、この3つの方法が実装されています.
自分のアプリケーションまたは4つのコンポーネントで傍受するだけで、この3つのメソッドを書き換えるだけで、superの3つのメソッドを呼び出すことが望ましい.他の場所で傍受する必要がある場合は、アプリケーションオブジェクトのregisterComponentCallback(ComponentCallback)メソッドでコールバックを登録すればよい.
onLowMemory():システムのメモリが不足し、すべてのバックグラウンドプログラム(優先度backgroundのプロセス、バックグラウンドで実行されるプロセスではない)が殺された場合、システムはOnLowMemoryを呼び出す.
onTrimMemory(int level):OnTrimMemoryはAndroid 4.0以降に提供するAPIであり、システムは異なるメモリ状態に応じてコールバックする.
コールバックのパラメータの意味:
この3つは、現在実行中のプログラムです.
TRIM_MEMORY_RUNNING_MODERATE(5):アプリケーションが正常に動作していることを示しますが、現在は携帯電話のメモリが少し低くなっています.実行中のプロセスでは、他の場所で不要なリソースを解放する必要がある場合があります.LRUキャッシュ規則に従ってプロセスを殺し始める可能性があります
TRIM_MEMORY_RUNNING_LOW(10):アプリケーションが正常に動作していることを示しますが、現在、携帯電話のメモリは少し低くなっています.実行中のプロセスは、他の場所で使用できるメモリを必要としないリソースを空ける必要があります.
TRIM_MEMORY_RUNNING_CRITICAL(15):アプリケーションが正常に動作しているが、デバイスで非常に低いメモリが動作し、バックグラウンドプロセスの実行を維持できないことを示します.実行中のプロセスは、他の場所で使用できるメモリを使用できるため、できるだけ多くの非キーリソースを空ける必要があります.この場合,ユーザに顕著な影響を及ぼし始めることができ,その後,onLowMemory()レポートが保持されていないバックグラウンドプロセスの後を呼び出す.
この3つは、現在のプログラムがバックグラウンドにあります.
TRIM_MEMORY_UI_HIDDEN(20):ユーザが再びデスクトップに戻って呼び出す
TRIM_MEMORY_BACKGROUND(40):携帯電話のメモリが低くなっていることを示し、LRUキャッシュに基づいてプロセスをクリーンアップする準備ができています.このとき、私たちのプログラムはLRUキャッシュリストの最近の位置では、クリーンアップされることはできませんが、回復しやすいリソースを解放することで、携帯電話のメモリを十分にすることができ、私たちのプログラムをキャッシュに長く残すことができます.これにより、ユーザーが私たちのプログラムに戻ると、再起動のプロセスを経験するのではなく、非常にスムーズに感じることができます.
TRIM_MEMORY_MODERATE(60):携帯電話のメモリが低く、私たちのプログラムがLRUキャッシュリストの中間位置にあることを示しています.もし携帯電話のメモリがさらに解放されなければ、私たちのプログラムはシステムに殺されるリスクがあります.
TRIM_MEMORY_COMPLETE(80):携帯電話のメモリが低く、私たちのプログラムがLRUキャッシュリストの最端にあることを示しています.システムは私たちのアプリケーションを殺すことを最優先しています.この時、できるだけ解放できるものを解放しなければなりません.
onConfigurationChanged(Configuration newConfig):デバイスの情報が変更されると呼び出され、システムの構成情報が変更されるとactivityが再onCreate()を避ける必要がある場合があります.android:configChangesで、ある属性が宣言されていることを宣言することができます.この属性の情報が変更されると、onConfigurationChanged(Configuration newConfig)メソッドのみがコールバックされます.
Configuration.fontScale:ユーザーがフォントのサイズを選択
Configuration.mcc:simをmccに交換
Configuration.mnc:simはmncに交換されました
Configuration.locale:システム言語設定
Configuration.screenLayout:
Configuration.touchscreen:
Configuration.keyboard:
Configuration.keyboardHidden:
Configuration.hardKeyboardHidden:
Configuration.navigation:
Configuration.navigationHidden:
Configuration.orientation:画面が回転しました
Configuration.uiMode:
Configuration.screenWidthDp:
Configuration.screenHeightDp:
Configuration.smallestScreenWidthDp:
Configuration.densityDpi:
Configuration.orientation:
2.2番目のコールバックは、Activity LifecycleCallbacksタイプ(4.0+)です.
従来我々はactivityのライフサイクルを検出するが,いずれも単独のactivityにおけるライフサイクル関数にLogを書く.
アプリケーションでこのインタフェースを実装して登録すれば、次のようになります.
3.3番目のコールバックは、OnProvideAssistDataListenerタイプです.まだ理解されていない
まず継承構造を見ます.
彼はContextWrapperクラスを継承して、その名の通り、Contextの包装クラス、ContextWrapperの中でこの正真のContextを維持して、mBaseと定義されて、彼は抽象クラスContextの実現クラスで、ContextImplと呼ばれています.
ContextWrapperのmBaseにContextImplオブジェクトを添付するには、次の2つの方法があります.
アプリケーションの作成:
やはりApplicationの作成から言えば、Applicationがなくて、ContextImplを設定する方法はありません(ここではデスクトップのiconをクリックして新しいアプリケーションを起動する方法からApplicationの作成について話します).
デスクトップ上のアプリケーションをクリックすると、最終的にActivity ThreadのperformLaunchActivityメソッドが呼び出されます.前の手順は「羅さんのブログ」を参考にすることができます.
2128:ここでアプリケーションの作成の開始です
ActivityThread.class
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
ここのr.packageInfoはLoadedApkオブジェクトで、彼はLoadedApkの中を呼び出しました.LoadedApk.class
public Application makeApplication(boolean forceDefaultAppClass,
Instrumentation instrumentation) {
if (mApplication != null) {
return mApplication;
}
Application app = null;
String appClass = mApplicationInfo.className;
if (forceDefaultAppClass || (appClass == null)) {
appClass = "android.app.Application";
}
try {
java.lang.ClassLoader cl = getClassLoader();
ContextImpl appContext = new ContextImpl();
appContext.init(this, null, mActivityThread);
app = mActivityThread.mInstrumentation.newApplication(
cl, appClass, appContext);
appContext.setOuterContext(app);
} catch (Exception e) {
if (!mActivityThread.mInstrumentation.onException(app, e)) {
throw new RuntimeException(
"Unable to instantiate application " + appClass
+ ": " + e.toString(), e);
}
}
mActivityThread.mAllApplications.add(app);
mApplication = app;
if (instrumentation != null) {
try {
instrumentation.callApplicationOnCreate(app);
} catch (Exception e) {
if (!instrumentation.onException(app, e)) {
throw new RuntimeException(
"Unable to create application " + app.getClass().getName()
+ ": " + e.toString(), e);
}
}
}
return app;
}
ここではContextImpl appContext=new ContextImpl()を利用する.をクリックしてContextImplオブジェクトを作成します.これは、後でApplicationに設定するmBaseオブジェクトです.そしてappContextを利用する.init(this, null, mActivityThread);をクリックしてContextImplのオブジェクトを初期化します.
ContextImpl .class
final void init(LoadedApk packageInfo, IBinder activityToken, ActivityThread mainThread) {
init(packageInfo, activityToken, mainThread, null, null, Process.myUserHandle());
}
final void init(LoadedApk packageInfo, IBinder activityToken, ActivityThread mainThread,
Resources container, String basePackageName, UserHandle user) {
mPackageInfo = packageInfo;
if (basePackageName != null) {
mBasePackageName = mOpPackageName = basePackageName;
} else {
mBasePackageName = packageInfo.mPackageName;
ApplicationInfo ainfo = packageInfo.getApplicationInfo();
if (ainfo.uid == Process.SYSTEM_UID && ainfo.uid != Process.myUid()) {
// Special case: system components allow themselves to be loaded in to other
// processes. For purposes of app ops, we must then consider the context as
// belonging to the package of this process, not the system itself, otherwise
// the package+uid verifications in app ops will fail.
mOpPackageName = ActivityThread.currentPackageName();
} else {
mOpPackageName = mBasePackageName;
}
}
mResources = mPackageInfo.getResources(mainThread);
mResourcesManager = ResourcesManager.getInstance();
CompatibilityInfo compatInfo =
container == null ? null : container.getCompatibilityInfo();
if (mResources != null &&
((compatInfo != null && compatInfo.applicationScale !=
mResources.getCompatibilityInfo().applicationScale)
|| activityToken != null)) {
if (DEBUG) {
Log.d(TAG, "loaded context has different scaling. Using container's" +
" compatiblity info:" + container.getDisplayMetrics());
}
if (compatInfo == null) {
compatInfo = packageInfo.getCompatibilityInfo();
}
mDisplayAdjustments.setCompatibilityInfo(compatInfo);
mDisplayAdjustments.setActivityToken(activityToken);
mResources = mResourcesManager.getTopLevelResources(mPackageInfo.getResDir(),
Display.DEFAULT_DISPLAY, null, compatInfo, activityToken);
} else {
mDisplayAdjustments.setCompatibilityInfo(packageInfo.getCompatibilityInfo());
mDisplayAdjustments.setActivityToken(activityToken);
}
mMainThread = mainThread;
mActivityToken = activityToken;
mContentResolver = new ApplicationContentResolver(this, mainThread, user);
mUser = user;
}
この中には多くのメンバー変数が維持されており、他の方法で間接的または直接呼び出される必要があります.ここで初期化を行い、次のようにします.mActivityThread.mInstrumentation.newApplication(cl, appClass, appContext);
ここでmActivity Threadが呼び出されました.mInstrumentationクラスであるオブジェクトのメソッド:Instrumentation.class
/**
* Perform instantiation of the process's {@link Application} object. The
* default implementation provides the normal system behavior.
*
* @param cl The ClassLoader with which to instantiate the object.
* @param className The name of the class implementing the Application
* object.
* @param context The context to initialize the application with
*
* @return The newly instantiated Application object.
*/
public Application newApplication(ClassLoader cl, String className, Context context)
throws InstantiationException, IllegalAccessException,
ClassNotFoundException {
return newApplication(cl.loadClass(className), context);
}
/**
* Perform instantiation of the process's {@link Application} object. The
* default implementation provides the normal system behavior.
*
* @param clazz The class used to create an Application object from.
* @param context The context to initialize the application with
*
* @return The newly instantiated Application object.
*/
static public Application newApplication(Class<?> clazz, Context context)
throws InstantiationException, IllegalAccessException,
ClassNotFoundException {
Application app = (Application)clazz.newInstance();
app.attach(context);
return app;
}
上から分かるように、最後にApplicationが作成すると、appが呼び出される.attach(context);この方法はApplicationでhideのものだったので、ideでは見つかりませんでしたが、ソースコードを見ると見つかりました.Application.class
/**
* @hide
*/
/* package */ final void attach(Context context) {
attachBaseContext(context);
mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;
}
ここでやっとattachBaseContext(context)が呼び出されたのを見た.の方法で、ここまでContextWrapperの中のmBaseはやっと本当にオブジェクトを獲得しました.アプリケーションはContextWrapperから継承する方法を使用できます.方法が多すぎると一つ一つリストされません.次に、Applicationが登録できる3つのコールバックを見てみましょう.
これは4.0後に入ったのでしょうか?
1.最初のコールバックはComponentCallbacksタイプであり、ComponentCallbacksまたはComponentCallbacks 2であってもよい.ComponentCallbacksコールバックインタフェースは2つの方法しか提供していない.
void onConfigurationChanged(Configuration newConfig);
void onLowMemory();
ComponentCallbacks 2 ComponentCallbacksを継承するには、次の方法があります.void onTrimMemory(int level);
Applicationでは、ComponentCallbacks 2インタフェースが実装されているため、この3つの方法が実装されています.
public void onConfigurationChanged(Configuration newConfig) {
Object[] callbacks = collectComponentCallbacks();
if (callbacks != null) {
for (int i=0; i<callbacks.length; i++) {
((ComponentCallbacks)callbacks[i]).onConfigurationChanged(newConfig);
}
}
}
public void onLowMemory() {
Object[] callbacks = collectComponentCallbacks();
if (callbacks != null) {
for (int i=0; i<callbacks.length; i++) {
((ComponentCallbacks)callbacks[i]).onLowMemory();
}
}
}
public void onTrimMemory(int level) {
Object[] callbacks = collectComponentCallbacks();
if (callbacks != null) {
for (int i=0; i<callbacks.length; i++) {
Object c = callbacks[i];
if (c instanceof ComponentCallbacks2) {
((ComponentCallbacks2)c).onTrimMemory(level);
}
}
}
}
自分のアプリケーションまたは4つのコンポーネントで傍受するだけで、この3つのメソッドを書き換えるだけで、superの3つのメソッドを呼び出すことが望ましい.他の場所で傍受する必要がある場合は、アプリケーションオブジェクトのregisterComponentCallback(ComponentCallback)メソッドでコールバックを登録すればよい.
onLowMemory():システムのメモリが不足し、すべてのバックグラウンドプログラム(優先度backgroundのプロセス、バックグラウンドで実行されるプロセスではない)が殺された場合、システムはOnLowMemoryを呼び出す.
onTrimMemory(int level):OnTrimMemoryはAndroid 4.0以降に提供するAPIであり、システムは異なるメモリ状態に応じてコールバックする.
コールバックのパラメータの意味:
この3つは、現在実行中のプログラムです.
TRIM_MEMORY_RUNNING_MODERATE(5):アプリケーションが正常に動作していることを示しますが、現在は携帯電話のメモリが少し低くなっています.実行中のプロセスでは、他の場所で不要なリソースを解放する必要がある場合があります.LRUキャッシュ規則に従ってプロセスを殺し始める可能性があります
TRIM_MEMORY_RUNNING_LOW(10):アプリケーションが正常に動作していることを示しますが、現在、携帯電話のメモリは少し低くなっています.実行中のプロセスは、他の場所で使用できるメモリを必要としないリソースを空ける必要があります.
TRIM_MEMORY_RUNNING_CRITICAL(15):アプリケーションが正常に動作しているが、デバイスで非常に低いメモリが動作し、バックグラウンドプロセスの実行を維持できないことを示します.実行中のプロセスは、他の場所で使用できるメモリを使用できるため、できるだけ多くの非キーリソースを空ける必要があります.この場合,ユーザに顕著な影響を及ぼし始めることができ,その後,onLowMemory()レポートが保持されていないバックグラウンドプロセスの後を呼び出す.
この3つは、現在のプログラムがバックグラウンドにあります.
TRIM_MEMORY_UI_HIDDEN(20):ユーザが再びデスクトップに戻って呼び出す
TRIM_MEMORY_BACKGROUND(40):携帯電話のメモリが低くなっていることを示し、LRUキャッシュに基づいてプロセスをクリーンアップする準備ができています.このとき、私たちのプログラムはLRUキャッシュリストの最近の位置では、クリーンアップされることはできませんが、回復しやすいリソースを解放することで、携帯電話のメモリを十分にすることができ、私たちのプログラムをキャッシュに長く残すことができます.これにより、ユーザーが私たちのプログラムに戻ると、再起動のプロセスを経験するのではなく、非常にスムーズに感じることができます.
TRIM_MEMORY_MODERATE(60):携帯電話のメモリが低く、私たちのプログラムがLRUキャッシュリストの中間位置にあることを示しています.もし携帯電話のメモリがさらに解放されなければ、私たちのプログラムはシステムに殺されるリスクがあります.
TRIM_MEMORY_COMPLETE(80):携帯電話のメモリが低く、私たちのプログラムがLRUキャッシュリストの最端にあることを示しています.システムは私たちのアプリケーションを殺すことを最優先しています.この時、できるだけ解放できるものを解放しなければなりません.
onConfigurationChanged(Configuration newConfig):デバイスの情報が変更されると呼び出され、システムの構成情報が変更されるとactivityが再onCreate()を避ける必要がある場合があります.android:configChangesで、ある属性が宣言されていることを宣言することができます.この属性の情報が変更されると、onConfigurationChanged(Configuration newConfig)メソッドのみがコールバックされます.
Configuration.fontScale:ユーザーがフォントのサイズを選択
Configuration.mcc:simをmccに交換
Configuration.mnc:simはmncに交換されました
Configuration.locale:システム言語設定
Configuration.screenLayout:
Configuration.touchscreen:
Configuration.keyboard:
Configuration.keyboardHidden:
Configuration.hardKeyboardHidden:
Configuration.navigation:
Configuration.navigationHidden:
Configuration.orientation:画面が回転しました
Configuration.uiMode:
Configuration.screenWidthDp:
Configuration.screenHeightDp:
Configuration.smallestScreenWidthDp:
Configuration.densityDpi:
Configuration.orientation:
2.2番目のコールバックは、Activity LifecycleCallbacksタイプ(4.0+)です.
従来我々はactivityのライフサイクルを検出するが,いずれも単独のactivityにおけるライフサイクル関数にLogを書く.
アプリケーションでこのインタフェースを実装して登録すれば、次のようになります.
public interface ActivityLifecycleCallbacks {
void onActivityCreated(Activity activity, Bundle savedInstanceState);
void onActivityStarted(Activity activity);
void onActivityResumed(Activity activity);
void onActivityPaused(Activity activity);
void onActivityStopped(Activity activity);
void onActivitySaveInstanceState(Activity activity, Bundle outState);
void onActivityDestroyed(Activity activity);
}
は、その後、r e g i s t e r A c t i vityLifecycleCallbacks(A t i v ityLifecycleCallbacks callback)によって登録され、アプリケーション内のすべてのactivityライフサイクルのリスニングを実現することができる.3.3番目のコールバックは、OnProvideAssistDataListenerタイプです.まだ理解されていない