Android之Service的用法

本文详细解析Android应用中后台服务(Service)的运作原理,包括Service的启动模式、生命周期管理、实现步骤及与Activity的交互方式。同时,阐述了如何通过绑定Service实现更高效的数据交换,以及Service在不同进程间通信的挑战与解决方案。
摘要由CSDN通过智能技术生成

后台服务和多线程:

         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的子类)
            在大多情况,需要重写onCreateonStartCommand方法

       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 playBtnstopBtnpauseBtnexitBtn;
private BindMusicService musicService;
@Override
public void onCreate(Bundle savedInstanceState) {
superonCreate(savedInstanceState);
setContentView(Rlayoutbind_music_service);
findView();bindButton();
connection();}
private void findView() {
playBtn= (Button)findViewById(Ridplay);
stopBtn= (Button)findViewById(Ridstop);
pauseBtn= (Button)findViewById(Ridpause);
exitBtn= (Button)findViewById(Ridexit);}
private void bindButton() {
playBtnsetOnClickListener(this);
stopBtnsetOnClickListener(this);
pauseBtnsetOnClickListener(this);
exitBtnsetOnClickListener(this);}
private void connection(){
Intent intent = newIntent(thisBindMusicServiceclass);
bindService(intentscContextBIND_AUTO_CREATE);

public void onClick(View v) {
switch(vgetId()) {
case Ridplay:
musicServiceplay();

break;
case Ridstop:
if(musicService!=null){
musicServicestop();}break;
case Ridpause:
if(musicService!=null){
musicServicepause();
}

break;
case Ridexit:
thisfinish();

break;}
}
private ServiceConnection sc =new ServiceConnection() {
public void onServiceDisconnected(ComponentName
name) {
musicService=null;}
public void onServiceConnected(ComponentName name,
IBinder service) {
musicService=
((BindMusicServiceMyBinder)(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() {
superonCreate();}
@Override
public voidonDestroy() {
superonDestroy();
if(mediaPlayer!=null){
mediaPlayerstop();
mediaPlayerrelease();}}
public voidplay() {
if(mediaPlayer==null) {
mediaPlayer=MediaPlayercreate(thisRrawtmp);
mediaPlayersetLooping(false);}

if(!mediaPlayerisPlaying()) {
mediaPlayerstart();}}
public voidpause() {
if(mediaPlayer!=null&&mediaPlayerisPlaying()) {
mediaPlayerpause();
}
}
public voidstop() {
if(mediaPlayer!=null) {
mediaPlayerstop();
try{
mediaPlayerprepare();
}catch(IOException ex) {
exprintStackTrace();
}
}
}
}

对于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) {
superonCreate(savedInstanceState); 

setContentView(Rlayoutmain); 

startService(newIntent(thisMyServiceclass));//主界面阻塞,最终会出现Application not responding
//连续两次启动IntentService,会发现应用程序不会阻塞,而且最重的是第二次的请求会再第一个请求结束之后运行(这个证实了
IntentService采用单独的线程每次只从队列中拿出一个请求进行处理) startService(newIntent(thisMyIntentServiceclass)); 

startService(newIntent(thisMyIntentServiceclass));
}
}

public classMyServiceextendsService{ 

@Override
public voidonCreate() {
superonCreate(); }

@Override
public voidonStart(Intent intentintstartId) {
superonStart(intentstartId);
//经测试,Service里面是不能进行耗时的操作的,必须要手动开启一个工作线程来处理耗时操作
newThread(newRunnable() { 

@Override
public voidrun() {
//此处进行耗时的操作,这里只是简单地让线程睡眠了1s
try{Threadsleep(1000); }

catch(Exception e) { eprintStackTrace(); } }}).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会处理完成一个之后再处理第二个 Systemoutprintln("onStart");
try{ Threadsleep(20000);
}catch(InterruptedException e) { eprintStackTrace();
} Systemoutprintln(" 睡眠结束" );
}
}

进程与进程之间无法进行直接的数据交换:Android系统中,各种应用程序都运行在自己的进程中,操作系统也对进程空间进行保护,一个进程不能直接访问另一个进程的内存空间,进程之间一般无法进行数据交换。所以进程间进行数据交互需要利用Android操作系统提供的进程间通讯(IPC)机制来实现

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值