来不急,就贴到帖子上,明天回公司看
Android SDK 提供了两种类型的 Service ,用于类似 *nix 守护进程或者 windows 的服务
1. 本地服务 Local Service :用于应用程序内部
2. 远程服务 Remote Service :用于 android 系统内部的应用程序之间
前者用于实现应用程序自己的一些耗时任务,比如查询升级信息,并不占用应用程式比如 Activity 所属线程,而是单开线程后台执行,这样用户体验比较好。
后者可被其他应用程序服用,比如天气预报服务,其他应用程序不需要再写这样的服务,调用已有的即可。
不需要和 Activitye 交互的本地服务
本地服务编写比较简单。首先,要创建一个 Service 类,该类继承 android 的 Service 类。然后在 Activity 中的 onCreate 和 onDestory 中分别执行以下语句开启服务和停止服务。
this .startService( new Intent( this , ServiceImpl. class ));
this .stopService( new Intent( this , ServiceImpl. class ));
需要和 Activity 交互的远程服务
上面的示例是通过 startService 和 stopService 启动关闭服务的。适用于服务和 activity 之间没有调用交互的情况。如果之间需要传递参数或者方法调用。需要使用 bind 和 unbind 方法。
具体做法是,服务类需要增加接口,比如 ServiceInterface ,另外,服务类需要有一个内部类,这样可以方便访问外部类的封装数据,这个内部类需要继承 Binder 类并实现 ServiceInterface 接口。还有,就是要实现 Service 的 onBind 方法,不能只传回一个 null 了。
在 android 的 musicplayer 源码中 MediaPlaybackService 使用了以上的服务方式,针对该源码进行分析:
首先需要了解进程间通信、需要 AIDL (以及 Binder )
关于 AIDL 的介绍在文档: docs/guide/developing/tools/aidl.html
关于 IBinder 的介绍在文档: docs/reference/android/os/IBinder.html
以及 Binder : docs/reference/android/os/Binder.html
manifest 中 Service 的语法,见 docs/guide/topics/manifest /service-element.html
以上转自 http://blog.csdn.net/saintswordsman/archive/2010/01/05/5130947.aspx
步骤一:建立 aidl 文件
通过 aidl.exe 会在 gen 中生成该 service 类,该类中的成员变量 stub 实现了以下功能:
extends Binder implements ServiceInterface,源码如下
Java代码 1.interface IMediaPlaybackService
2.{
3. void openfile(String path);
4. void openfileAsync(String path);
5. void open(in int [] list, int position);
6. ...................//接口方法
7.}
interface IMediaPlaybackService
{
void openfile(String path);
void openfileAsync(String path);
void open(in int [] list, int position);
...................//接口方法
}
Java代码 1.public interface IMediaPlaybackService extends android.os.IInterface {
2. /**生成binder类 */
3. public static abstract class Stub extends android.os.Binder implements
4. com.android.mymusic.IMediaPlaybackService {
5. private static final java.lang.String DESCRIPTOR = "com.android.mymusic.IMediaPlaybackService";
6.
7. /** Construct the stub at attach it to the interface. */
8. public Stub() {
9. this.attachInterface(this, DESCRIPTOR);
10. }
11. ...................
12. ...................
13. ...................//binder 方法
14. }
15.
16. public void openfile(java.lang.String path)
17. throws android.os.RemoteException;
18. ...................
19. ...................//接口方法
20. ...................
21.
22.}
public interface IMediaPlaybackService extends android.os.IInterface {
/**生成binder类 */
public static abstract class Stub extends android.os.Binder implements
com.android.mymusic.IMediaPlaybackService {
private static final java.lang.String DESCRIPTOR = "com.android.mymusic.IMediaPlaybackService";
/** Construct the stub at attach it to the interface. */
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
...................
...................
...................//binder 方法
}
public void openfile(java.lang.String path)
throws android.os.RemoteException;
...................
...................//接口方法
...................
}
步骤二:编写服务的实现类 MediaPlaybackService
Java代码 1.public class MediaPlaybackService extends Service {
2.
3. ......
4.
5. @Override
6. public IBinder onBind(Intent intent) {
7. mDelayedStopHandler.removeCallbacksAndMessages(null);
8. mServiceInUse = true;
9. return mBinder;
10. }
11. private final IMediaPlaybackService.Stub mBinder = new IMediaPlaybackService.Stub()
12. {
13. ...................//实现接口方法
14. };
15.}
public class MediaPlaybackService extends Service {
......
@Override
public IBinder onBind(Intent intent) {
mDelayedStopHandler.removeCallbacksAndMessages(null);
mServiceInUse = true;
return mBinder;
}
private final IMediaPlaybackService.Stub mBinder = new IMediaPlaybackService.Stub()
{
...................//实现接口方法
};
}
步骤三:编写一个消费这个服务的 Activity : MediaPlaybackActivity: (除此之外还有其他类)
Java代码
1.public class MediaPlaybackActivity extends Activity implements MusicUtils.Defs,
2. View.OnTouchListener, View.OnLongClickListener
3.{
4. private IMediaPlaybackService mService = null;
5.
6. @Override
7. public void onStart() {
8. super.onStart();
9. ...................//其他代码
10.
11. if (false == MusicUtils.bindToService(this, serviecConnection)) {
12. // something went wrong
13. ...................//其他代码
14. }
15.
16. private ServiceConnection serviecConnection = new ServiceConnection() {
17. public void onServiceConnected(ComponentName classname, IBinder obj) {
18. mService = IMediaPlaybackService.Stub.asInterface(obj);
19. if (MusicUtils.sService == null) {
20. MusicUtils.sService = mService;
21.
22. ...................//其他代码
23.
24. }
25. }
26. public void onServiceDisconnected(ComponentName classname) {
27. }
28. };
29.}
30.//MusicUtils类:定义了播放器所需要的操作以及service和Activity之间的相互作用的操作
31.public class MusicUtils {
32.
33. ...................//其他代码
34.
35. public static boolean bindToService(Context context, ServiceConnection callback) {
36. context.startService(new Intent(context, MediaPlaybackService.class));
37. ServiceBinder sb = new ServiceBinder(callback);
38. sConnectionMap.put(context, sb);
39. return context.bindService((new Intent()).setClass(context,
40. MediaPlaybackService.class), sb, 0);
41. }
42.
43. ...................//其他代码
44.
45.}
public class MediaPlaybackActivity extends Activity implements MusicUtils.Defs,
View.OnTouchListener, View.OnLongClickListener
{
private IMediaPlaybackService mService = null;
@Override
public void onStart() {
super.onStart();
...................//其他代码
if (false == MusicUtils.bindToService(this, serviecConnection)) {
// something went wrong
...................//其他代码
}
private ServiceConnection serviecConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName classname, IBinder obj) {
mService = IMediaPlaybackService.Stub.asInterface(obj);
if (MusicUtils.sService == null) {
MusicUtils.sService = mService;
...................//其他代码
}
}
public void onServiceDisconnected(ComponentName classname) {
}
};
}
//MusicUtils类:定义了播放器所需要的操作以及service和Activity之间的相互作用的操作
public class MusicUtils {
...................//其他代码
public static boolean bindToService(Context context, ServiceConnection callback) {
context.startService(new Intent(context, MediaPlaybackService.class));
ServiceBinder sb = new ServiceBinder(callback);
sConnectionMap.put(context, sb);
return context.bindService((new Intent()).setClass(context,
MediaPlaybackService.class), sb, 0);
}
...................//其他代码
}
需要注意:
远程服务往往不只是传递 java 基本数据类型。这时需要注意 android 的一些限制和规定:
以下转自 http://yangguangfu.javaeye.com/blog/699306
1. android 支持 String 和 CharSequence
2. 如果需要在 aidl 中使用其他 aidl 接口类型,需要 import ,即使是在相同包结构下;
3. android 允许传递实现 Parcelable 接口的类,需要 import ;
4. android 支持集合接口类型 List 和 Map ,但是有一些限制,元素必须是基本型或者上述三种情况,不需要 import 集合接口类,但是需要对元素涉及到的类型 import ;
非基本数据类型,也不是 String 和 CharSequence 类型的,需要有方向指示,包括 in 、 out 和 inout , in 表示由客户端设置, out 表示由服务端设置, inout 是两者均可设置。
转自:http://blog.csdn.net/bigapple88/archive/2011/03/29/6285411.aspx
下面介绍一下Andriod多媒体框架对开发者提供的支持有哪些。
1. MediaScannerReceiver
这个广播接收者在接收到ACTION_BOOT_COMPLETED、ACTION_MEDIA_MOUNTED或 ACTION_MEDIA_SCANNER_SCAN_FILE 广播时对SD卡中的图片、音乐和视频文件进行了扫描,因为扫描不能影响用户使用,这里启动了一个服务MediaScannerService,扫描的文件类型如下:
/* Audio */
addFileType("MP3", FILE_TYPE_MP3, "audio/mpeg");
addFileType("M4A", FILE_TYPE_M4A, "audio/mp4");
addFileType("WAV", FILE_TYPE_WAV, "audio/x-wav");
addFileType("AMR", FILE_TYPE_AMR, "audio/amr");
addFileType("AWB", FILE_TYPE_AWB, "audio/amr-wb");
addFileType("WMA", FILE_TYPE_WMA, "audio/x-ms-wma");
addFileType("OGG", FILE_TYPE_OGG, "application/ogg");
addFileType("MID", FILE_TYPE_MID, "audio/midi");
addFileType("XMF", FILE_TYPE_MID, "audio/midi");
addFileType("RTTTL", FILE_TYPE_MID, "audio/midi");
addFileType("SMF", FILE_TYPE_SMF, "audio/sp-midi");
addFileType("IMY", FILE_TYPE_IMY, "audio/imelody");
/* Video */
addFileType("MP4", FILE_TYPE_MP4, "video/mp4");
addFileType("M4V", FILE_TYPE_M4V, "video/mp4");
addFileType("3GP", FILE_TYPE_3GPP, "video/3gpp");
addFileType("3GPP", FILE_TYPE_3GPP, "video/3gpp");
addFileType("3G2", FILE_TYPE_3GPP2, "video/3gpp2");
addFileType("3GPP2", FILE_TYPE_3GPP2, "video/3gpp2");
addFileType("WMV", FILE_TYPE_WMV, "video/x-ms-wmv");
/* Image */
addFileType("JPG", FILE_TYPE_JPEG, "image/jpeg");
addFileType("JPEG", FILE_TYPE_JPEG, "image/jpeg");
addFileType("GIF", FILE_TYPE_GIF, "image/gif");
addFileType("PNG", FILE_TYPE_PNG, "image/png");
addFileType("BMP", FILE_TYPE_BMP, "image/x-ms-bmp");
addFileType("WBMP", FILE_TYPE_WBMP, "image/vnd.wap.wbmp");
/* Audio Play List */
addFileType("M3U", FILE_TYPE_M3U, "audio/x-mpegurl");
addFileType("PLS", FILE_TYPE_PLS, "audio/x-scpls");
addFileType("WPL", FILE_TYPE_WPL, "application/vnd.ms-wpl");
扫描结束后写入到数据库中。
其他的应用程序通过接收MediaScannerService发出的ACTION_MEDIA_SCANNER_STARTED 和ACTION_MEDIA_SCANNER_FINISHED意图能够知道什么时候扫描操作开始和结束。
2. MediaProvider
对于存入数据库的多媒体信息,MediaProvider提供了数据访问的接口。MediaProvider继承了ContentProvider,我们先来看一下数据查询接口:
Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder);
Uri:指明要查询的数据库名称加上表的名称,从MediaStore中我们可以找到相应信息的参数,具体请参考开发文档。
Projection: 指定查询数据库表中的哪几列,返回的游标中将包括相应的信息。Null则返回所有信息。
selection: 指定查询条件
selectionArgs:参数selection里有 ?这个符号是,这里可以以实际值代替这个问号。如果selection这个没有?的话,那么这个String数组可以为null。
SortOrder:指定查询结果的排列顺序
下面的命令将返回所有在外部存储卡上的音乐文件的信息:
Cursor cursor = query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, null,
null, null, MediaStore.Audio.Media.DEFAULT_SORT_ORDER);
获取ID标签中的歌曲的专辑名:MediaStore.Audio.Media.ALBUM
String album = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ALBUM));
其他具体参数请参考MediaStore类。