您的位置:首页 > 移动开发 > Android开发

Android 四大组件之Service

2014-07-14 19:32 471 查看
什么是Service?

Service是能够在后台执行长时间运行操作并且不提供用户界面的应用程序组件。(简单来说,Service就是提供服务的代码,这些代码最终体现为一个个的接口函数。所以,Service就是实现一组函数的对象,通常也称为组件。)它跟Activity的级别差不多,但是他不能自己运行,需要通过某一个Activity或者其他Context对象来调用, Context.startService() 和Context.bindService()。

为什么要用Service?

Service不是进程,也不是线程。
处理耗时操作,需开启子线程。
Service一般是运行在主线程的,可以通过在主线程和Service都打印Thread.currentThread().getId()验证。
具体使用在:比如播放多媒体的时候用户启动了其他Activity这个时候程序要在后台继续播放,比如检测SD卡上文件的变化,再或者在后台记录你地理信息位置的改变等等。
请注意:Service和Thread的区别?参考文献:/article/1374666.htmlhttp://blog.sina.com.cn/s/blog_68c0129901014hz6.htmlhttp://www.juziku.com/wiki/4245.htm

Service的分类:
Service按启动方法分类分为两种,它们的区别如下:

启动方法Activity与Service是否返回值何时被动终止手动关闭
startService没有关系Activity退出,仍运行stopService或stopSelf(只有intent执行完才行停止掉)
bindService可以有多个Acyivity绑定是,可以IPC通信所有绑定Activity退出,才退出???同上
要想正确使用Service,必须熟知Service的启动流程,具体如下:

context.startService() 启动流程:

context.startService() -> onCreate() -> onStart() -> Service running -> context.stopService() -> onDestroy() -> Service stop

如果Service还没有运行,则android先调用onCreate(),然后调用onStart();

如果Service已经运行,则只调用onStart(),所以一个Service的onStart方法可能会重复调用多次。

如果stopService的时候会直接onDestroy,如果是调用者自己直接退出而没有调用stopService的话,Service会一直在后台运行,该Service的调用者再启动起来后可以通过stopService关闭Service。

所以调用startService的生命周期为:onCreate --> onStart (可多次调用) --> onDestroy

context.bindService()启动流程:

context.bindService() -> onCreate() -> onBind() -> Service running -> onUnbind() -> onDestroy() -> Service stop

onBind()将返回给客户端一个IBind接口实例,IBind允许客户端回调服务的方法,比如得到Service的实例、运行状态或其他操作。这个时候把调用者(Context,例如Activity)会和Service绑定在一起,Context退出了,Srevice就会调用onUnbind->onDestroy相应退出。

所以调用bindService的生命周期为:onCreate --> onBind(只一次,不可多次绑定) --> onUnbind --> onDestory。

在Service每一次的开启关闭过程中,只有onStart可被多次调用(通过多次startService调用),其他onCreate,onBind,onUnbind,onDestory在一个生命周期中只能被调用一次。

PS: onStart() 虽仍能使用,但它已被抛弃,被onStartCommand所取代。

下面我们用图的形式来了解Service的生命周期:


这里要说明一下的是如果你在Service的onCreate或者onStart做一些很耗时间的事情,最好在Service里启动一个线程来完成,因为Service是跑在主线程中,会影响到你的UI操作或者阻塞主线程中的其他事情。

下面,我们分别用不同方式启动的Service举一个例子:

先用context.startService() 这种方式做一个背景音乐,在界面上有两个button,控制背景音乐的开关:

创建一个MusicService.java继承Service。

public class MusicService extends Service {
private static MediaPlayer mediaPlayer;

@Override
public void onStart(Intent intent, int startId) {
// TODO Auto-generated method stub
super.onStart(intent, startId);
System.out.println("onStart");
// 设置音乐循环
mediaPlayer.setLooping(true);
if (!mediaPlayer.isPlaying())
mediaPlayer.start();
}

@Override
public void onCreate() {
System.out.println("onCreate");
mediaPlayer = MediaPlayer.create(this, R.raw.begin_music);
super.onCreate();
}

@Override
public void onDestroy() {
System.out.println("onDestroy");
super.onDestroy();
mediaPlayer.stop();
}

@Override
public IBinder onBind(Intent intent) {
System.out.println("onBind");
return null;
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
System.out.println("onStartCommand");
return super.onStartCommand(intent, flags, startId);
}

}


在MainActivity中的代码为:

public class MainActivity extends Activity {
final int RIGHT = 0;
final int LEFT = 1;
private GestureDetector gestureDetector;
private Intent intent;

public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
intent = new Intent("com.topcsa.test.music");
startService(intent);
Button btn_close=(Button) findViewById(R.id.btn_close);
Button btn_start=(Button) findViewById(R.id.btn_start);
btn_close.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View v) {

stopService(new Intent(MainActivity.this,MusicService.class));

}
});
btn_start.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View v) {
startService(new Intent(MainActivity.this,MusicService.class));

}
});

}

@Override
protected void onDestroy() {
stopService(new Intent(MainActivity.this,MusicService.class));
super.onDestroy();
}

}


记住在Activity的onDestroy中停止服务,否则即使退出当前应用,Service依然在后台执行并播放音乐。(这种方式中,Activity启动服务后就与Service几乎没有关系了,所以必须要手动关闭Service)

注意:一定不要忘记注册Service

<service android:name="com.example.test_android.MusicService">
<intent-filter >
<action android:name="com.topcsa.test.music"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</service>


该程序的运行结果为:

刚打开应用时的结果为(此时,音乐已开始播放):



第一次点击打开背景音乐的button时,结果为(音乐正常播放,无停顿、异常):



此时未运行onCreate方法,但执行了onStartCommand()、onStart()方法。

接下来,第一次点击关闭背景音乐的button,结果为(音乐被关闭):



此时执行了onDestroy()方法。

接下来,我们再点击打开背景音乐的button,结果为(音乐再次打开):



此时,执行了onCreate()方法。

下面我们通过一个例子来了解了解context.bindService()的使用:

main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >

<Button
android:id="@+id/start"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="启动服务"/>
<Button
android:id="@+id/stop"
android:layout_width="wrap_content"
android:layout_below="@id/start"
android:layout_height="wrap_content"
android:text="停止服务"/>
<Button
android:id="@+id/bind"
android:layout_below="@id/stop"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="绑定服务"/>
<Button
android:id="@+id/unbind"
android:layout_below="@id/bind"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="解除绑定服务"/>

</RelativeLayout>


MusicService.java


public class MusicService extends Service {
private static MediaPlayer mediaPlayer, mediaPlayer2;
Intent intent;
private IBinder myBinder = new IBinder() {

@Override
public String getInterfaceDescriptor() throws RemoteException {

return "My Service class";
}

@Override
public boolean pingBinder() {
// TODO Auto-generated method stub
return false;
}

@Override
public boolean isBinderAlive() {
// TODO Auto-generated method stub
return false;
}

@Override
public IInterface queryLocalInterface(String descriptor) {
// TODO Auto-generated method stub
return null;
}

@Override
public void dump(FileDescriptor fd, String[] args)
throws RemoteException {
// TODO Auto-generated method stub

}

@Override
public void dumpAsync(FileDescriptor fd, String[] args)
throws RemoteException {
// TODO Auto-generated method stub

}

@Override
public boolean transact(int code, Parcel data, Parcel reply, int flags)
throws RemoteException {
// TODO Auto-generated method stub
return false;
}

@Override
public void linkToDeath(DeathRecipient recipient, int flags)
throws RemoteException {
// TODO Auto-generated method stub

}

@Override
public boolean unlinkToDeath(DeathRecipient recipient, int flags) {
// TODO Auto-generated method stub
return false;
}

};

@Override
public void onStart(Intent intent, int startId) {
// TODO Auto-generated method stub
super.onStart(intent, startId);
System.out.println("onStart");

}

@Override
public void onCreate() {
System.out.println("onCreate");
mediaPlayer = MediaPlayer.create(this, R.raw.begin_music);
super.onCreate();
}

@Override
public void onDestroy() {
System.out.println("onDestroy");
super.onDestroy();
mediaPlayer.stop();
}

@Override
public IBinder onBind(Intent intent) {
System.out.println("onBind");
return null;
}

@Override
public boolean onUnbind(Intent intent) {
System.out.println("onUnbind");
return super.onUnbind(intent);
}

@Override
public void onRebind(Intent intent) {
System.out.println("onRebind");
super.onRebind(intent);
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
System.out.println("onStartCommand");
if (!mediaPlayer.isPlaying())
mediaPlayer.start();
mediaPlayer.setLooping(true);// 设置音乐循环
return Service.START_CONTINUATION_MASK;
}

}


MainActivity.java:

public class MainActivity extends Activity {
final int RIGHT = 0;
final int LEFT = 1;
private GestureDetector gestureDetector;
private Intent intent;
boolean tag=false;

private ServiceConnection sercon = new ServiceConnection() {

@Override
public void onServiceDisconnected(ComponentName name) {
System.out.println("onServiceDisconnected");

}

@Override
public void onServiceConnected(ComponentName name, IBinder service) {
try {
System.out.println("onServiceConnected service="
+ service.getInterfaceDescriptor());
} catch (RemoteException e) {
e.printStackTrace();
}

}
};

public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
startService(new Intent(MainActivity.this, MusicService.class));
Button btn_close = (Button) findViewById(R.id.stop);
Button btn_start = (Button) findViewById(R.id.start);
Button btn_bind = (Button) findViewById(R.id.bind);
Button btn_unbind = (Button) findViewById(R.id.unbind);
btn_close.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View v) {

stopService(new Intent(MainActivity.this, MusicService.class));

}
});
btn_start.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View v) {
startService(new Intent(MainActivity.this, MusicService.class));

}
});
btn_bind.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View v) {
tag=true;
bindService(new Intent(MainActivity.this, MusicService.class),
MainActivity.this.sercon, Context.BIND_AUTO_CREATE);

}
});
btn_unbind.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View v) {
if(tag)
unbindService(MainActivity.this.sercon);
tag=false;
}
});

}

}


运行程序可知:

程序启动时:onCreate、onStartCommand

点击第一个启动服务按钮:onStartCommand

点击第二个停止服务按钮:onDestroy

点击第三个绑定服务按钮:onCreate、onBind

点击第三个解除绑定服务时:onUnbind、onDestroy



推荐文献:http://blog.csdn.net/androiddevelop/article/details/14498193       /content/4092709.html

     http://blog.csdn.net/ithomer/article/details/7364024
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: