四大组件之
Activity的生命周期,启动
Intent和intentFilter
Service的生命周期,两种编程方式
BroadcastReceiver 广播接收者
ContentProvider内容提供者
--------------------------------------------------------------------------------
什么是Activity
a,布满整个窗口或者悬浮于其他窗口上的交互界面
b,一个应用程序中通常有一个或多个Activity构成
b,每个Activity都必须在AndroidManifest.xml中进行申明
c,多个Activity是通过栈进行管理,当前的活动的Activity在栈顶
d,在程序中自定义的Activity必须继承基类Activity
c,Activity有自己的生命周期,并且在不同的生命周期中会调用不同的函数
创建方法:
1.定义一个Activity的子类
2.重写onCreate()
3.定义一个布局视图
4.将布局视图关联给活动(界面)
5.注册活动子类到清单文件
四大组件之Activity的生命周期
class 人类{
出生方法(){}
上幼儿方法(){}
上小学(){}
上中学(){}
上大学(){}
工作1(){}
工作2(){}
找对象(){}
成家(){}
去世(){}
}
onCreate(): Activity开始被创建的时候被调用,
主要完成的任务:创建ui视图,绑定数据到list中
onStart(): 当Activity变成可视化的时候被调用,可见了,但还不是可交互的从后台切换到前台也会调用
此方法中可以去维护一些显示在Activity上的资源,比如可以注册一个BroadcastReceiver,
用于监控对UI产生影响的状态变化
比如ui上的内容发生变化,可以通过个BroadcastReceiver去广播
onResume: 获取到与用户交互的焦点,也可以认为是apk正在running
在这里可以做一些动画的播放,打开独占设备(比如相机)
onPause: 失去用户交互的焦点,但是视图还在,比如另外一个Activity切换到前台并获取到焦点时
(一个对话框出现,或者是休眠)
在这个方法中执行停止动画等比较耗CPU的操作,或者将需要永久化存储的数据进行保存,
因为有可能不会回来了
onResume和onPause会经常切换,所以里面的内容尽量的是轻量级的,以避免导致用户等待
onStop:表示当前Activity完全被其他的视图给占用了
onDestrory: 整个Activity完全销毁的时候,该方法中应该完成释放资源的操作
3个阶段和7个方法
开始阶段:onCreate, onStart, onResume
重新获取焦点: onRestart(); onStart();onResume;
关闭Activity: onPause, onStop,onDestory
Activity获得与失去焦点的循环:
onPause->onResume->onPause
Activity可见与不可见的循环
onStart->onRestart->onResume->onPause->onStop
整个生命周期:onCreate-->onDestory
可视周期:
onStart->onStop
焦点周期:
onResume->onPause
在 activity 被停止后重新启动时(调用打开过的应用程序)调用该方法。
其后续会调用 onStart 方法
onRestart()
总共7个
-------------------------------------------------
activity创建(onCreate)->可视化(onStart)->获取焦点(onResume)
|
来了一个电话
onPause(失去焦点)->onStop(失去视图)
|
接完电话,返回到app
onRestart(重新开始,针对恢复activity)->onStart(可视化)->onResum(获取焦点)
|
退出activity
onPause(失去焦点)->onStop(失去视图)->onDestroy(毁灭)
按下返回按键:onPause()->onStop()->onDestory()
长按Home键,弹出最近打开过的应用程序
按Home键:onPause()->onStop()
onRestart():启动一个另外一个Activity后,由另外一个Activity返回时
===============================================================================
启动Activity的方式:
1,startActivity();
a,启动一个自定义的Activity(显示的启动)
Intent intent = new Intent(); //创建一个Intent对象
intent.setClass(activity1.this, activity2.class); //描述起点和目标
startActivity(intent); //开始跳转
b,启动系统的Activity
String telString = "tel:13800138000";
final Uri telUri = Uri.parse(telString);
String data = "http://www.google.com";
final Uri webUri = Uri.parse(data);
Intent intent = new Intent(Intent.ACTION_VIEW, webUri);
startActivity(intent);
2,启动另外一个Activity并返回结果--实质也是通过Bundle实现
startActivityForResult(Intent, int requestCode);---------->
参数2:requestCode请求码,由程序员自行定义,用于标识请求来源
例如:一个Activity有两个按钮,点击这两个按钮会打开不同的Activity
不管哪个Activity关闭后,系统都会调用前面Activity的onActivityResult()
如果需要获取不同的Activity返回来的数据,那么可以通过该请求码进行识别
onActivityResult(int requestCode, int resultCode, Intent)<-----------------
----setResult(Int resultCode);
requestCode:用于区分到底是哪个请求
resultCode: 结果码
Intent:包含Bundle,里面有跟多信息
另外一个:
Intent data=new Intent();
data.putExtra("bookname", str_bookname);
data.putExtra("booksale", str_booksale);
setResult(20, data); //
3,启动activity的时候传递数据: intent作为中介(也可以理解为容器)
a,携带Bundle
1,构建Bundle
2,填入数据
bundle.putInt("键", 值); //普通数据
budle.putSerialize("键",对象);
3,将Bundle加入到Intent
putExtra(Bundle)
b,键值对
putExtra("键", 值);
c,获取数据
Intent intent = getIntent();
关闭Activity:
a,关闭当前的activity
finish();
b,关闭以startActivityForResult()方法启动的Activity
finishActivity(int requestCode);
========================================================================
intent的作用和使用
什么是intent?
a,为一个信息的载体,用于应用间的交互与通讯,对应用中一次操作的动作、动作涉及数据、附加数据进行
描述,Android则根据此Intent的描述,负责找到对应的组件,将Intent传递给调用的组件,并完成
组件的调用
b,Intent不仅可用于应用程序之间,也可用于应用程序内部的Activity/Service之间的交互
比如启动另外一个Activity,另外一个Service,还可以发送广播给BoardcastReciver
c,intent的属性--表示要做什么,带了一些什么信息
Intent主要有以下四个重要属性,它们分别为:
0,Component name:表示该intent是交给哪个具体的Component组件的(该对象是可选的,同时也可以不用intent-filter)
在代码中需要如下操作:
ComponentName comp = new ComponentName(xxx类.this, 另一个Activity的this);
Intent intent = new Intent();
intent.setComponent(comp);
StartActivity(Intent);
Action 和Category,在启动的组件中需要有intent-filter
1,Action:值为一个字符串,它代表了系统中已经定义了一系列常用的动作
a,系统自带的常量:ACTION_CALL,ACTION_EDIT
b,自定义的字符串,一般格式:"包名.类名.特定的字符"
2,Category:组件的类别,用于描述哪一类的组件可以处理该Intent,也是一个字符串,为Action添加的附加信息,通常会和Action结合使用
一个Intent只能指定一个Action,但可以指定多个Category
CATEGORY_DEFAULT :默认的category
CATEGORY_LAUNCHER:决定应用程序是否显示在程序列表里,表示在luncher中可否启动该组件
CATEGORY_BROWSABLE :在网页上点击图片或链接时,系统会考虑将此目标Activity列入可选列表,
供用户选择以打开图片或链接。比如有个网页链接,你的系统装了很多浏览器,此时会列举出多个打开方式
3,Data:Android中采用指向数据的一个URI来表示,如在联系人应用中,
对于不同的动作,其URI数据的类型是不同的(可以设置type属性指定特定类型数据),
如ACTION_EDIT指定Data为文件URI,打电话为tel:URI,访问网络为http:URI,
而由content provider提供的数据则为content: URIs。一个指向某联系人的URI可能为:content://contacts/1。
4,Extras:Extras属性主要用于传递目标组件所需要的额外的数据。通过putExtras()方法设置。常用于在多个Action之间进行数据交换
public void invokeWebSearch(View view) {
Intent intent = new Intent(Intent.ACTION_WEB_SEARCH);
intent.putExtra(SearchManager.QUERY, "android"); //关键字
startActivity(intent);
}
以上一般比较重要的是:
action
data (both URI and data type)
category
Intent被解析的过程:显示intent和隐式intent
显示intent:明确指定需要启动或者触发的组件的类名,常用于启动当前应用程序的不同组件
类似与找人: 找章子怡
隐式intent:指定需要启动或者触发的组件应满足怎样的条件,常用于启动其他应用程序中的组件
也就是说系统会对intent进行解析,解析出它的条件
然后再在系统中查找与之匹配的目标组件
而被调用或目标组件需要通过intentfilter来声明自己满足条件
类似与找人: 穿红衣服的女孩
Intent-filter:组件的意图过滤器,
a,其实是一个对象,但是一般不会直接去创建,都是在AndroidManifest.xml中存在
b,一个组件中可以有多个Intent-filter,可以根据过滤不同的intent而采取不同的处理
c,过滤的时候会过滤三个域:action,data,category,任何intent必须成功经过这三道过滤,缺一不可
Action test:至少有一个
<intent-filter . . . >
<action android:name="com.example.project.SHOW_CURRENT" />
<action android:name="com.example.project.SHOW_RECENT" />
<action android:name="com.example.project.SHOW_PENDING" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
必须添加一个android.intent.category.DEFAULT
c,隐式的启动:
在intent添加过滤器intentfilter
<activity <!--被启动的Activity -->
android:name="com.example.android.tst.SecondActivity"
android:label="@string/title_activity_main" >
<intent-filter>
<action android:name="com.example.android.tst.SecondActivity"/>
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
启动方法:
Intent intent=new Intent("com.example.android.tst.SecondActivity");
//或者如下操作
//intent.setAction( "com.example.android.tst.SecondActivity");
//intent.addCategory(Intent.CATEGORY_DEFAULT);
startActivity(intent);
解释:
发送了这个intent之后,android会去系统里保存的MainManifest.xml里查找符
合这两个属性的activity,
任何一个需要隐式启动的Activity都必须要有这项:
<category android:name="android.intent.category.DEFAULT"/>
==========================================================================
Service在Android中和Activity是属于同一级别上的组件
Activity仪表不凡,迷倒万千少女
Service身强力壮,但是在后台做一些搬运工的力气活
后台运行
Service的特性:
1, 拥有后台运行的特性,比如将屏幕关闭后,继续运行
2,不是一个独立的进程,除非特别指定(存在于一个进程中)
3,它不是一个线程
4,服务是一种 应用程告诉系统它想在后台要做的某个事情 的工具,并将功能提供(暴露)给其它应用程序
Service的应用场合:
从播放列表播放音乐,播放器有一些activities来叫用户选定歌曲并开始播放。但是,播放本身不需要activity处理,因为用户希望关闭activity
后歌曲会继续播放。因此media player 的activity 会启动一个service
Service和Thread的区别:
1,Thread 是程序执行的最小单元,它是分配CPU的基本单位,而Service是一个组件,你也可以认为是应用程序的一个插件
这个插件能完成后台的操作
2,Service其实是运行在主线程中的,如果需要执行复杂耗时的操作,必须在Service中再创建一个Thread来执行任务
3,Service的优先级高于后台挂起的Activity,当然,也高于Activity所创建的Thread,因此,系统可能在内存不足的时候优先杀死后台
的Activity或者Thread,而不会轻易杀死Service组件,即使被迫杀死Service,也会在资源可用时重启被杀死的Service
4,Thread只是一个用来执行后台任务的工具类,它可以在Activity中被创建,也可以在Service中被创建。
所以不需要去疑惑使用Service还是Thread,而是应该讨论在什么地方创建Thread。
Service的两种启动方式:
context.startService()-- 对应于Local Service(本地服务,调用和实现在同一个进程)
依附在主进程上而不是独立的进程,这样在一定程度上节约了资源,另外Local服务因为是在同一进程因此不需要IPC
主进程被Kill后,服务便会终止。
context.bindService()-- 对应于Remote Service(远程服务,调用和实现不在同一个进程)
由于是独立的进程,因此在Activity所在进程被Kill的时候,该服务依然在运行,不受其他进程影响,有利于为多个进程
提供服务具有较高的灵活性。该服务是独立的进程,会占用一定资源,并且使用AIDL进行IPC稍微麻烦一点
Service的生命周期:
本地服务:
启动一个Service的过程
context.startService() ->onCreate()->onStartCommand()->Servicerunning
startService()在Activity中启动服务,实际是并实例化了一个Service实例
onCreate() 进行一些服务的初始化工作,比如可以创建一个线程用于播放音乐
onStartCommand():服务正常运行时,能够处理Intent,如果多多次启动服务,该方法会被调用
在以前的版本该方法为onStart();onStartCommand()内部会被调用,已经过时了
停止一个Service的过程:
context.stopService() ->onDestroy() ->Service stop
Activity调用这即使结束了自己的生命周期,只要没有使用stopService方法停止这个服务,服务仍会运行
远程服务: 远程服务其实就是给外部apk提供各种接口
启动一个Service的过程
context.bindService()-->onCreate()-->onBind()-->Servicerunning
onBind():当绑定成功时,该方法被调用,并且需要返回一个binder接口的实例
如果重复绑定,该方法只会执行一次
停止一个Service的过程:
context.unbindService()-->onUnBinde()-->onDestroy()-->Service stop
bindService模式下服务是与调用者生死与共的,在绑定结束之后,一旦调用者被销毁,服务也就立即终止,
就像江湖上的一句话:不求同生,但愿同死,当然罗,如果要继续用服务,再bind就好了, 服务会跟着运行起来的
aidl: 实际是一个工具,帮我们自定生成一些代码,完成进程调度的细节代码
只需要定义好service段和调用端直接的接口就可以了
package com.hq.service;
interface IService{ //一定要文件的名字保持一致,文件名一定要是aidl的后缀
int add(int a, int b);
int sub(int a, int b);
}
1,在服务端里实现接口:
public class MyService extends Service{
public IBinder onBind(Intent arg0)
{
// TODO Auto-generated method stub
Log.i(TAG, "------onBind--------");
//如果需要绑定成功,就一定要返回一个binder的子类
return new IServiceImpl();
}
// 实现用户提供的接口,定义一个内部类
public class IServiceImpl extends IService.Stub{
public int add(int a, int b) throws RemoteException
{
// TODO Auto-generated method stub
return a+b;
}
@Override
public int sub(int a, int b) throws RemoteException
{
// TODO Auto-generated method stub
return a-b;
}
}
}
2,在client中进行调用:
bindService(intent3, serviceConnection, Service.BIND_AUTO_CREATE); //启动服务
//参数2: 当绑定成功之后,需要做的事情:
private ServiceConnection serviceConnection = new ServiceConnection(){
public void onServiceConnected(ComponentName name, IBinder iBinder){
//通过IService中将ibider统一的接口转换成自己定义的接口对象
serviceManager = IService.Stub.asInterface(iBinder);
serviceManager.add(34, 56) //直接调用
}
}
MediaPlayer media;
media = MediaPlayer.create(MyService.this,R.raw.nobody);
media.start();
media.stop();
------------------------------------------------------------------------------------------------------------------------------------
BroadcastReceiver也就是“广播接收者”的意思,顾名思义,它就是用来接收来自系统和应用中的广播
广播体现在方方面面,例如
当开机完成后系统会产生一条广播,接收到这条广播就能实现开机启动服务的功能;
当网络状态改变时系统会产生一条广播,接收到这条广播就能及时地做出提示和保存数据等操作;
当电池电量改变时,系统会产生一条广播,接收到这条广播就能在电量低时告知用户及时保存进度,等等。
广播的发送:
普通广播:
对于多个接收者来说是完全异步的,通常每个接收者都无需等待即可以接收到广播,接收者相互之间不会有影响。对于这种广播,
接收者无法终止广播, 即无法阻止其他接收者的接收动作。
sendBroadcast(intent);
abortBroadcast();
有序广播:
它每次只发送到优先级较高的接收者那里,然后由优先级高的接受者再传播到优先级低的接收者那里,优先级高的接收者有能力终止这个广播
sendOrderedBroadcast(intent, "george.permission.MY_BROADCAST_PERMISSION");
参数中有个权限,所以
在AndroidMainfest.xml中定义一个权限:
<permission android:protectionLevel="normal"
android:name="george.permission.MY_BROADCAST_PERMISSION" />
如果要发送广播,必须要获取到这个权限:
<uses-permission android:name="george.permission.MY_BROADCAST_PERMISSION" />
过滤器的配置:
1,静态:在AndroidManifest.xml文件中配置,这种方式的注册是常驻型的,也就是说当应用关闭后,
如果有广播信息传来,MyBroadCastReceiver也会被系统调用而自动运行
<receiver android:name="com.hq.component.broadcast.MyBroadCastReceiver" >
<intent-filter android:priority="999" >
<action android:name="broadcast.MyBroadCastReceiver" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
2,动态:在代码中动态的指定广播地址并注册,通常我们是在Activity或Service注册一个广播
不是常驻型的,也就是说广播会跟随程序的生命周期
private ThirdBroadCastReceiver receiver = null;
//新建一个广播接收器
receiver = new ThirdBroadCastReceiver();
//新建一个过滤器
IntentFilter filter = new IntentFilter();
filter.addAction("broadcast.MyBroadCastReceiver");
filter.setPriority(997);
//为广播接受器注册一个过滤器
registerReceiver(receiver, filter);
广播的接收:
普通广播:
intent.getExtras();
有序广播:
接受
String extraStr = getResultExtras(true).getString("passMsg");
继续传播:
// 给下个广播接受者传递广播
Bundle bundle = new Bundle();
bundle.putString("passMsg", intentStr + "from @SecondBroadCastReceiver");
setResultExtras(bundle);
停止传播:
abortBroadcast();
网友评论