Activity篇
生命周期篇
整个生命周期:
Activity完整生命周期发生在onCreate()和onDestroy()之间。在onCreate()中执行一些全局性的设置(例如设置布局文件,初始化View等等),在onDestroy()中释放所有资源
可见生命周期:
Activity可见生命周期发生在onStart()和onStop()之间,在这段时间内,用户可以在屏幕上看见Activity并与之交互。在整个生命周期,Activity对用户可见和隐藏两种状态可能交替出现,系统就会多次调用onStart()和onStop()方法。
前台生命周期:
Activity的前台生命周期发生在onResume()和onPause()之间,在这段时间内,Activity位于屏幕上其他Activiy之前,而且获取屏幕的焦点。Activity可能频繁的转入或转出前台,例如当设备休眠或者弹出对话框时,系统会调用onPause()方法。因为此状态可能经常发生变化,所以在这两个方法中建议做一些轻量级操作。
图例如下

多Activity之间生命周期影响
当一个activity(A)启动的时候:
onCreate()->onStart()->onResume().
启动第二个Activity(B)并且完全遮挡住A的时候。A会先执行
onPause()->onStop()
如果此时点击back返回按钮,A会执行
onRestart()->onStart()->onResume().
没有完全遮挡住A的时候,A只会执行onPause方法,比如说弹出一个对话框,dialog之类的,最典型的是打电话界面。当用户点击返回的时候,A会执行onResume方法,如下所示,执行。
onPause()->onResume()
Activity回收
在系统回收的activity里面恰好有存放的数据,
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
}
然后在oncreate恢复
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(savedInstanceState!=null){}
}
启动模式篇
standard
默认为该种启动模式,特点就是每当发送一个intent请求打开该activity时,都会创建一个新的activity实例
应用方式如下:
*本应用打开,新创建的activity实例放入本应用,即发送intent的task栈的顶部,这个比较简单
*跨引用打开,这里5.0之前和之后的处理方式是不一样的,5.0之前是和本应用打开效果一样,5.0之后的跨应用打开是会创建一个新的task栈去处理
singleTop
如果调用的目标Activity已经位于调用者的Task的栈顶,则不创建新实例,而是使用当前的这个Activity实例,并调用这个实例的onNewIntent方法。
场景比较少,可以使用的例子比如用户已经在当前activity,用户点击一条推送消息之后也需要跳转到当前activity,那么为了避免activity的重复打开,则需要将该activity设置为singleTop并且复写onNewIntent即可。
如果是外部程序启动singleTop的Activity,在Android 5.0之前新创建的Activity会位于调用者的Task中,5.0及以后会放入新的Task中,这点和standard一样。
singleTask
使用singleTask启动模式的Activity 在系统中 只会存在一个实例。如果这个实例已经存在,intent就会通过onNewIntent传递到这个Activity,并且将栈中该activity之上的activity清除(销毁过程会调用Activity生命周期回调),如果不存在新的Activity实例将被创建。
应用场景:
本应用启动,在一个应用中启动设置为singleTask的activity,如果该activity在task栈中不存在,则会创建一个新的实例放在栈顶,如果在activity的task栈中已经存在了该activity实例,则会将栈中该activity实例之上的其他activity实例清空,并且会调用该activity的onNewIntent方法。最常用的使用例子就是首页,比如首页上面已经有了很多的activity,回到首页就可以使用这种方式,然后复写首页的onNewIntent方法。使用提示:onNewIntent方法中不能进行fragment的相关操作
跨应用启动,由于整个系统只能存在activity的一个实例,所以如果系统中不存在该activity,则会启动一个新的task去启动该activity,并且将该activity放入栈底。如果系统中存在该activity实例,则会直接启动该activity,调用该activity的onNewIntent的方法,同时将该activity task栈上面的其他activity清空(销毁过程会调用Activity生命周期回调),此时如果用户摁下返回键,那么将在singleTask activity的task栈中操作,即返回该栈中singleTask activity的上一个activity直到该栈中无activity时才会返回到最开始启动singleTask activity的activity中。还有一种情况是singleTask Activity所在的应用进程存在,但是singleTask Activity实例不存在,那么从别的应用启动这个Activity,新的Activity实例会被创建,并放入到所属进程所在的Task中,并位于栈顶位置。
singleInstance
在系统中 只会存在一个实例,唯一的区别就是系统不会在singleInstance activity的task栈中启动任何其他的activity,singleInstance activity栈中仅仅只能有该activity的实例,其他任何从这个activity启动的activity都会在其他的栈中被打开。
Service篇
启动模式篇
Services有两种启动形式:
Started:
其他组件调用startService()方法启动一个Service。一旦启动,Service将一直运行在后台(run in the background indefinitely)即便启动Service的组件已被destroy。通常,一个被start的Service会在后台执行单独的操作,也并不给启动它的组件返回结果。比如说,一个start的Service执行在后台下载或上传一个文件的操作,完成之后,Service应自己停止。
一般使用如下两种方式创建一个start Service:
继承Service类:请务必在Service中开启线程来执行耗时操作,因为Service运行在主线程中。
继承IntentService类:IntentService继承于Service,若Service不需要同时处理多个请求,那么使用IntentService将是最好选择:您只需要重写onHandleIntent()方法,该方法接收一个回传的Intent参数,您可以在方法内进行耗时操作,因为它默认开启了一个子线程,操作执行完成后也无需手动调用stopSelf()方法,onHandleIntent()会自动调用该方法。
start方式一次onCreat后只onStartCommand
Bound:
其他组件调用bindService()方法绑定一个Service。通过绑定方式启动的Service是一个client-server结构,该Service可以与绑定它的组件进行交互。一个bound service仅在有组件与其绑定时才会运行(A bound service runs only as long as another application component is bound to it),多个组件可与一个service绑定,service不再与任何组件绑定时,该service会被destroy。
Service与Activity通信
依靠onBind()方法
Service中代码
public class MyService extends Service {
public static final String TAG = "MyService";
private MyBinder mBinder = new MyBinder();
@Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "onCreate() executed");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "onStartCommand() executed");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, "onDestroy() executed");
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
class MyBinder extends Binder {
public void startDownload() {
Log.d("TAG", "startDownload() executed");
// 执行具体的下载任务
}
}
}
Acitivity中代码
private MyService.MyBinder myBinder;
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
myBinder = (MyService.MyBinder) service;
myBinder.startDownload();
}
};
Intent bindIntent = new Intent(this, MyService.class);
bindService(bindIntent, connection, BIND_AUTO_CREATE);
Service销毁
单纯StartService方式
//启动方式
Intent startIntent = new Intent(this, MyService.class);
startService(startIntent);
//销毁方式
Intent stopIntent = new Intent(this, MyService.class);
stopService(stopIntent);
流程Service onCreat -> onStartCommand -> onDestroy
单纯的bindServic方式
//启动方式
Intent bindIntent = new Intent(this, MyService.class);
bindService(bindIntent, connection, BIND_AUTO_CREATE);
//销毁方式
unbindService(connection);
由于在绑定Service的时候指定的标志位是BIND_AUTO_CREATE,说明点击Bind Service按钮的时候Service也会被创建,这时应该怎么销毁Service呢?其实也很简单,unbindService,将Activity和Service的关联解除就可以了。
混合启动的销毁
以上这两种销毁的方式都很好理解。那么如果我们既点击了Start Service按钮,又点击了Bind Service按钮会怎么样呢?这个时候你会发现,不管你是单独点击Stop Service按钮还是Unbind Service按钮,Service都不会被销毁,必要将两个按钮都点击一下,Service才会被销毁。也就是说,点击Stop Service按钮只会让Service停止,点击Unbind Service按钮只会让Service和Activity解除关联,一个Service必须要在既没有和任何Activity关联又处理停止状态的时候才会被销毁。
最后:###我们应该始终记得在Service的onDestroy()方法里去清理掉那些不再使用的资源,防止在Service被销毁后还会有一些不再使用的对象仍占用着内存。
为什么不在Activity中创建而是在Service中创建线程
这是因为Activity很难对Thread进行控制,当Activity被销毁之后,就没有任何其它的办法可以再重新获取到之前创建的子线程的实例。而且在一个Activity中创建的子线程,另一个Activity无法对其进行操作。但是Service就不同了,所有的Activity都可以与Service进行关联,然后可以很方便地操作其中的方法,即使Activity被销毁了,之后只要重新与Service建立关联,就又能够获取到原有的Service中Binder的实例。因此,使用Service来处理后台任务,Activity就可以放心地finish,完全不需要担心无法对后台任务进行控制的情况。
较标准的Service
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
new Thread(new Runnable() {
@Override
public void run() {
// 开始执行后台任务
}
}).start();
return super.onStartCommand(intent, flags, startId);
}
class MyBinder extends Binder {
public void startDownload() {
new Thread(new Runnable() {
@Override
public void run() {
// 执行具体的下载任务
}
}).start();
}
}
前台Service
public class MyService extends Service {
public static final String TAG = "MyService";
private MyBinder mBinder = new MyBinder();
@Override
public void onCreate() {
super.onCreate();
Notification notification = new Notification(R.drawable.ic_launcher,
"有通知到来", System.currentTimeMillis());
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
notificationIntent, 0);
notification.setLatestEventInfo(this, "这是通知的标题", "这是通知的内容",
pendingIntent);
startForeground(1, notification);
Log.d(TAG, "onCreate() executed");
}
.........
}
可以看到,我们首先创建了一个Notification对象,然后调用了它的setLatestEventInfo()方法来为通知初始化布局和数据,并在这里设置了点击通知后就打开MainActivity。然后调用startForeground()方法就可以让MyService变成一个前台Service,并会将通知的图片显示出来。
远程Service
将一个普通的Service转换成远程Service其实非常简单,只需要在注册Service的时候将它的android:process属性指定成:remote就可以了,代码如下所示:
<service
android:name="com.example.servicetest.MyService"
android:process=":remote" >
</service>
使用了远程Service后,MyService已经在另外一个进程当中运行了,所以只会阻塞该进程中的主线程,并不会影响到当前的应用程序。
远程Service弊端
为什么点击Start Service按钮程序就不会崩溃,而点击Bind Service按钮就会崩溃呢?这是由于在Bind Service按钮的点击事件里面我们会让MainActivity和MyService建立关联,但是目前MyService已经是一个远程Service了,Activity和Service运行在两个不同的进程当中,这时就不能再使用传统的建立关联的方式,程序也就崩溃了。
那么如何才能让Activity与一个远程Service建立关联呢?这就要使用AIDL来进行跨进程通信了(IPC)。
不详细贴讲解了
http://blog.youkuaiyun.com/guolin_blog/article/details/9797169
BroadcastReceive篇
启动方式
1)创建需要启动BroadcastReceiver的Intent。
2)调用Context的sendBroadcast()或sendOrderedBroadcast()方法来启动指定的BroadcastReceiver。其中sendBroadcast发送的是普通广播,sendOrderedBroadcast发送的是有序广播。
第一步:创建BroadcastReceiver的子类:
由于BroadcastReceiver本质上是一种监听器,所以创建BroadcastReceiver的方法也非常简单,只需要创建一个BroadcastReceiver的子类然后重写onReceive (Context context, Intentintent)方法即可。
具体代码如下:
public class MyBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
String msg=intent.getExtras().get("msg").toString();
Toast.makeText(context,"intent.getAction()"+intent.getAction().toString(),
Toast.LENGTH_LONG).show();
System.out.println("msg:"+msg);
}
}
第二步:注册BroadcastReceiver
第一种是静态注册:这种方法是在配置AndroidManifest.xml配置文件中注册,通过这种方式注册的广播为常驻型广播,也就是说如果应用程序关闭了,有相应事件触发,程序还是会被系统自动调用运行。例如:
<receiver android:name="com.example.test.MyBroadcastReceiver">
<intent-filter>
<action android:name="android.intent.action.MyBroadcastReceiver"></action>
<category android:name="android.intent.category.DEFAULT"></category>
</intent-filter>
</receiver>
第二种是动态注册
这种方法是通过代码在.Java文件中进行注册。通过这种方式注册的广播为非常驻型广播,即它会跟随Activity的生命周期,所以在Activity结束前我们需要调用unregisterReceiver(receiver)方法移除它。例如:
MyBroadcastReceiver receiver=new MyBroadcastReceiver();
IntentFilter filter=new IntentFilter();
filter.addAction("android.intent.action.MyBroadcastReceiver");
//注册receiver
registerReceiver(receiver, filter);
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
//当Activity销毁的时候取消注册BroadcastReceiver
unregisterReceiver(receiver);
}
BroadcastReceiver的生命周期:
BroadcastReceiver的生命周期,从对象调用它开始,到onReceiver方法执行完成之后结束。另外,每次广播被接收后会重新创建BroadcastReceiver对象,并在onReceiver方法中执行完就销毁,如果BroadcastReceiver的onReceiver方法中不能在10秒内执行完成,Android会出现ANR异常。所以不要在BroadcastReceiver的onReceiver方法中执行耗时的操作。如果需要在BroadcastReceiver中执行耗时的操作,可以通过Intent启动Service来完成。但不能绑定Service。
广播类型
Broadcast的类型有两种:普通广播和有序广播。
Normal broadcasts(普通广播):Normal broadcasts是完全异步的可以同一时间被所有的接收者接收到。消息的传递效率比较高。但缺点是接收者不能讲接收的消息的处理信息传递给下一个接收者也不能停止消息的传播。
Ordered broadcasts(有序广播):Ordered broadcasts的接收者按照一定的优先级进行消息的接收。如:A,B,C的优先级依次降低,那么消息先传递给A,在传递给B,最后传递给C。优先级别声明在<intent-filter>中,取值为[-1000,1000]数值越大优先级别越高。优先级也可通过filter.setPriority(10)方式设置。 另外Ordered broadcasts的接收者可以通过abortBroadcast()的方式取消广播的传播,也可以通过setResultData和setResultExtras方法将处理的结果存入到Broadcast中,传递给下一个接收者。然后,下一个接收者通过getResultData()和getResultExtras(true)接收高优先级的接收者存入的数据。