第一章 四大组件
一、四大组件的简单介绍
- activity负责UI页面跳转代表着一个页面单元。
- service 负责与UI无关操作,耗时操作(需要再其中另开线程执行耗时操作)
- Broadcast 各个应用组件中进行通讯,简化通信问题
- ContentProvider 储存,共享数据,多应用共享
1.Activity的singleInstance启动模式,在同一时刻系统中只存在一个Activity实例
2.Fragment在Android3.0后引入了Fragment,其需要被嵌套在Activity中进行使用,它作为一个更大粒度的UI单元。如果需要在低于android3.0的系统上使用,则需要导入android-support-v4包。
3.Service默认也是执行在UI线程中,所以不要在Service中执行耗时操作除非在其中新建了线程来执行耗时操作。
4.Service中onCreate只会调用一次,当多次调用startService时,onStartCommand会被调用多次,但实际上每个服务都会只存在一个实例,无论调用了多少次startService()方法。
5.当Service运行起来后,需要通过stop-Service()或stopSelf()方法来停止服务,Service不会自动停止。
6.IntentService适用于短期的耗时操作,自带子线程功能,用户只需要重写其内部的onHandlerIntent方法即可,在其中执行耗时操作即可。并且IntentSelf执行完毕后会自动调用stopSelf方法来自我销毁。
7.前台服务的启动方式startForeground(NOTIFY_ID,notifycation);
二、AIDL(接口描述语言)
AIDL就是定义一个接口,客户端(调用端)通过bindService来与远程服务端建立一个连接,在该连接建立时,会返回一个IBinder对象,该对象是服务端Binder的BinderProxy,在建立连接时,客户端通过asInterface方法将该BinderProxy对象包装成本地的Proxy,并将远程调用服务端的BinderProxy对象赋值给Proxy类的mRemote字段,就是通过mRemote来执行远程函数的调用。
代码实例如下:
//调用端
// SsoAuth.aidl
package com.example.zero.testaidl;
interface SsoAuth {
//默认生成的方法
void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
double aDouble, String aString);
//自定义方法
void ssoAuth(String username,String pwd);
}
客户端创建好SsoAuth.aidl后,ReBuild项目,即可自动生成SsoAuth.java文件
其代码如下:
package com.example.zero.testaidl;
// Declare any non-default types here with import statements
public interface SsoAuth extends android.os.IInterface
{
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements com.example.zero.testaidl.SsoAuth
{
private static final java.lang.String DESCRIPTOR = "com.example.zero.testaidl.SsoAuth";
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.example.zero.testaidl.SsoAuth interface,
* generating a proxy if needed.
*/
public static com.example.zero.testaidl.SsoAuth asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.example.zero.testaidl.SsoAuth))) {
return ((com.example.zero.testaidl.SsoAuth)iin);
}
return new com.example.zero.testaidl.SsoAuth.Stub.Proxy(obj);
}
@Override public android.os.IBinder asBinder()
{
return this;
}
@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
{
switch (code)
{
case INTERFACE_TRANSACTION:
{
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_basicTypes:
{
data.enforceInterface(DESCRIPTOR);
int _arg0;
_arg0 = data.readInt();
long _arg1;
_arg1 = data.readLong();
boolean _arg2;
_arg2 = (0!=data.readInt());
float _arg3;
_arg3 = data.readFloat();
double _arg4;
_arg4 = data.readDouble();
java.lang.String _arg5;
_arg5 = data.readString();
this.basicTypes(_arg0, _arg1, _arg2, _arg3, _arg4, _arg5);
reply.writeNoException();
return true;
}
case TRANSACTION_ssoAuth:
{
data.enforceInterface(DESCRIPTOR);
java.lang.String _arg0;
_arg0 = data.readString();
java.lang.String _arg1;
_arg1 = data.readString();
this.ssoAuth(_arg0, _arg1);
reply.writeNoException();
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements com.example.zero.testaidl.SsoAuth
{
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote)
{
mRemote = remote;
}
@Override public android.os.IBinder asBinder()
{
return mRemote;
}
public java.lang.String getInterfaceDescriptor()
{
return DESCRIPTOR;
}
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
@Override public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeInt(anInt);
_data.writeLong(aLong);
_data.writeInt(((aBoolean)?(1):(0)));
_data.writeFloat(aFloat);
_data.writeDouble(aDouble);
_data.writeString(aString);
mRemote.transact(Stub.TRANSACTION_basicTypes, _data, _reply, 0);
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
@Override public void ssoAuth(java.lang.String username, java.lang.String pwd) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeString(username);
_data.writeString(pwd);
mRemote.transact(Stub.TRANSACTION_ssoAuth, _data, _reply, 0);
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
}
static final int TRANSACTION_basicTypes = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_ssoAuth = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
}
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException;
public void ssoAuth(java.lang.String username, java.lang.String pwd) throws android.os.RemoteException;
}
将客户端的aidl文件夹拷贝到被服务端(被调用端),服务端与客户端的aidl的包名,类名完全一致,生成的aidl也完全一致,所以Rebuild服务端后也会生成相同的SsoAuth.java文件
客户端通过Service(Service是一个外壳,包含着Stub的子类,在onBind方法中返回子类对象)进行调用:
public class SinaSsoAuthService extends Service {
SinaSsoImpl mBinder = new SinaSsoImpl();
@Override
public void onCreate() {
super.onCreate();
Log.d(this.getClass().getSimpleName(), "---onCreate");
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
Log.d(this.getClass().getSimpleName(), "---onBind");
return mBinder;
}
class SinaSsoImpl extends SsoAuth.Stub {
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
}
@Override
public void ssoAuth(String username, String pwd) throws RemoteException {
Log.d("mjc", "这里是新浪微博,用户名:" + username + ",密码:" + pwd);
}
}
}
需要在Manifest中对Service进行注册,重要的是意图过滤器的书写:
<intent-filter>
<action android:name="com.example.zero.testaidlservice.SinaSsoAuthService"/>
</intent-filter>
在客户端完成调用服务端的代码:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initWidgets();
}
public void initWidgets() {
btnStart = (Button) findViewById(R.id.btnStart);
btnStart.setOnClickListener(this);
}
@Override
public void onClick(View v) {
if (ssoAuth == null) {
bindSsoService();
} else {
doSsoAuth();
}
}
private void bindSsoService() {
Intent intent = new Intent();
intent.setAction("com.example.zero.testaidlservice.SinaSsoAuthService");
intent.setPackage("com.example.zero.testaidlservice");
bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
}
ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
try{
ssoAuth = SsoAuth.Stub.asInterface(service);
doSsoAuth();
}catch (Exception e){
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
ssoAuth = null;
}
};
private void doSsoAuth() {
try {
ssoAuth.ssoAuth("Mr.ma", "123321");
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(serviceConnection);
}
这一切的核心都是AIDL中生成的Stub类及其背后的Binder机制。
Proxy模式暂时不了解,所以对于自动生成的SsoAuth.java文件不做详细分析,同时其中使用了Parcel,也应该了解下其用法。有待补充。
三、Broadcast
1.分类
- 普通广播:执行顺序不确定,接收者之间不能传递处理结果,中途不能停止传播,直到没有接收器时才能停止广播,传播效率比较高。
- 有序广播:sendOrderBroadcast()方法来发送有序广播。有序广播的优先级可以通过receiver中的android:priority属性来设定,数值越大,越优先接受到广播,有序广播可以在中途停止(不在向下进行传递广播),方法为abrotBroadcast();可通过setResultData(String data)和setResultExtras(Bundle extras)方法来向下一级传递数据,相应的下一级接收器通过getResultData()及getResultExtras(boolean makeMap)来获取上一级传递来的数据。
本地广播:在21版的v4包中新增了本地广播,之前所有的广播都是所有应用都可以接收到的,肯呢个存在安全隐患,(虽然在设定intent-filter 中的action时都使用了公司的域名等级制)。具体方法:
sticky广播:发送广播后,一直滞留(同一时刻仅能有一条广播存在),当已经存在一条,再次发送新的一条时,应该先调用removeStickyBroadcast()再发送。发送方法:sendStickyBroadcast()。sticky广播需要权限android.permission.BROADCAST_STYCKY
2. 广播的注册方式
①静态注册,在AndroidManifest.xml文件中进行注册
②动态注册
registerReceiver(new TestReceiver(),strAction);
//发送广播时
sendBroadcast(new Intent(strAction));
//动态注册时,需要动态销毁广播。
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(netWorkChangeReceiver);
}
3.本地广播的相关方法
“`
Public Methods
static LocalBroadcastManager getInstance(Context context)
void registerReceiver(BroadcastReceiver receiver, IntentFilter filter)
boolean sendBroadcast(Intent intent)
void sendBroadcastSync(Intent intent)
void unregisterReceiver(BroadcastReceiver receiver)