参考《Professional Android 4 Development》android
Service是invisible的,所以其优先级不高于visible的Activity,之因此说不高于,是由于咱们能够设置Service为在前台运行。app
Android提供了Service抽象类,继承它即可以建立一个Service类:异步
import android.app.Service; import android.content.Intent; import android.os.IBinder; public class MyService extends Service { @Override public void onCreate() { super.onCreate(); // TODO: Actions to perform when service is created. } @Override public IBinder onBind(Intent intent) { // TODO: Replace with service binding implementation. return null; } }
建立Service类以后,还须要在Manifest里面注册:async
<service android:enabled=”true” android:name=”.MyService” android:permission=”com.paad.MY_SERVICE_PERMISSION”/>
若要默认只有本身的程序可使用这个Service,须要添加Android:permission属性。其余Application若要使用这个服务,须要加入这个permission。ide
当Service由startService()方法调用时,便可引发onStartCommand方法的调用,所以须要重写Service中的onStartCommand方法,而且onStartCommand方法可能会被屡次调用。onStartCommand()方法将返回一个int值,用于指定当Service被runtime杀掉又重启的时,系统该如何响应:post
@Override public int onStartCommand(Intent intent, int flags, int startId) { startBackgroundTask(intent, startId); return Service.START_STICKY; }
onStartCommand()方法能够返回这些参数,它们的意义是:ui
START_STICKY:若是service进程被kill掉,保留service的状态为开始状态,但不保留递送的intent对象。随后系统会尝试从新建立service,因为服务状态为开始状态,因此建立服务后必定会调用onStartCommand(Intent,int,int)方法。若是在此期间没有任何启动命令被传递到service,那么参数Intent将为null。this
START_NOT_STICKY:“非粘性的”。若是在执行完onStartCommand后,服务被异常kill掉,系统不会自动重启该服务。
START_REDELIVER_INTENT:使用这个返回值时,若是未执行完onStartCommand,服务在调用stopSelf以前被kill掉,系统会自动重启该服务,并将Intent的值传入。spa
参考:http://www.krislq.com/2013/05/android-class-return-value-of-onstartcommand/线程
调用startService方法能够启动服务:
private void explicitStart() { // Explicitly start My Service Intent intent = new Intent(this, MyService.class); // TODO Add extras if required. startService(intent); } private void implicitStart() { // Implicitly start a music Service Intent intent = new Intent(MyMusicService.PLAY_ALBUM); intent.putExtra(MyMusicService.ALBUM_NAME_EXTRA, “United”); intent.putExtra(MyMusicService.ARTIST_NAME_EXTRA, “Pheonix”); startService(intent); }
调用stopService方法能够中止服务:
// Stop a service explicitly. stopService(new Intent(this, MyService.class)); // Stop a service implicitly. Intent intent = new Intent(MyMusicService.PLAY_ALBUM); stopService(intent);
服务内部调用stopSelf方法,能够中止该服务。
首先,Service要实现IBind接口:
@Override public IBinder onBind(Intent intent) { return binder; } public class MyBinder extends Binder { MyMusicService getService() { return MyMusicService.this; } } private final IBinder binder = new MyBinder();
ServiceConnection类用于表示Service到Activity的绑定,每一个绑定都须要建立一个ServiceConnection:
// Reference to the service private MyMusicService serviceRef; // Handles the connection between the service and activity private ServiceConnection mConnection = new ServiceConnection() { public void onServiceConnected(ComponentName className, IBinder service) { // Called when the connection is made. serviceRef = ((MyMusicService.MyBinder)service).getService(); } public void onServiceDisconnected(ComponentName className) { // Received when the service unexpectedly disconnects. serviceRef = null; } };
最后,调用bindService方法,传入用于启动Service的Intent,ServiceConnection和标志位:
// Bind to the service Intent bindIntent = new Intent(MyActivity.this, MyMusicService.class); bindService(bindIntent, mConnection, Context.BIND_AUTO_CREATE);
一般状况下,Android应用在本身的内存空间中运行,并不共享内存。若要与其余进程通讯,可使用广播,或在Intent中添加Bundle参数启动其余Service的方法。若是须要更紧密的通讯,可使用Android Interface Defi nition Language(AIDL)。AIDL使用OS级别的简单变量定义了接口,能够跨应用传递对象。
使用startForeground方法启动服务,可使服务得到与Visible Activity相同的优先级,例如:
private void startPlayback(String album, String artist) { int NOTIFICATION_ID = 1; // Create an Intent that will open the main Activity if the notification is clicked. Intent intent = new Intent(this, MyActivity.class); PendingIntent pi = PendingIntent.getActivity(this, 1, intent, 0); // Set the Notification UI parameters Notification notification = new Notification(R.drawable.icon, “Starting Playback”, System.currentTimeMillis()); notification.setLatestEventInfo(this, album, artist, pi); // Set the Notification as ongoing notification.flags = notification.flags | Notification.FLAG_ONGOING_EVENT; // Move the Service to the Foreground startForeground(NOTIFICATION_ID, notification); }
使用stopForeground方法能够取消Service的前台属性:
public void pausePlayback() { // Move to the background and remove the Notification stopForeground(true); }
Service和Activity同样,也是在主线程中运行的,为了更好地响应用户,咱们须要使用后台线程的方式执行Service。Android提供了两个抽象类来帮助咱们实现:AsyncTask和IntentService。
AsyncTask不只能帮助咱们将费时操做放到后台执行,还能够实现和UI线程的同步。AsyncTask适合执行那些耗时比较短而且和UI线程有交互的任务,对于耗时较久的任务(例以下载),使用Service更为合适。须要注意的是AsyncTask在应用restart以后会被cancel掉。
private class MyAsyncTask extends AsyncTask<String, Integer, String> { @Override protected String doInBackground(String... parameter) { // Moved to a background thread. String result = “”; int myProgress = 0; int inputLength = parameter[0].length(); // Perform background processing task, update myProgress] for (int i = 1; i <= inputLength; i++) { myProgress = i; result = result + parameter[0].charAt(inputLength-i); try { Thread.sleep(100); } catch (InterruptedException e) { } publishProgress(myProgress); } // Return the value to be passed to onPostExecute return result; } @Override protected void onProgressUpdate(Integer... progress) { // Synchronized to UI thread. // Update progress bar, Notification, or other UI elements asyncProgress.setProgress(progress[0]); } @Override protected void onPostExecute(String result) { // Synchronized to UI thread. // Report results via UI update, Dialog, or notifications asyncTextView.setText(result); } }
使用AsyncTask,首先要建立一个AsyncTask的子类类并实现doInBackground,onProgressUpdate,onPostExecute方法。这三个方法的说明:
String input = “redrum ... redrum”; new MyAsyncTask().execute(input);
IntentService能够经过传入Intent参数调用,传入的Intent将进入一个队列中被异步执行。IntentService封装了消息的异步处理,后台线程建立以及与UI线程的同步。继承IntentService类并实现onHandleIntent方法,便可建立一个Intent Service:
import android.app.IntentService; import android.content.Intent; public class MyIntentService extends IntentService { public MyIntentService(String name) { super(name); // TODO Complete any required constructor tasks. } @Override public void onCreate() { super.onCreate(); // TODO: Actions to perform when service is created. } @Override protected void onHandleIntent(Intent intent) { // This handler occurs on a background thread. TODO The time consuming task should be implemented here. // Each Intent supplied to this IntentService will be processed consecutively here. When all incoming Intents have been processed the Service will terminate itself. } }
Loader是一个抽象类,封装了异步加载数据的最佳实践,最典型的就是CursorLoader了。Android中建立Loader类的简单方法是继承AsyncTaskLoader类,并实现这两个功能:
尽管AsyncTask和Intent Service提供了简单易用的异步类封装,但咱们也能够建立自定义的异步线程:
// This method is called on the main GUI thread. private void backgroundExecution() { // This moves the time consuming operation to a child thread. Thread thread = new Thread(null, doBackgroundThreadProcessing, “Background”); thread.start(); } // Runnable that executes the background processing method. private Runnable doBackgroundThreadProcessing = new Runnable() { public void run() { backgroundThreadProcessing(); } }; // Method which does some processing in the background. private void backgroundThreadProcessing() { // [ ... Time consuming operations ... ] }
runOnUiThread方法会在UI线程执行:
runOnUiThread(new Runnable() { public void run() { // Update a View or other Activity UI element. } });
此外,可使用Handler类更新UI线程:
//This method is called on the main GUI thread. private void backgroundExecution() { // This moves the time consuming operation to a child thread. Thread thread = new Thread(null, doBackgroundThreadProcessing, “Background”); thread.start(); } // Runnable that executes the background processing method. private Runnable doBackgroundThreadProcessing = new Runnable() { public void run() { backgroundThreadProcessing(); } }; // Method which does some processing in the background. private void backgroundThreadProcessing() { // [ ... Time consuming operations ... ] // Use the Handler to post the doUpdateGUI // runnable on the main UI thread. handler.post(doUpdateGUI); } //Initialize a handler on the main thread. private Handler handler = new Handler(); // Runnable that executes the updateGUI method. private Runnable doUpdateGUI = new Runnable() { public void run() { updateGUI(); } }; // This method must be called on the UI thread. private void updateGUI() { // [ ... Open a dialog or modify a GUI element ... ] }
Handler类还可使用postDelayed和postAtTime实现推迟运行和推迟指定时间运行:
// Post a method on the UI thread after 1sec. handler.postDelayed(doUpdateGUI, 1000); // Post a method on the UI thread after the device has been in use for 5mins. int upTime = 1000*60*5; handler.postAtTime(doUpdateGUI, SystemClock.uptimeMillis()+upTime);
与Timer不太,Alarms属于系统服务,独立于应用程序。即便应用程序为启动,也可使用Alarms启动应用程序并获取其服务,这样不只减小了耦合,也减小了系统资源的占用。Android中Alarms常与Broadcast Receiver一块儿使用。建立Alarm以前,首先要建立AlarmManager:
AlarmManager alarmManager = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
建立Alarm须要这些参数:alarm类型,触发时间,Alarm将要触发的Pending Intent。目前Alarm类型有这些:
下面是一个10秒后启动Pending Intent的Alarm示例:
AlarmManager alarmManager = (AlarmManager)getSystemService(Context.ALARM_SERVICE); // Set the alarm to wake the device if sleeping. int alarmType = AlarmManager.ELAPSED_REALTIME_WAKEUP; // Trigger the device in 10 seconds. long timeOrLengthofWait = 10000; // Create a Pending Intent that will broadcast and action String ALARM_ACTION = “ALARM_ACTION”; Intent intentToFire = new Intent(ALARM_ACTION); PendingIntent alarmIntent = PendingIntent.getBroadcast(this, 0, intentToFire, 0); // Set the alarm alarmManager.set(alarmType, timeOrLengthofWait, alarmIntent);
alarmManager.cancel(alarmIntent);
这里的alarmIntent是指使用Alarm启动的Pending Intent。
使用setRepeating或setInexactRepeating方法替代前面的set方法,并传递响应的参数进去,就能够实现可重复的Alarm。
相比setRepeating,setInexactRepeating更省电,但不能指定某个具体的时间间隔。
setInexactRepeating能够接收的时间间隔参数:
下面这个例子指定半小时后启动Alarm,而后每隔半小时启动一次:
// Get a reference to the Alarm Manager AlarmManager alarmManager = (AlarmManager)getSystemService(Context.ALARM_SERVICE); // Set the alarm to wake the device if sleeping. int alarmType = AlarmManager.ELAPSED_REALTIME_WAKEUP; // Schedule the alarm to repeat every half hour. long timeOrLengthofWait = AlarmManager.INTERVAL_HALF_HOUR; // Create a Pending Intent that will broadcast and action String ALARM_ACTION = “ALARM_ACTION”; Intent intentToFire = new Intent(ALARM_ACTION); PendingIntent alarmIntent = PendingIntent.getBroadcast(this, 0, intentToFire, 0); // Wake up the device to fire an alarm in half an hour, and every half-hour after that. alarmManager.setInexactRepeating(alarmType, timeOrLengthofWait, timeOrLengthofWait, alarmIntent);