Application应用程序
2016-05-16 14:07
363 查看
第1节 应用的基本概念
我们常说的“安卓应用”可能有三种不同的概念:软件,能够完成一个特定功能的软件。例如“安装一个应用”、“这个应用可以帮助你寻找附近的美食”。
安装包,应用的实体,是我们摸得着、看得见的APK包,是一个很具体的东西。
应用运行起来后在内存中存在的形态。安装在设备上的APK文件在系统中运行起来就是Application。Android应用开发中,常说的Application就是它。它就是Android SDK中的
Application类。
在讨论程序的开发、执行、存在周期的时候,我们说的
Application就是第三种意思。
第2节 Android四大组件
Activity、
Service、
ContentProvider与
BroadcastReceiver被称作Android应用的四大组件,它们分别对应着一个应用程序可能用到的表现形式。
2.1 Activity
这是应用的显示组件。通常来讲,我们能看到的设备上的内容,除了状态栏(statusbar)、导航栏(navigation bar)、锁屏界面,凡是显示出来的内容都属于Activity。
(为了便于理解,这里讲的是大多数情况,一些窗口类型的界面–例如popupwindow,toast,输入法、壁纸等等,不应该称作Activity。)
Activity中显示的是一个应用希望呈现给用户的内容。我们开发的应用基本上一定会有一个
Activity,用来向用户展示我们希望呈现的内容。例如电话拨号界面,设置界面,日历界面。
2.2 Service
这是应用可以在后台运行的服务组件,不需要有用户看得见的界面。它通常需要和Activity配合,借助
Activity给用户提供控制的界面。
最典型的例子就是音乐播放器。音乐播放器的界面就是一个提供了音乐控制方式的
Activity,当我们点击
Activity上的播放按钮之后,
Activity通知播放器的
Service组件,让
Service组件开始播放音乐;之后即使用户选择退出了音乐播放器的
Activity界面,音乐仍然在被播放着,没有随着界面的退出而停止播放。
2.3 ContentProvider
这是一个应用的数据存储组件。在Android系统中,出于数据安全的考虑,应用之间是被严格的隔离的,应用A不能访问到应用B的数据。但是如果应用B使用了ContentProvider组件,就能让应用A通过Android系统制定好的规则获取到应用B愿意提供的数据了。
它就像是一个拥有某种数据的网站,安卓系统运行的其它组件可以通过“网址”访问这个网站,获取需要查询的数据。
ContentProvider可以是私有的,只能为它所在的应用提供数据访问请求;
ContentProvider也可以是公开的,为别的应用程序提供数据访问请求。
2.4 BroadcastReceiver
这是应用获取系统或者获取某些应用发出特定消息的组件。例如,有个应用叫“换壁纸”,它希望设备开机完成后,自动更换桌面壁纸。可是开机后“换壁纸”还没有运行起来,用户也不会主动的告诉“换壁纸”“手机已经启动了,换一张壁纸吧”。
这时,就可以通过BroadcastReceiver组件获取开机完成后系统主动发出的“开机完成通知”。得到“通知”后,“换壁纸”就可以按照预想设计工作了。
BroadcastReceiver组件有个特点,就是包含它的应用不一定要正在运行,系统可以根据“通知”类型,先把这个“通知”告诉关注它的
BroadcastReceiver,由
BroadcastReceiver决定是否需要启动一个Activiy或者Service来做相应的处理。
第3节 Intent初步
如果将Activity、
Service与
BroadcastReceiver这些组件比喻成一座一座的岛屿,那么Intent就是穿梭于这些小岛之间的小船。
从主界面启动Activity,需要通过Intent;
在Activity里面启动另一个Activity,也需要通过Intent;
启动Service需要通过Intent;
BroadcastReceiver被唤醒,也是通过Intent。
Intent不仅能将这些组件联系了起来。Intent也能穿梭于各个应用之间,把它们也联系起来。
3.1 创建Intent
在创建Intent的时候,可以使用下面的方式指定小船的目的地。就像给某个机构发货,只需要发送给某个机构,但不需要知道这个机构中具体是哪个人。
//action_name可以指定那一类组件可以收到这个Intent发出的请求 Intent i = new Intent("action_name");
就像发货时写下接收方具体的名字和地址。
Intent i = new Intent(); i.setClassName("接收方的包名", "接收方的类名");
3.2 携带数据
小船可以携带货物,Intent也可以携带各种类型的数据。在创建Intent对象后,使用如下的方法,你就可以把想要在“岛屿”之间传递的数据放到小船上。Intent i = new Intent(); i.putExtra("索引关键字",goods);
这些数据包括
String、
char、
long、
int、
boolean、
float、
double、
byte等等常用的基本类型,也包括它们的数组。甚至还能传递
自定义类封装的对象。
不过要传递
自定义类封装的对象,需要这个类做特殊的处理,
继承了
Serializable接口,
class data implements Serializable { } Intent i = new Intent(); i.putExtra("DATA", new data());
继承了
Parcelable接口,
class data implements Parcelable { @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { } } Intent i = new Intent(); i.putExtra("DATA", new data());
Parcelable的性能要比
Serializable好很多,传输的效率要高上10倍左右;但是
Parcelable需要开发者自己定义数据序列化和反序列化的规则,所以编码量比使用
Serializable要大很多。
在实际的开发场景中要根据实际的情况作选择。
第4节 Manifest初步
在应用工程的源码目录下,都有一个AndroidManifest.xml文件,它是这个应用的配置文件,当应用安装到设备上后,Android系统会从这个文件中获取很多关于这个应用的配置信息。Manifest文件内容,大体如下:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.anddle.activitytest"> <uses-permission /> <permission /> <permission-tree /> <permission-group /> <instrumentation /> <uses-sdk /> <uses-configuration /> <uses-feature /> <supports-screens /> <compatible-screens /> <supports-gl-texture /> <application android:icon="@mipmap/ic_launcher" android:name=".MyApplication"> <activity android:name=".MainActivity"/> <service android:name=".MyService"/> <provider android:name=".MyContentProvider" android:authorities="com.anddle.authoriteies"/> <receiver android:name=".MyReceiver"/> </application> </manifest>
不是所有的项都需要在Manifest文件中使用,通常只会用到最常用的。
4.1 application标签
应用使用了哪些组件,都要在这个配置文件中登记。不然在程序启动这些组件的时候,系统会找不到它们,导致程序崩溃。<application android:icon="@mipmap/ic_launcher" android:name=".MyApplication"> <activity android:name=".MainActivity"/> <service android:name=".MyService"/> <provider android:name=".MyContentProvider" android:authorities="com.anddle.authoriteies"/> <receiver android:name=".MyReceiver"/> </application>
4.2 uses-permission标签
这个应用要使用系统的哪些权限,也要在这个配置文件中声明。这样在安装的时候,系统会根据填写的内容,告诉用户,让用户判断是否接受应用使用这些系统的功能。例如,一个应用要读取磁盘存储器上的内容,就需要申请权限,如果用户同意,才能成功读取磁盘。
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
第5节 Task、Application与四大组件的关系
5.1 Task
在Android系统中,很多模块是互用的。例如当我们启动“相机”拍摄了一张照片,然后通过“图库”浏览刚拍的照片,最后选择“微信”将照片分享出去。为了实现这一些列的操作,达到我们希望的目的,整个过程就利用了3个不同应用,分别使用了它们对应的Activity。我们将使用到的这些Activity串在一起,称作Task。它们就像一个叠叠乐,后启动的放在另一个的上面–我们给这个叠叠乐一个专业的术语–栈。Task中包含的Activity是以栈的形式存放的。
假如此时,我们按返回按钮一步一步返回,Task中位于顶部的Activity就被一步一步退出,直到退出这个Task中所有的Activity,然后回到了系统主界面。
假如此时,我们按home按钮,就会返回到系统主界面,同时将这个Task保存下来。如果你再启动主界面上的另一个应用,一个新的Task就会被建立起来。
通过上面的描述,我们可以知道:Task只和Activity有关。
另外,Task可以在系统中存在多个,例如启动应用A,创建Activity A,这里就有一个Task A了;然后按“home”键返回,再启动应用B,创建Activity B,这里就有一个Task B了;以此类推,会有Task C Task D。
不过运行在最前台的只有一个Task,这就是前台Task。其他的Task都是后台Task。
5.2 Application与组件的关系
站在系统的角度看,Application就是运行着组件的那个线程环境。这个线程环境中运行着正在工作的组件---即那些在它Manifest中声明了的、正运行着的组件。以上面微信分享照片的task作为例子。相机应用:虽然没有被看见,但它还有Activity存在着,它运行的线程环境还存在着,所以这个application正在运行着;
图片浏览应用:虽然没有被看见,但它还有Activity存在着,它运行的线程环境还存在着,所以这个application正在运行着;
微信应用:很明显,它有Activity运行着,它运行的线程环境存在,所以这个application正在运行着;可以想象微信一定有个正在后台接受网络发送了消息的Service 。这个Service也是application的一部分--因为他们在同一个线程当中(这种说法并不严谨,如果Service被指定了在单独的进程中运行,那么application就不是同一个了。不过这里为了举一个贴近实际场景的例子,就没有去做详细的区分了);
Application可以看做是这些组件的集合,是这些组件对外共同的名字。
Application被运行起来的情况有:
Activity被启动,显示出一个界面;
service被启动,在后台默默的运行;
其他应用开始访问自己提供的ContentProvider;
BroadcastReceiver收到了一个“消息”;
站在系统的角度看,当应用运行起来时,系统为这个应用创造了一个线程环境,这个线程环境就是Application,那些组件运行的环境都在这个线程当中。
由此可知,Application是一个安装应用的入口。不过通常来讲,在通过Android Studio创建工程的时候,并没有给我们指出这个Application,而是使用了系统默认的Application。
另外Android Studio还为我们创建了一个Activity。这多少会让我们误以为Activity才是应用程序被最早启动的地方。
要自己定义应用的Application环境,首先要在代码中继承Application类。这里列出了一部分可以被覆盖的Application类方法。
public class MyApplication extends Application { @Override public void onCreate() { super.onCreate(); } @Override public void onLowMemory() { super.onLowMemory(); } @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); } @Override public void onTerminate() { super.onTerminate(); } @Override public void onTrimMemory(int level) { super.onTrimMemory(level); } }
这里的
onCreate()函数才是一个应用被启动的第一个地方(而非Activity的onCreate())。
创建Application类后,我们要再manifest文件中,指明我们的应用要使用这个自定义的Application:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.anddle.activitytest"> ...... <application android:icon="@mipmap/ic_launcher" android:name=".MyApplication"> -->指定我们自定义的Application </application> </manifest>
如果这里不指定
android:name,那么系统将使用默认的Application。
不是所有的应用都需要使用自定义的Application,对于那些有很多组件(Activity Service等等)都需要做相同初始化都应用,就可以使用它。
例如,有个应用包含一个Activity和一个Service,无论是哪个先启动,都首先要去做一个共同的操作。这种情况就可以考虑把那个共同的操作放到Application中进行。
Application还可以作为各个组件共享变量和数据的仓库。
Activity和Service都是有生命周期的,一旦生命结束,它们保存的一些数据就会被释放掉。但是它们的生命结束了,不代表Application的生命结束了(Application是整个应用的生命)。为了其他组件还能继续使用这些数据,我们就可以把数据放着这个生命更长的Application中。
相关文章推荐
- android 输入法弹出键盘把listview顶上去,保留顶部标题栏位置不动
- iOS 9适配技巧
- jQuery动态表格插件 AppendGrid
- iOS 二维码扫描
- 微信 错误码:40018,错误提示:invalid button name size
- 微信 错误码:40018,错误提示:invalid button name size
- Android Studio添加assets文件夹
- LayoutParams继承于Android.View.ViewGroup.LayoutParams.
- iOS开发中APP跳转
- Android Studio你不知道的调试技巧
- Unity uGui RawImage 渲染小地图
- android 进入页面时让焦点固定在顶部
- iOS常见警告和错误集锦
- android 开发奇葩问题
- Android 打开URL
- 解决Android输入法不隐藏的问题
- [swift学习之十一]协议语法练习
- Android手势锁实现
- category使用 objc_setAssociatedObject/objc_getAssociatedObject 实现添加属性
- windows平台下Tuxedo应用simpapp编译失败问题解析