手机是人们生活中不可或缺的一个有用工具。我们在使用手机时,往往是多线程的,而且是会突然间断的。比如我们会一边浏览网页,一边听MP3。或者正在发短信的时候,突然打进来电话。这样我们必定会离开当前的用户界面。比如你会关闭MP3歌曲列表,去发短信,所以往往就需要有些程序在后台完成,暂时脱离屏幕。这时就可以用到Android中的Service
下面会用一个播放MP3的小应用来体会一下Android的Service

******************************
另外也可参照以下哥们的博客:
① http://wayfarer.iteye.com/blog/586167
******************************

1、什么是Service
Android引入了Service的概念是为了处理后台进程。Service不实现任何用户界面。最常见的例子如:媒体播放器程序,它可以在转到后台运行的时候仍然能保持播放歌曲;或者如文件下载程序,它可以在后台执行文件的下载。
它跟Activity的级别差不多,但是他不能自己运行,需要通过某一个Activity或者其他Context对象来调用, Context.startService() 和 Context.bindService()。

2、Service的生命周期
Service的生命周期方法比Activity少一些,只有onCreate, onStart, onDestroy
我们有两种方式启动一个Service,他们对Service生命周期的影响是不一样的。两种启动Service的方式有所不同。 这里要说明一下的是如果你在Service的onCreate或者onStart做一些很耗时间的事情,最好在Service里启动一个线程来完成,因为Service 是跑在主线程中,会影响到你的UI操作或者阻塞主线程中的其他事情。

3、创建一个Service
Android中已经定义了一个 ‘Service’类,所有其他的Service都继承于该类。Service类中定义了一系列的生命周期相关的方法,如: onCreate(), onStart(), onDestroy()

4、提高 Service 优先级
Android 系统对于内存管理有自己的一套方法,为了保障系统有序稳定的运行,系统内部会自动分配,控制程序的内存使用。当系统觉得当前的资源非常有限的时候,为了保证一些优先级高的程序能运行,就会杀掉一些他认为不重要的程序或者服务来释放内存。这样就能保证真正对用户有用的程序仍然再运行。如果你的 Service 碰上了这种情况,多半会先被杀掉。但如果你增加 Service 的优先级就能让他多留一会,我们可以用 setForeground(true) 来设置 Service 的优先级。
为什么是 foreground ? 默认启动的 Service 是被标记为 background,当前运行的 Activity 一般被标记为 foreground,也就是说你给 Service 设置了 foreground 那么他就和正在运行的 Activity 类似优先级得到了一定的提高。当让这并不能保证你得 Service 永远不被杀掉,只是提高了他的优先级。

5、启动Service
 有了 Service 类我们如何启动他呢,有两种方法:
Context.startService()
context.startService() ->onCreate()- >onStart()->Service running
context.stopService() | ->onDestroy() ->Service stop

Context.bindService()
context.bindService()->onCreate()->onBind()->Service running
onUnbind() -> onDestroy() ->Service stop
在同一个应用任何地方调用 startService() 方法就能启动 Service 了,然后系统会回调 Service 类的 onCreate() 以及 onStart() 方法。这样启动的 Service 会一直运行在后台,直到 Context.stopService() 或者 selfStop() 方法被调用。如果是调用者自己直接退出而没有调用stopService的话,Service会一直在后台运行。该Service的调用者再启动起来后可以通过stopService关闭Service。
另外如果一个 Service 已经被启动,其他代码再试图调用 startService() 方法,是不会执行 onCreate() 的,但会重新执行一次 onStart() 。
另外一种 bindService() 方法的意思是,把这个 Service 和调用 Service 的客户类绑起来,如果调用这个客户类被销毁,Service 也会被销毁。用这个方法的一个好处是,bindService() 方法执行后 Service 会回调上边提到的 onBind() 方发,你可以从这里返回一个实现了 IBind 接口的类,在客户端操作这个类就能和这个服务通信了,比如得到 Service 运行的状态或其他操作。如果 Service 还没有运行,使用这个方法启动 Service 就会 onCreate() 方法而不会调用 onStart()。

public class BindMusicService extends Service {  06    07     private static final String TAG = "MyService";  08     private MediaPlayer mediaPlayer;  09    10     private final IBinder binder = new MyBinder();  11    12     public class MyBinder extends Binder {  13         BindMusicService getService() {  14             return BindMusicService.this;  15         }  16     }  17    18     /*  19      * (non-Javadoc)  20      *   21      * @see android.app.Service#onBind(android.content.Intent)  22      */ 23     @Override 24     public IBinder onBind(Intent intent) {  25         Log.d(TAG, "onBind");  26         play();  27         return binder;  28     }  29    30     @Override 31     public void onCreate() {  32         super.onCreate();  33            34         Log.d(TAG, "onCreate");  35         Toast.makeText(this, "show media player", Toast.LENGTH_SHORT).show();  36            37            38     }  39    40     @Override 41     public void onDestroy() {  42         super.onDestroy();  43            44         Log.d(TAG, "onDestroy");  45         Toast.makeText(this, "stop media player", Toast.LENGTH_SHORT);  46         if(mediaPlayer != null){  47             mediaPlayer.stop();  48             mediaPlayer.release();  49         }  50     }  51    52        53     public void play() {  54         if (mediaPlayer == null) {  55             mediaPlayer = MediaPlayer.create(this, R.raw.tmp);  56             mediaPlayer.setLooping(false);  57         }  58         if (!mediaPlayer.isPlaying()) {  59             mediaPlayer.start();  60         }  61     }  62    63     public void pause() {  64         if (mediaPlayer != null && mediaPlayer.isPlaying()) {  65             mediaPlayer.pause();  66         }  67     }  68    69     public void stop() {  70         if (mediaPlayer != null) {  71             mediaPlayer.stop();  72             try {  73                 // 在调用stop后如果需要再次通过start进行播放,需要之前调用prepare函数  74                 mediaPlayer.prepare();  75             } catch (IOException ex) {  76                 ex.printStackTrace();  77             }  78         }  79     }  80    81 } 


用其他方式启动 Service
其实不光能从 Activity 中启动 Service ,还有一个很有用的方法是接收系统的广播,这就要用到 Receiver 。在 Mainfest 文件中配置你得 Receiver 能接收什么样的广播消息,那么即使你得程序没有显示给用户,你的 Service 也能启动。你要做的就是继承 android.content.BroadcastReceiver ,然后实现 onReceive(Context context, Intent intent) 方法,就可以启动你得 Service 了。这里不能 bindService 因为一个 Receiver 是一个短暂存在的对象,所以 bind 是没有什么意义的。

与 Service 通信并且让它持续运行
如果我们想保持和 Service 的通信,又不想让 Service 随着 Activity 退出而退出呢?
可以先 startService() 再 bindService()。当不需要绑定的时候再执行 unbindService() 方法,执行这个方法只会触发 Service 的 onUnbind() 而不会把这个 Service 销毁。这样就可以既保持和 Service 的通信,也不会随着 Activity 销毁而销毁了。

6、通过不同的方法启动service所带来的不同
① 通过startService
Service会经历 onCreate -> onStart, stopService的时候直接onDestroy。
如果是调用者自己直接退出而没有调用stopService的话,Service会一直在后台运行。
下次调用者再起来可以stopService。

 ② 通过bindService
Service只会运行onCreate,这个时候调用者和Service绑定在一起,调用者退出 了,Srevice就会调用onUnbind->onDestroyed,所谓绑定在一起就共存亡了。

③ 交织在一起调用
要是这几个方法交织在一起的话,会出现什么情况呢?
一个原则是Service的onCreate的方法只会被调用一次,就是你无论多少次的startService又 bindService,Service只被创建一次。
a.如果先是bind了,那么start的时候就直接运行Service的onStart方法。这时候如果调 用stop方法就关不掉service了,就是stopService不好使了,只能先UnbindService, 再StopService
b.如果先是start,那么bind的时候就直接运行onBind方法。所以是先start还是先bind行为是有区别的。

MP3TestActivity.java提供控制界面
package com.android.mp3test;import android.app.Activity;import android.content.Intent;import android.os.Bundle;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;public class MP3TestActivity extends Activity {private Button start;private Button stop;private Intent i;/** Called when the activity is first created. */@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.main);start = (Button) this.findViewById(R.id.start);stop = (Button) this.findViewById(R.id.stop);// 指向MP3播放Service的actioni = new Intent("com.kennan.android.music");start.setOnClickListener(startListener);stop.setOnClickListener(stopListener);}private OnClickListener startListener = new OnClickListener() {public void onClick(View v) {// 开始服务MP3TestActivity.this.startService(i);}};private OnClickListener stopListener = new OnClickListener() {public void onClick(View v) {// 结束服务MP3TestActivity.this.stopService(i);}};}


MusicService.java提供MP3播放功能,在开启播放后,可以尝试退出应用程序界面。看是否音乐还在继续播放。
package com.android.mp3test;import android.app.Service;import android.content.Intent;import android.media.MediaPlayer;import android.os.IBinder;public class MusicService extends Service {private MediaPlayer player;public IBinder onBind(Intent arg0) {return null;}public void onStart(Intent intent, int startId) {super.onStart(intent, startId);// 在服务开始时,启动MP3播放player = MediaPlayer.create(this, R.raw.music);player.start();}public void onDestroy() {// 在服务消灭时,关闭MP3播放player.stop();super.onDestroy();}}


layout/mean.xml
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:orientation="vertical"    android:layout_width="fill_parent"    android:layout_height="fill_parent"    ><TextView      android:layout_width="fill_parent"     android:layout_height="wrap_content"     android:text="@string/hello"    />        <Button android:id="@+id/start"    android:layout_width="wrap_content"    android:layout_height="wrap_content"    android:text="@string/start"    />       <Button android:id="@+id/stop"       android:layout_width="wrap_content"    android:layout_height="wrap_content"    android:text="@string/stop"    />    </LinearLayout>


AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android"package="com.android.mp3test" android:versionCode="1"android:versionName="1.0"><application android:icon="@drawable/icon" android:label="@string/app_name"><activity android:name=".MP3TestActivity" android:label="@string/app_name"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity><service android:name="MusicService"><intent-filter><action android:name="com.kennan.android.music" /><category android:name="android.intent.category.DEFAULT" /></intent-filter></service></application><uses-sdk android:minSdkVersion="4" /></manifest> 


参考项目结构





================ 20110630 ====================
与远程Service通信(进程间Service通信):
如何两个进程间的Service需要进行通信,则需要把对象序列化后进行互相发送。
Android提供了一个 AIDL (Android接口定义语言)工具来处理序列化和通信。这种情况下Service需要以aidl文件的方式提供服务接口,AIDL工具将生成一个相应的java接口,并且在生成的服务接口中包含一个功能调用的stub服务桩类。Service的实现类需要去继承这个 stub服务桩类。Service的onBind方法会返回实现类的对象,之后你就可以使用它了,参见下例:
先创建一个IMyRemoteService.aidl文件,内容如下:

package com.wissen.testApp;

interface IMyRemoteService {
int getStatusCode();
}

如果你正在使用eclipse的 Android插件,则它会根据这个aidl文件生成一个Java接口类。生成的接口类中会有一个内部类Stub类,你要做的事就是去继承该Stub类:

package com.wissen.testApp;

class RemoteService implements Service {
int statusCode;

@Override
public IBinder onBind(Intent arg0) {
return myRemoteServiceStub;
}

private IMyRemoteService.Stub myRemoteServiceStub = new IMyRemoteService.Stub() {
public int getStatusCode() throws RemoteException {
return 0;
}
};


}

当客户端应用连接到这个Service时,onServiceConnected方法将被调用,客户端就可以获得IBinder对象。参看下面的客户端onServiceConnected方法:


ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
IMyRemoteService myRemoteService = IMyRemoteService.Stub.asInterface(service);
try {
statusCode = myRemoteService.getStatusCode();
} catch(RemoteException e) {
// handle exception
}
Log.i(”INFO”, “Service bound “);
}


};

权限:
我们可以在AndroidManifest.xml文件中使用<service>标签来指定Service访问的权限:

<service class=”.service.MyService” android:permission=”com.wissen.permission.MY_SERVICE_PERMISSION”>
<intent-filter>
<action android:value=”com.wissen.testApp.service.MY_SERVICE” />
</intent-filter>
</service>

之后应用程序要访问该Service的话就需要使用<user-permission>标签来指定相应的权限:

<uses-permission android:name=”com.wissen.permission.MY_SERVICE_PERMISSION”>
</uses-permission>


本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/xiangyong2008/archive/2010/04/26/5530427.aspx

更多相关文章

  1. 基于 Android(安卓)NDK 的学习之旅-----Java 调用C(附源码)
  2. Android内核开发:系统启动速度优化
  3. 深入剖析Android消息机制原理
  4. Unity调用Android(安卓)jar包方法——(三、使用UnitySendMessage
  5. [Android] [Android的视窗系统及显示机制][下] [底层显示子系统S
  6. 『叫兽学堂』手把手教你如何正确启动Android(安卓)SDK 1.5模拟器
  7. Android模拟器正确应用与安装方法
  8. Android运用自定义控件实现闪烁字
  9. Android(安卓)4.4、5.1、6.0 屏蔽Home键

随机推荐

  1. Ue4.20 安卓开发配置及Android(安卓)Stud
  2. android之style样式-EditText样式
  3. 关于Android(安卓)LOG系统
  4. Android(安卓)uevent
  5. Java(Android)线程池
  6. [Android]在Manifest中注册广播监听器
  7. 29.Android(安卓)传感器
  8. php操作redis命令及代码实例大全
  9. Thinkphp极验滑动验证码实现步骤解析
  10. PHP获取真实IP及IP模拟方法解析