后台服务和多线程:
Service即“服务” ,它与Activity属于同一等级的应用程序组件,都代表可执行的程序。不同的是Activity拥有前台运行的用户界面,而Service不能自己运行,需要通过某个Activity或者其他Context对象来调用。没有专属界面的activity。是以分时程序的方式运行吗,即在activity里面启动的service,不会在相同的进程中运行。
由Service,Activity或者Broadcast Receiver开始,停止和控制。
具体可以通过Context.startService()(一旦启动,各自无关。Context.stopService())和Context.bindService()。优先级比没有活动的activity高,不会被轻易杀死。用于耗时的操作。
1、不需要知道Service的状态:开启Service 定义 Intent 第一次启动的时候,必须有inCreate(),onStart()每次调用的时候执行,不是第一次启动start就不需要启动。停止的时候onDestroy()。
2、需要知道的话,就使用绑定。
启动模式一:通过StartService启动。(一旦启动,各自无关)
1、通过startService启动的Service的生命周期状态
2、通过调用Context.startService()启动,而以调用Context.stopService()结束。它可以调用Service.stopSelf()或Service.stopSelfResult()来自己停止。不论调用了多少次startService()方法,需要调用一次stopService()来停止服务。startService()启动和stopService()关闭服务,Service与访问者之间基本不存在太多关联,因此Service和访问者之间无法通讯和数据交换。
开启Service:
Intent intent = new Intent(this,MyService.class);
startService(Intent); //其中MyService类是开发者自定义的继承Service的子类。
当第一次启动Service时,先后调用了onCreate(),onStart()这两个方法,当停止Service时,则执行onDestroy()方法。若Service已经启动,当再次启动Service时,不会在执行onCreate()方法,而是直接执行onStart()方法。
关闭Service:在Activity中通过stopService(Intent)关闭Service;
Intentintent= new Intent(this,MyService.class);stopService(intent);
n 或者在Service中通过stopSelf()关闭自身。
具体实现:
1、建立Android工程:
ØActivity: ServiceApplication.java。程序入口,例程将在这个Activity中启动Service。
ØService: MyService.java(继承Service的子类)
在大多情况,需要重写onCreate和onStartCommand方法。
2、onStartCommand方法
Ø 在使用startService方法启动Service时被调用,在Service的生命周期内会多次
被调用。
Ø onStartCommand方法代替了Android 2.0之前一直使用的onStart方法。通过onStartCommand方法,可以明确告诉操作系统,在用户调用stopService或者stopSelf方法显式停止之前被操作系统杀死的Service重启的时候要执行的操作。
ServiceApplication.java
public classServiceApplicationextendsActivity {
@Override
public voidonCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//启动指定的Service
Intent intent =newIntent(this,MyService.class);
startService(intent);
}
}
在AndroidManifest.xml中注册这个Service
如果没有在此定义服务名称、访问权限,服务就无法被正确运行
<applicationandroid:icon= "@drawable/icon"android:label= "@string/app_name">
<activityandroid:name= ".ServiceApplication“ android:label="@string/app_name" >
<intent-filter>
<actionandroid:name= "android.intent.action.MAIN"/>
<categoryandroid:name= "android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<serviceandroid:name= ".MyService"
android:process= "serviceApplication"/>
</application>
启动模式二:通过bindService启动。
1.当程序通过startService()和stopService()启动、关闭Service时,Service和访问者基本上不存在太多关联,也无法进行通信和数据交换。
2.若Service和访问者之间需要进行方法调用或数据交换,则应该使用bindService(intent service, ServiceConnection conn, int flags)方式
Øservice:通过Intent指定要启动的Service;
Øconn:该对象用于监听访问者与Service之间的连接情况。当访问者连接成功时将回调ServiceConnection对象的onServiceConnected (ComponentName name, Ibinder service)方法;
Øflags:绑定时是否自动创建Service。(自动或不自动创建)
通过Context.bindService()方法启动服务,通过Context.unbindService()关闭服务。多个客户端可以绑定至同一个服务。如果服务此时还没有加载,bindService()会先加载它。
bindService启动的Service的生命周期。
onBind()只有采用Context.bindService()方法启动服务时才会回调该方法。该方法在调用者与服务绑定时被调用。当调用者与服务已经绑定,多次调用Context.bindService()方法并不会导致该方法被多次调用。
Ø采用Context.bindService()方法启动服务时,只能调用onUnbind()方法解除调用者与服务解除,服务结束时会调用onDestroy()方法。可被其他应用程序复用,比如天气预报服务,其他应用程序不需要再写这样的服务,调用已有的即可。
由于Service没有界面,所以用户控制Service需要通过另外一个Activity来接收用户输入。
Ø 通过绑定Activity与Service,可以实现Activity与Service之间的交互。
例如在Activity中控制音乐播放Service对音乐进行开始/停止,快进/快退等操作。Service运行在本地进程中与Activity属于同一进程,则只要在Activity中获得指向Service的引用,就可以像调用成员对象的方法一样去调用Service的方法。
Activity和Service交互示意图:
public class PlayBindMusic extendsActivity implements
OnClickListener{
private Button playBtn, stopBtn, pauseBtn, exitBtn;
private BindMusicService musicService;
@Override
public void onCreate(Bundle savedInstanceState) {
super. onCreate(savedInstanceState);
setContentView(R. layout. bind_music_service);
findView();bindButton();
connection();}
private void findView() {
playBtn= (Button)findViewById(R. id. play);
stopBtn= (Button)findViewById(R. id. stop);
pauseBtn= (Button)findViewById(R. id. pause);
exitBtn= (Button)findViewById(R. id. exit);}
private void bindButton() {
playBtn. setOnClickListener(this);
stopBtn. setOnClickListener(this);
pauseBtn. setOnClickListener(this);
exitBtn. setOnClickListener(this);}
private void connection(){
Intent intent = newIntent(this, BindMusicService. class);
bindService(intent, sc, Context. BIND_AUTO_CREATE);
public void onClick(View v) {
switch(v. getId()) {
case R. id. play:
musicService. play();
break;
case R. id. stop:
if(musicService!=null){
musicService. stop();}break;
case R. id. pause:
if(musicService!=null){
musicService. pause();
}
break;
case R. id. exit:
this. finish();
break;}
}
private ServiceConnection sc =new ServiceConnection() {
public void onServiceDisconnected(ComponentName
name) {
musicService=null;}
public void onServiceConnected(ComponentName name,
IBinder service) {
musicService=
((BindMusicService. MyBinder)(service)).getService();}
};
}
服务端代码:
public classBindMusicService extends Service{
privateMediaPlayer mediaPlayer;
privatefinal IBinder binder = newMyBinder();
public classMyBinder extends Binder{
BindMusicService getService() {
return BindMusicService.this;}}
@Override
publicIBinder onBind(Intent intent) {
returnbinder;}
@Override
public voidonCreate() {
super. onCreate();}
@Override
public voidonDestroy() {
super. onDestroy();
if(mediaPlayer!=null){
mediaPlayer. stop();
mediaPlayer. release();}}
public voidplay() {
if(mediaPlayer==null) {
mediaPlayer=MediaPlayer. create(this, R. raw. tmp);
mediaPlayer. setLooping(false);}
if(!mediaPlayer. isPlaying()) {
mediaPlayer. start();}}
public voidpause() {
if(mediaPlayer!=null&&mediaPlayer. isPlaying()) {
mediaPlayer. pause();
}
}
public voidstop() {
if(mediaPlayer!=null) {
mediaPlayer. stop();
try{
mediaPlayer. prepare();
}catch(IOException ex) {
ex. printStackTrace();
}
}
}
}
对于Service的onBind()方法所返回的IBinder对象来说,它可以被当成该Service组件所返回的代理对象,Service允许客户端通过该IBinder对象来访问Service内部的数据,实现客户端与Service之间的通信。
Service本身存在两个问题:
Ø 1、Service不是一个单独的进程 ,它和应用程序在同一个进程中。
Ø 2、Service不是一个线程,所以应该避免在Service里面进行耗时的操作;
把耗时的操作直接放在Service的onStart方法中,会出现Application Not Responding!Service不是一个线程,不能直接处理耗时的操作。如果有耗时操作在Service里,就必须开启一个单独的线程来处理。
IntentService:IntentService使用队列的方式将请求的Intent加入队列,然后开启一个worker thread(线程)来处理队列中的Intent,对于异步的startService请求,IntentService会处理完成一个之后再处理第二个,每一个请求都会在一个单独的worker thread中处理,不会阻塞应用程序的主线程。如果有耗时的操作可以在Service里面开启新线程或使用IntentService来处理。创建单独的worker线程来处理所有的Intent请求;创建单独的worker线程来处理onHandleIntent()方法实现的代码,开发者无需处理多线程问题;当所有请求处理完成后,IntentService会自动停止,开发者无需调用stopSelf()停止该Service;提供了一个onBind()方法的默认实现,它返回null。提供了onStartCommand()方法的默认实现,它将Intent先传送至工作队列,然后从工作队列中每次取出一个传送至onHandleIntent()方法,在该方法中Intent对相应的处理。
public classServiceDemoActivityextendsActivity{
/** Called when the activity is first created. */ @Override
public voidonCreate(Bundle savedInstanceState) {
super. onCreate(savedInstanceState);
setContentView(R. layout. main);
startService(newIntent(this, MyService. class));//主界面阻塞,最终会出现Application not responding
//连续两次启动IntentService,会发现应用程序不会阻塞,而且最重的是第二次的请求会再第一个请求结束之后运行(这个证实了
IntentService采用单独的线程每次只从队列中拿出一个请求进行处理) startService(newIntent(this, MyIntentService. class));
startService(newIntent(this, MyIntentService. class));
}
}
public classMyServiceextendsService{
@Override
public voidonCreate() {
super. onCreate(); }
@Override
public voidonStart(Intent intent, intstartId) {
super. onStart(intent, startId);
//经测试,Service里面是不能进行耗时的操作的,必须要手动开启一个工作线程来处理耗时操作
newThread(newRunnable() {
@Override
public voidrun() {
//此处进行耗时的操作,这里只是简单地让线程睡眠了1s
try{Thread. sleep(1000); }
catch(Exception e) { e. printStackTrace(); } }}).start();
returnSTART_STICKY;
}
@Override
publicIBinder onBind(Intent intent) {
returnnull;
}
}
public classMyIntentServiceextendsIntentService{
publicMyIntentService() {
super("yyyyyyyyyyy");
}
@Override
protected voidonHandleIntent(Intent intent){
//经测试,IntentService里面是可以进行耗时的操作的
//IntentService使用队列的方式将请求的Intent加入队列,然后开启一个worker thread(线程)来处理队列中的Intent
//对于异步的startService请求,IntentService会处理完成一个之后再处理第二个 System. out. println("onStart");
try{ Thread. sleep(20000);
}catch(InterruptedException e) { e. printStackTrace();
} System. out. println(" 睡眠结束" );
}
}
进程与进程之间无法进行直接的数据交换:Android系统中,各种应用程序都运行在自己的进程中,操作系统也对进程空间进行保护,一个进程不能直接访问另一个进程的内存空间,进程之间一般无法进行数据交换。所以进程间进行数据交互需要利用Android操作系统提供的进程间通讯(IPC)机制来实现。