Actvity的生命周期流程图:
以下是Activity生命周期的几个过程:
1.启动Activity:系统会先调用onCreate方法,然后调用onStart方法,最后调用onResume,Activity进入运行状态。
2.当前Activity被其他Activity覆盖其上或被锁屏:系统会调用onPause方法,暂停当前Activity的执行。
3.当前Activity由被覆盖状态回到前台或解锁屏:系统会调用onResume方法,再次进入运行状态。
4.当前Activity转到新的Activity界面或按Home键回到主屏,自身退居后台:系统会先调用onPause方法,然后调用onStop方法,进入停滞状态。
5.用户后退回到此Activity:系统会先调用onRestart方法,然后调用onStart方法,最后调用onResume方法,再次进入运行状态。
6.当前Activity处于被覆盖状态或者后台不可见状态,即第2步和第4步,系统内存不足,杀死当前Activity,而后用户退回当前Activity:再次调用onCreate方法、onStart方法、onResume方法,进入运行状态。
7.用户退出当前Activity:系统先调用onPause方法,然后调用onStop方法,最后调用onDestory方法,结束当前Activity。
但是知道这些还不够,我们必须亲自试验一下才能深刻体会,融会贯通。
1.onWindowFocusChanged方法:在Activity窗口获得或失去焦点时被调用,例如创建时首次呈现在用户面前;当前Activity被其他Activity覆盖;当前Activity转到其他Activity或按Home键回到主屏,自身退居后台;用户退出当前Activity。以上几种情况都会调用onWindowFocusChanged,并且当Activity被创建时是在onResume之后被调用,当Activity被覆盖或者退居后台或者当前Activity退出时,它是在onPause之后被调用。这个方法在某种场合下还是很有用的,例如程序启动时想要获取视特定视图组件的尺寸大小,在onCreate中可能无法取到,因为窗口Window对象还没创建完成,这个时候我们就需要在onWindowFocusChanged里获取。
2.onSaveInstanceState:(1)在Activity被覆盖或退居后台之后,系统资源不足将其杀死,此方法会被调用;(2)在用户改变屏幕方向时,此方法会被调用;(3)在当前Activity跳转到其他Activity或者按Home键回到主屏,自身退居后台时,此方法会被调用。第一种情况我们无法保证什么时候发生,系统根据资源紧张程度去调度;第二种是屏幕翻转方向时,系统先销毁当前的Activity,然后再重建一个新的,调用此方法时,我们可以保存一些临时数据;第三种情况系统调用此方法是为了保存当前窗口各个View组件的状态。onSaveInstanceState的调用顺序是在onPause之前。
3.onRestoreInstanceState:(1)在Activity被覆盖或退居后台之后,系统资源不足将其杀死,然后用户又回到了此Activity,此方法会被调用;(2)在用户改变屏幕方向时,重建的过程中,此方法会被调用。我们可以重写此方法,以便可以恢复一些临时数据。onRestoreInstanceState的调用顺序是在onStart之后。
下面再介绍一下关于Activity屏幕方向的相关知识:
我们可以为一个Activity指定一个特定的方向,指定之后即使转动屏幕方向,显示方向也不会跟着改变:
1.指定为竖屏:在AndroidManifest.xml中对指定的Activity设置android:screenOrientation="portrait",或者在onCreate方法中指定:
2.指定为横屏:在AndroidManifest.xml中对指定的Activity设置android:screenOrientation="landscape",或者在onCreate方法中指定:
1、不设置Activity的android:configChanges时,切屏会重新调用各个生命周期,切横屏时会执行一次,切竖屏时会执行两次
2、设置Activity的android:configChanges="orientation"时,切屏还是会重新调用各个生命周期,切横、竖屏时只会执行一次
3、设置Activity的android:configChanges="orientation|keyboardHidden"时,切屏不会重新调用各个生命周期,只会执行onConfigurationChanged方法
以下是需要注意的几点:
1.如果<activity>配置了android:screenOrientation属性,则会使android:configChanges="orientation"失效。
2.模拟器与真机差别很大:模拟器中如果不配置android:configChanges属性或配置值为orientation,切到横屏执行一次销毁->重建,切到竖屏执行两次。真机均为一次。模拟器中如果配置android:configChanges="orientation|keyboardHidden"(如果是Android4.0,则是"orientation|keyboardHidden|screenSize"),切竖屏执行一次onConfigurationChanged,切横屏执行两次。真机均为一次。
Android中两个Activity之间数据传递及返回
MainActivity
[java] view plaincopy
由MainActivity 通过最简单的Intent.putExtra方法,将参数传入,也可以用Bundle传入参数,
Bundle bundle = new Bundle();
bundle.putString("str", "Intent Demo");
intent.putExtras(bundle);
若需要获得返回值,则用startActivityForResult(),并需要知道返回的一个RESULT_CODE(int类型),可以理解为指针,用intent.setClass() 确定传递给那个类(这里包括Activity、Service等)。第二个Activity---本例中的SecondActivity ,用Intent intent=getIntent();Bundle bundle=intent.getExtras();String str=bundle.getString("str");获得前一个Activity传来的参数,这里还需要返回给MainActivity参数,用到了setResult(RESULT_CODE, intent); 这里 要说明的是RESULT_CODE必须与前一个Activity一致,否则就不能正常返回。而第一个MainActivity通过重写onActivityResult()来取得相应的返回值。
若不需要返回,可以直接用startActivity()。
SecondActivity
<--------------------------------------------------------------------------------!!!!!!!!!!!!!!!---------------------------------------------------->
Service的生命周期流程图:
Service概念及用途:
Android中的服务,它与Activity不同,它是不能与用户交互的,不能自己启动的,运行在后台的程序,如果我们退出应用时,Service进程并没有结束,它仍然在后台运行,那 我们什么时候会用到Service呢?比如我们播放音乐的时候,有可能想边听音乐边干些其他事情,当我们退出播放音乐的应用,如果不用Service,我 们就听不到歌了,所以这时候就得用到Service了,又比如当我们一个应用的数据是通过网络获取的,不同时间(一段时间)的数据是不同的这时候我们可以 用Service在后台定时更新,而不用每打开应用的时候在去获取。
Service与线程的区别:
刚开始接触service的时候,很多人会有这样的疑问,为什么不用thread代替service呢。首先得明白本地service是运行在主进程的main线程上的,如果是远程service,则运行在独立进程的main线程上。而新建线程主要是用来执行一些异步的操作。首先从生命周期来分析,当一个应用程序被强制终止后,应用程序中开启的线程也会被销毁,而service可以做到在应用被终止的情况下仍然在后台欢快的运行。其次是同一个线程对象没法被多个activty控制,如有时候会出现这种情况:当 Activity 被 finish 之后,该Activty启动的线程还在执行,此时你失去了对该线程的引用,只能通过终止应用来停止该线程的运行。对于一些比较关键的服务,一般选择使用service,如果比较耗时则可以在service中创建和控制线程,进行异步操作。
有了 Service 类我们如何启动他呢,有两种方法:
service可以通过两种方式创建:startService()和bindService().
1. 在同一个应用任何地方调用 startService() 方法就能启动 Service 了,然后系统会回调 Service 类的 onCreate() 以及 onStart() 方法。这样启动的 Service 会一直运行在后台,直到 Context.stopService() 或者 selfStop() 方法被调用。另外如果一个 Service 已经被启动,其他代码再试图调用 startService() 方法,是不会执行 onCreate() 的,但会重新执行一次 onStart() ,如果service是被开启的,那么它的活动生命周期和整个生命周期一同结束。
2. 另外一种 bindService() 方法的意思是,把这个 Service 和调用 Service 的客户类绑起来,如果调用这个客户类被销毁,Service 也会被销毁。用这个方法的一个好处是,bindService() 方法执行后 Service 会回调上边提到的 onBind() 方发,你可以从这里返回一个实现了 IBind 接口的类,在客户端操作这个类就能和这个服务通信了,比如得到 Service 运行的状态或其他操作。有时候我们想在Activity中获知Service的状态,例如一个音乐播放器,Service负责音乐播放,Activity负责显示当前歌曲名和播放进度。可以用Broadcast,这个也不失为一个解决方法。但如果可以获取Service实例,那么就可以调用Service中自定义的一些方法来获取Service状态了。首先要明确的是,第一种类型的Service是无能为力的。因为Activity与Service之间并没有相关联的接口,即使这个Service是在Activity里start的,一旦start,两者不再有关联。
一个service可以同时和多个客户绑定,当多个客户都解除绑定之后,系统会销毁service。如果调用者退出后,它们它的活动生命周期是在onUnbind()方法,onDestroy()后结束。
这两条路径并不是完全分开的。
即是说,你可以和一个已经调用了 startService()而被开启的service进行绑定。
比如,一个后台音乐service可能因调用 startService()方法而被开启了,稍后,可能用户想要控制播放器或者得到一些当前歌曲的信息,可以通过bindService()将一个activity和service绑定。这种情况下,stopService()或 stopSelf()实际上并不能停止这个service,除非所有的客户都解除绑定。另外,你的service被开启并且接受绑定,那么当系统调用你的 onUnbind()
方法时,如果你想要在下次客户端绑定的时候接受一个onRebind()的调用(而不是调用 onBind()
),你可以选择在 onUnbind()
中返回true。onRebind()的返回值为void,但是客户端仍然在它的 onServiceConnected()
回调方法中得到 IBinder
对象。
两种方式的适用场合:
startService():一般用于在后台上传文件或者下载文件等,不跟其他组件通信,就算启动它的应用被销毁了,它仍然会欢快的在后台执行,直到完成任务的时候自刎(自己调用stopSelf())或者被其他人下黑手(调用stopService()).
bindService():允许其他组件跟它进行通信,允许多个客户端绑定到同一个service上,当所有的客户端都解除绑定后,该service就销毁了。
由于Service 的onStart()方法只有在startService()启动Service的情况下才调用,故使用onStart()的时候要注意这点。
以下是调用方法的使用注意事项:
1、如果是由activity bindService启动,则service自己的onCreate(),onBind(),onServiceConnected()按照这个顺序被调用,则在该activity调用onDestroy()方法时不论是否调用unBindService方法,service自己的onUnbind方法都会被调用,但是如果不调用unBindService方法,则在bindService方法中会抛android.app.ServiceConnectionLeaked: ******.MainActivity has leaked ServiceConnection 异常,这中情况不会影响service及activity。
2、bindService及unBindService方法可多次调用,在调用unBindService方法前连续调bindService对应的onBind()只会调用一次,连续多次调用unBindService对应的onUnbind方法只会调用一次。
3、第一次调用startService-->bindeService-->unBindService对应的调service方法为onCreate()->onBind()->onServiceConnected()->onStart()(其中startService与bindeService的顺序没有关系,onStart在onBind()前还是后可能是受service 的onCreate()方法执行时间影响)
4、在Service stop前不论是在当前activity还是其他对象中继续调用startService-->bindeService-->unBindService这些方法对应的调service方法为onStart()->onServiceConnected()(在同一对象如果调过bindService后在调用unBindService前重复调bindService,则onServiceConnected()方法不会重复调用),不会再调用onBind()方法和onUnbind()方法。
5、在service的生命周期中onBind()方法和onUnbind()只会被调用一次即使在不同对象调了多次bindeService和unBindService。
6、如果在activity1中startService,在activity2中onBindServie,则在activity2调unBindService前在activity1中调stopService则不能立即调service的onDestroy,只有在activity2调unBindService后才会调service的onDestroy.如果只在activity1中startService和onBindServie则可在unBindService前调stopService使service的onDestroy被调用。
总结:startService和bindService及stopService和unBindService都可以多次调用,只是在Service关闭之前重复调用startService方法会重复调service的onStart(),重复调bindeService只会调onServiceConnected()而不会调onBind(),重复调unBindService是不会调onUnbind()方法的。
stopService只有在所有调过bindServie的对象(调stopService的对象除外,可不用unBindeService)中都调了unBindService以后调才能使service的onDestroy被调用。
onServiceDisconnected方法在意外连接断开或者系统资源不够的时候调用,或者service stop后,则之前调了几次unBindService则调几次onServiceDisconnected方法
Android Service生命周期与Activity生命周期是相似的,但是也存在一些细节上也存在着重要的不同:
1.onCreate和onStart是不同的
通过从客户端调用Context.startService(Intent)方法我们可以启动一个服务。如果这个服务还没有运行,Android将启动它并且在onCreate方法之后调用它的onStart方法。如果这个服务已经在运行,那么它的onStart方法将被新的Intent再次调用。所以对于单个运行的Service它的onStart方法被反复调用是完全可能的并且是很正常的。
2.onResume、onPause以及onStop是不需要的
回调一个服务通常是没有用户界面的,所以我们也就不需要onPause、onResume或者onStop方法了。无论何时一个运行中的Service它总是在后台运行。
3.onBind
如果一个客户端需要持久的连接到一个服务,那么他可以调用Context.bindService方法。如果这个服务没有运行方法将通过调用onCreate方法去创建这个服务但并不调用onStart方法来启动它。相反,onBind方法将被客户端的Intent调用,并且它返回一个IBind对象以便客户端稍后可以调用这个服务。同一服务被客户端同时启动和绑定是很正常的。
4.onDestroy
与Activity一样,当一个服务被结束是onDestroy方法将会被调用。当没有客户端启动或绑定到一个服务时Android将终结这个服务。与很多Activity时的情况一样,当内存很低的时候Android也可能会终结一个服务。如果这种情况发生,Android也可能在内存够用的时候尝试启动被终止的服务,所以你的服务必须为重启持久保存信息,并且最好在onStart方法内来做。
在Android开发中,我们或许会碰到这么一种业务需求,一项任务分成几个子任务,子任务按顺序先后执行,子任务全部执行完后,这项任务才算成功。那么,利用几个子线程顺序执行是可以达到这个目的的,但是每个线程必须去手动控制,而且得在一个子线程执行完后,再开启另一个子线程。或者,全部放到一个线程中让其顺序执行。这样都可以做到,但是,如果这是一个后台任务,就得放到Service里面,由于Service和Activity是同级的,所以,要执行耗时任务,就得在Service里面开子线程来执行。那么,有没有一种简单的方法来处理这个过程呢,答案就是IntentService。
简单说,IntentService是继承于Service并处理异步请求的一个类,在IntentService内有一个工作线程来处理耗时操作,启动IntentService的方式和启动传统Service一样,同时,当任务执行完后,IntentService会自动停止,而不需要我们去手动控制。另外,可以启动IntentService多次,而每一个耗时操作会以工作队列的方式在IntentService的onHandleIntent回调方法中执行,并且,每次只会执行一个工作线程,执行完第一个再执行第二个,以此类推。
而且,所有请求都在一个单线程中,不会阻塞应用程序的主线程(UI Thread),同一时间只处理一个请求。
那么,用IntentService有什么好处呢?首先,我们省去了在Service中手动开线程的麻烦,第二,当操作完成时,我们不用手动停止Service。
继承IntentService的类,这里是IntentServiceDemo.java
public class IntentServiceDemo extends IntentService { public IntentServiceDemo() { //必须实现父类的构造方法 super("IntentServiceDemo"); } @Override public IBinder onBind(Intent intent) { System.out.println("onBind"); return super.onBind(intent); } @Override public void onCreate() { System.out.println("onCreate"); super.onCreate(); } @Override public void onStart(Intent intent, int startId) { System.out.println("onStart"); super.onStart(intent, startId); } @Override public int onStartCommand(Intent intent, int flags, int startId) { System.out.println("onStartCommand"); return super.onStartCommand(intent, flags, startId); } @Override public void setIntentRedelivery(boolean enabled) { super.setIntentRedelivery(enabled); System.out.println("setIntentRedelivery"); } @Override protected void onHandleIntent(Intent intent) { //Intent是从Activity发过来的,携带识别参数,根据参数不同执行不同的任务 String action = intent.getExtras().getString("param"); if (action.equals("oper1")) { System.out.println("Operation1"); }else if (action.equals("oper2")) { System.out.println("Operation2"); } try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } @Override public void onDestroy() { System.out.println("onDestroy"); super.onDestroy(); } }
IntentService是继承Service的,那么它包含了Service的全部特性,当然也包含service的生命周期,那么与service不同的是,IntentService在执行onCreate操作的时候,内部开了一个线程,去你执行你的耗时操作。
publicclassTestActivity extends Activity {
/** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); //可以启动多次,每启动一次,就会新建一个work thread,但IntentService的实例始终只有一个 //Operation 1 Intent startServiceIntent = new Intent("com.test.intentservice"); Bundle bundle = new Bundle(); bundle.putString("param", "oper1"); startServiceIntent.putExtras(bundle); startService(startServiceIntent); //Operation 2 Intent startServiceIntent2 = new Intent("com.test.intentservice"); Bundle bundle2 = new Bundle(); bundle2.putString("param", "oper2"); startServiceIntent2.putExtras(bundle2); startService(startServiceIntent2); } }