麦子学院Android开发教程Service组件介绍.docx
在Android工作中,如果计算量较大,又不是UI层的工作,可以考虑将这部分工作放置在Service中。目前Android中Service的应用非常广泛,尤其是在框架层,应用更多的是对系统服务的调用。今天首先介绍几个常用的系统服务。 为了将Service纳入编译系统,必须在AndroidManifest.xml中对Service进行显式声明,方法如下:<service android:name=".service.TestService"></service>1. InputMethodServiceInputMethodService提供了一个输入法的标准实现,普通开发者不必关心这一点,ODM厂商和输入法企业则需考虑。一种输入法在界面上由3部分构成,即软输入视图(Soft Input View)、候选视图(Candidates View)和全屏模式(Fullscreen Mode)。在实现自定义的输入法时,有以下几个回调方法需要注意:public void onInitializeInterface()public void onBindInput()public void onStartInput(EditorInfo attribute, boolean restarting)public View onCreateCandidatesView()public View onCreateInputView()public View onCreateExtractTextView()public void onStartInputView(EditorInfo info, boolean restarting)在Android中,Google提供了一个名为SoftKeyboard的自定义输入法示例,有兴趣的读者可查阅相关资料,本书就不再详述。2. IntentServiceIntentService作为Service的子类,主要用于处理异步请求,防止服务阻塞。所有的请求将在一个工作线程(HandlerThread)中处理,工作结束后,线程也结束。在gallery3d应用中,CacheService即是IntentService的一个示例。3. MediaScannerServiceMediaScannerService主要在设备启动和SD卡挂载时执行多媒体文件的扫描工作。出于性能方面的考虑,Android区分SD卡和手机存储空间。对于SD卡,MediaScannerService会在收到Action为ACTION_MEDIA_MOUNTED的Intent(即SD卡挂载)时进行扫描;对于手机存储空间,MediaScannerReceiver会在收到Action为ACTION_BOOT_COMPLETED的Intent(即设备启动完毕)时进行扫描。另外,在下载文件时,也可能启动媒体扫描服务。媒体扫描服务相关的类图如图1-5所示。目前MediaScannerService扫描的多媒体格式定义在MediaFile.java文件中,其中,音频格式有MP3、M4A、WAV、AMR、AWB、WMA、OGG、OGA、AAC、MKA;MIDI格式有MID、MIDI、XMF、RTTTL、SMF、IMY、RTX、OTA; 视频格式有MPEG、MP4、M4V、3GP、3GPP、3G2、3GPP2、WMV、ASF、MKV、WEBM、TS, 并从Android 2.3.3开始支持WEBM; 图像格式有JPG、JPEG、GIF、PNG、BMP、WBMP; 播放列表格式有M3U、PLS、WPL。当系统开始扫描时,媒体扫描服务会广播一个Action为ACTION_MEDIA_SCANNER_STARTED的Intent,然后创建一个MediaScanner执行扫描;当扫描结束后,广播一个Action为ACTION_MEDIA_SCANNER_FINISHED的Intent。下面是执行扫描的具体过程:private void scan(String directories, String volumeName) / 获得唤醒锁,设置扫描过程中系统休眠 mWakeLock.acquire(); ContentValues values = new ContentValues(); values.put(MediaStore.MEDIA_SCANNER_VOLUME, volumeName); Uri scanUri = getContentResolver().insert( MediaStore.getMediaScannerUri(), values); Uri uri = Uri.parse("file:/" + directories0); sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_STARTED,uri); try if (volumeName.equals(MediaProvider.EXTERNAL_VOLUME) openDatabase(volumeName); MediaScanner scanner = createMediaScanner(); scanner.scanDirectories(directories, volumeName); catch (Exception e) Log.e(TAG, "exception in MediaScanner.scan()", e); getContentResolver().delete(scanUri, null, null); sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_FINISHED, uri); mWakeLock.release(); 在一些特殊场合,如录音应用和下载场景中,如果希望产生的多媒体文件即刻被加入到数据库中,可以直接调用媒体扫描服务进行单个文件的扫描,但对于删除的文件,无法通过如下方式进行同步:sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE,Uri.fromFile(file);4. RecognitionServiceRecognitionService是一个抽象服务,仅在开发者希望实现一个新的语音识别器时才可能用到。为了实现一个新的语音识别器,必须实现如下抽象方法:protected abstract void onStartListening(Intent recognizerIntent, Callback listener)protected abstract void onCancel(Callback listener)protected abstract void onStopListening(Callback listener)在Android中,提供了一个名为VoiceRecognitionService的示例,有兴趣的读者可查阅相关资料。由于RecognitionService用途有限,本书就不再详述。5. 绑定服务和启动服务服务的运行有两种发起方式,即绑定服务和启动服务。当通过绑定服务的方式运行服务时,一旦绑定解除,服务即被销毁,当进行了多次绑定时,只有所有绑定均解除,服务才会销毁;当以启动服务的方式运行服务时,服务并不会随着绑定组件的销毁而销毁,而是服务会自我销毁,这种方式适用于文件下载、文件上传等请求后自行运行的场景。(1)绑定服务为了绑定一个服务,需要设置ServiceConnection和标志位,方法如下:public abstract boolean bindService(Intent service,ServiceConnection conn,int flags)ServiceConnection可以监控服务的状态,在进行服务绑定时,其标志位可以为BIND_AUTO_CREATE、BIND_DEBUG_UNBIND和BIND_NOT_FOREGROUND等。其中BIND_AUTO_CREATE表示当收到绑定请求时,如果服务尚未创建,则即刻创建,在系统内存不足,需要先销毁优先级组件来释放内存,且只有驻留该服务的进程成为被销毁对象时,服务才可被销毁;BIND_DEBUG_UNBIND通常用于调试场景中判断绑定的服务是否正确,但其会引起内存泄漏,因此非调试目的不建议使用;BIND_NOT_FOREGROUND表示系统将阻止驻留该服务的进程具有前台优先级,仅在后台运行,该标志位在Froyo中引入。绑定服务的示例如下:Intent intent = new Intent();intent.setClassName("com.android.providers.media","com.android.providers.media.MediaScannerService");bindService(intent, mMediaScannerConnection, BIND_AUTO_CREATE);注意,绑定服务是以异步的方式运行的。绑定服务必须在当前的上下文环境中进行,在某些场景中,如果无法绑定成功,则可能需要在应用级的上下文环境中进行,方法如下:getApplicationContext().bindService(.)如果需要解除绑定,方法如下:public abstract void unbindService(ServiceConnection conn)(2) 启动服务启动服务的方法如下:public abstract ComponentName startService(Intent service)自我停止服务的方法如下:public final void stopSelf ()被动停止服务的方法如下:public abstract boolean stopService(Intent service)6. 服务的生命周期和Activity一样,服务同样有着自己的生命周期。和Activity相比,服务在两种运行方式下,其生命周期所执行的过程略有不同。服务的生命周期如图1-6所示。当外部组件调用其上下文的startService()方法时,即可启动相应的服务。在服务的onStartCommand(Intent intent, int flags, int startId)方法(Android 2.0以前为onStart())中,会返回一个唯一的整数标识符标识启动请求。启动请求可以为START_STICKY_COMPATIBILITY、START_STICKY、START_NOT_STICKY、START_REDELIVER_INTENT等,其中,标志位可以为START_FLAG_REDELIVERY、START_FLAG_RETRY等。启动服务的示例如下:Intent intent = new Intent(this, ExperimentService.class);intent.putExtra(EXTRA_EXP_ID, which);intent.putExtra(EXTRA_RUN_ALL, all);startService(intent);Intent传递过来的参数可以在onStartCommand()方法中进行处理,示例如下:public int onStartCommand(Intent intent, int flags, int startId) if (intent != null) Message msg = mServiceHandler.obtainMessage(); msg.arg1 = startId; msg.obj = intent.getExtras(); mServiceHandler.sendMessage(msg); return START_REDELIVER_INTENT; 停止服务的方法如下:Intent intent = new Intent(this, ExperimentService.class);stopService(intent);当外部组件调用其上下文的bindService()方法时,也可绑定相应的服务。如果服务未启动,则调用onCreate()方法启动服务,但不会调用onStartCommand()方法,只有在所有绑定均解除后,服务才自动停止运行。通过服务的onBind()方法,可以获得一个客户端与服务进行通信的IBinder接口。注意,绑定服务的Android组件在销毁前应解除绑定,否则会造成内存泄漏。绑定和解除绑定的示例如下:mContext.bindService(newIntent(IBluetoothHeadset.class.getName(), mConnection, 0)mContext.unbindService(mConnection);上述代码中,参数mConnection的实现如下:private ServiceConnection mConnection = new ServiceConnection() public void onServiceConnected(ComponentName className, IBinder service) if (DBG) Log.d(TAG, "Proxy object connected"); mService = IBluetoothHeadset.Stub.asInterface(service); if (mServiceListener != null) mServiceListener.onServiceConnected(); public void onServiceDisconnected(ComponentName className) if (DBG) Log.d(TAG, "Proxy object disconnected"); mService = null; if (mServiceListener != null) mServiceListener.onServiceDisconnected(); ;至于采用何种服务的执行方式,开发者应根据使用的场景进行抉择。如需了解更多相关知识,请至麦子学院官网查询(