Application简介
官方文档中的描述:
Application 是用来维护应用程序全局状态[maintain global application state]的基础类。你可以通过在 AndroidManifest.xml 文件的 <application> 标签中指出他的 android:name 属性的方式提供自己的实现。在创建应用程序/包的进程时,Application类或Application类的子类在任何其他类之前实例化。
注意:通常不需要子类化Application。在大多数情况下,静态单例[static singletons]可以以更模块化的方式[more modular way]提供相同的功能。如果您的单例需要全局上下文(例如注册广播接收器),则在调用单例的getInstance()方法时将Context.getApplicationContext()作为Context参数。
<application
android:name=".MyApplication"
...
x
1
<application
2
android:name=".MyApplication"
3
...
Android系统会为每个程序运行时创建一个Application类的对象且仅创建一个,所以Application可以说是单例 (Singleton)模式的一个类。且 Application 对象的生命周期是整个程序中最长的,它的生命周期就等于这个程序的生命周期。因为它是全局唯一的,所以在不同的Activity,Service中获得的对象都是同一个对象。所以通过 Application 来进行一些:数据传递、数据共享、数据缓存等操作。
Application和Activity,Service一样是Android框架的一个系统组件,当android程序启动时系统会创建一个 Application对象,用来存储系统的一些信息。通常我们是不需要指定一个Application的,这时系统会自动帮我们创建,如果需要创建自己 的Application,也很简单,创建一个类继承 Application并在manifest的application标签中进行注册,只需要给Application标签增加个name属性把自己的 Application的名字定入即可。
android系统会为每个程序运行时创建一个Application类的对象且仅创建一个,所以Application可以说是单例模式的一个类,且application对象的生命周期是整个程序中最长的,它的生命周期就等于这个程序的生命周期。因为它是全局的单例的,所以在不同的Activity,Service中获得的对象都是同一个对象。所以可以通过Application来进行一些数据传递,数据共享,数据缓存等操作。
Application 的生命周期方法
-
onCreate:在应用程序创建的时候被调用,可以实现这个这个方法来创建和实例化任何应用程序状态变量或共享资源。还可以在这个方法里面得到 Application 的单例。
-
onTerminate:当终止应用程序对象时调用,不保证一定被调用,当程序是被内核终止以便为其他应用程序释放资源,那么将不会提醒,并且不调用应用程序的对象的onTerminate方法而直接终止进程。
-
onLowMemory:当系统资源匮乏的时候,我们可以在这里可以释放额外的内存。这个方法一般只会在后台进程已经结束,但前台应用程序还是缺少内存时调用。可以重写这个方法来清空缓存或者释放不必要的资源。
按我的理解就是,当APP处于前台时,但是所有后台程序都被kill光了,但是还是内存不足时,系统就会调用这个方法告诉APP:兄弟轮到你了。我们可以在这个方法里面释放一些不重要的资源,来保证到时候内存足够而让APP进程不被系统杀掉,或者提醒用户清一下垃圾,让内存清一点空位出来,我的手机老是这样提示我,不知道是不是这个方法惹的祸。
x
1
按我的理解就是,当APP处于前台时,但是所有后台程序都被kill光了,但是还是内存不足时,系统就会调用这个方法告诉APP:兄弟轮到你了。我们可以在这个方法里面释放一些不重要的资源,来保证到时候内存足够而让APP进程不被系统杀掉,或者提醒用户清一下垃圾,让内存清一点空位出来,我的手机老是这样提示我,不知道是不是这个方法惹的祸。
-
onConfigurationChanged(Configuration newConfig):重写此方法可以监听APP一些配置信息的改变事件(如屏幕旋转等),当配置信息改变的时候会调用这个方法。与 Activity 不同,配置改变时,应用程序对象不会被终止和重启。如果应用程序使用的值依赖于特定的配置,则重写这个方法来加载这些值,或者在应用程序级处理配置值的改变。
- onTrimMemory(int level):系统用这个方法提醒APP释放一些缓存了,如图片缓存,数据缓存之类的。里有传入一个int类型的参数level,它告诉APP们内存不足的严重性(越高越严重)
注册全局的 ActivityLifecycleCallbacks
registerActivityLifecycleCallbacks 和 unregisterActivityLifecycleCallbacks 这两个方法用于注册或者注销对APP内所有Activity的生命周期监听,当APP内Activity的生命周期发生变化的时候就会调用ActivityLifecycleCallbacks里面的方法:
registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
}
@Override
public void onActivityDestroyed(Activity activity) {
}
@Override
public void onActivityStarted(Activity activity) {
}
@Override
public void onActivityResumed(Activity activity) {
Log.i("bqt", "当前Activity" + "(" + activity.getClass().getSimpleName()+".java" + ":" +30 + ")");
}
@Override
public void onActivityPaused(Activity activity) {
}
@Override
public void onActivityStopped(Activity activity) {
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
});
x
1
registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
2
3
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
4
}
5
6
7
public void onActivityDestroyed(Activity activity) {
8
}
9
10
11
public void onActivityStarted(Activity activity) {
12
}
13
14
15
public void onActivityResumed(Activity activity) {
16
Log.i("bqt", "当前Activity" + "(" + activity.getClass().getSimpleName()+".java" + ":" +30 + ")");
17
}
18
19
20
public void onActivityPaused(Activity activity) {
21
}
22
23
24
public void onActivityStopped(Activity activity) {
25
}
26
27
28
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
29
}
30
});
Application 中的其他注册方法
1、registerComponentCallbacks 和 unregisterComponentCallbacks 方法
用于注册和注销 ComponentCallbacks2 回调接口,里面的方法前面已经介绍过,看名字就知道。
Context 类也有这两个方法,但是 Context 类的方法只可以使用 ComponentCallbacks,比 ComponentCallbacks2 少了一个 onTrimMemory() 回调。
registerComponentCallbacks(new ComponentCallbacks2() {
@Override
public void onTrimMemory(int level) { //ComponentCallbacks2 比 ComponentCallbacks 多了这个回调方法
Log.i("bqt", "【onTrimMemory】" + level);
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
Log.i("bqt", "【onConfigurationChanged】");
}
@Override
public void onLowMemory() {
Log.i("bqt", "【onLowMemory】");
}
});
16
1
registerComponentCallbacks(new ComponentCallbacks2() {
2
3
public void onTrimMemory(int level) { //ComponentCallbacks2 比 ComponentCallbacks 多了这个回调方法
4
Log.i("bqt", "【onTrimMemory】" + level);
5
}
6
7
8
public void onConfigurationChanged(Configuration newConfig) {
9
Log.i("bqt", "【onConfigurationChanged】");
10
}
11
12
13
public void onLowMemory() {
14
Log.i("bqt", "【onLowMemory】");
15
}
16
});
2、registerOnProvideAssistDataListener 和 unregisterOnProvideAssistDataListener 方法
API18 以上的方法,网上关于这两个方法的介绍很少,几乎没有,在官网上的介绍是这样的:
This is called when the user is requesting an assist, to build a full ACTION_ASSIST Intent with all of the context of the current application.
好像是当用户请求帮助的时候会调用这个方法,然后会启动一个 ACTION_ASSIST 的 Intent。什么时候才是用户请求帮助呢?* 里有的人说是长按 Home 键,外国的机子会跳出 Google Now 这个助手,至于国内的机子...。然后尝试了一下用下面的代码来发送一个ACTION_ASSIST来看看有什么效果:
context.startActivity(new Intent(ACTION_ASSIST));
结果打开了我手机上UC浏览器的语音搜索功能。
最后还是搞不懂这个方法什么时候会回调,如果有知道的请告知,谢谢!
使用 Application 实现数据全局共享
可以在以下场景中使用 Application 实现数据全局共享:
-
可以设置一些全局的共享常量,如一些TAG,枚举值等。
-
可以设置一些全局使用的共享变量数据,如一个全局的Handler等等。但是要注意,这里缓存的变量数据的作用周期只在APP的生命周期,如果APP因为内存不足而结束的话,再开启这些数据就会消失,所以这里只能存储一些不重要的数据来使数据全APP共享,想要储存重要数据的话需要SharePreference、数据库或者文件存储等这些持久化本地存储方式。
-
可以设置一些静态方法来让其他类调用,来使用Application里面的全局变量,如实现APP一键退出功能时候会用到。
反射方式获取当前应用的 Application
public class App {
private static Application application;
private App() {
}
//通过反射方式获取当前应用的Application
@SuppressLint("PrivateApi")
public static Application get() {
if (application == null) {
try {
Class<?> clazz = Class.forName("android.app.ActivityThread");
Field field = clazz.getDeclaredField("sCurrentActivityThread");
field.setAccessible(true);
Object object = field.get(null);//得到ActivityThread的对象,虽然是隐藏的,但已经指向了内存的堆地址
Method method = clazz.getDeclaredMethod("getApplication");
method.setAccessible(true);
application = (Application) method.invoke(object);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
//没有自定义时为【android.app.Application】,自定义时为你设置的Application
Log.i("bqt", "当前应用的Application为:" + application.getClass().getName());
return application;
}
}
x
1
public class App {
2
private static Application application;
3
4
private App() {
5
}
6
7
//通过反射方式获取当前应用的Application
8
("PrivateApi")
9
public static Application get() {
10
if (application == null) {
11
try {
12
Class<?> clazz = Class.forName("android.app.ActivityThread");
13
Field field = clazz.getDeclaredField("sCurrentActivityThread");
14
field.setAccessible(true);
15
Object object = field.get(null);//得到ActivityThread的对象,虽然是隐藏的,但已经指向了内存的堆地址
16
Method method = clazz.getDeclaredMethod("getApplication");
17
method.setAccessible(true);
18
application = (Application) method.invoke(object);
19
} catch (ClassNotFoundException e) {
20
e.printStackTrace();
21
} catch (NoSuchFieldException e) {
22
e.printStackTrace();
23
} catch (NoSuchMethodException e) {
24
e.printStackTrace();
25
} catch (IllegalAccessException e) {
26
e.printStackTrace();
27
} catch (InvocationTargetException e) {
28
e.printStackTrace();
29
}
30
}
31
//没有自定义时为【android.app.Application】,自定义时为你设置的Application
32
Log.i("bqt", "当前应用的Application为:" + application.getClass().getName());
33
return application;
34
}
35
}
测试:
没有自定义Application时,当前应用的Application为:android.app.Application
自定义Application时,当前应用的Application为你所设置的Application:
public class MyApplication extends Application {
public static MyApplication application;
@Override
public void onCreate() {
super.onCreate();
application = this;
}
}
1
public class MyApplication extends Application {
2
public static MyApplication application;
3
4
5
public void onCreate() {
6
super.onCreate();
7
application = this;
8
}
9
}
Log.i("bqt", "" + (App.get() == MyApplication.application));//true,完全是同一个对象,使用时完全不用担心有bug
1
Log.i("bqt", "" + (App.get() == MyApplication.application));//true,完全是同一个对象,使用时完全不用担心有bug
2018-9-8