参考《Professional Android 4 Development》

Services

Service是invisible的,因此其优先级不高于visible的Activity,之所以说不高于,是因为我们可以设置Service为在前台运行。

创建Service

Android提供了Service抽象类,继承它便可以创建一个Service类:

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
public class MyService extends Service {@Overridepublic void onCreate() {super.onCreate();// TODO: Actions to perform when service is created.}@Overridepublic IBinder onBind(Intent intent) {// TODO: Replace with service binding implementation.return null;}
}

创建Service类之后,还需要在Manifest里面注册:

<service android:enabled=”true” android:name=”.MyService” android:permission=”com.paad.MY_SERVICE_PERMISSION”/>

若要默认只有自己的程序可以使用这个Service,需要添加Android:permission属性。其他Application若要使用这个服务,需要加入这个permission。

执行Service

当Service由startService()方法调用时,即可引起onStartCommand方法的调用,因此需要重写Service中的onStartCommand方法,并且onStartCommand方法可能会被多次调用。onStartCommand()方法将返回一个int值,用于指定当Service被runtime杀掉又重启的时,系统该如何响应:

@Override
public int onStartCommand(Intent intent, int flags, int startId) {startBackgroundTask(intent, startId);return Service.START_STICKY;
}

重启Service

onStartCommand()方法可以返回这些参数,它们的意义是:

START_STICKY:如果service进程被kill掉,保留service的状态为开始状态,但不保留递送的intent对象。随后系统会尝试重新创建service,由于服务状态为开始状态,所以创建服务后一定会调用onStartCommand(Intent,int,int)方法。如果在此期间没有任何启动命令被传递到service,那么参数Intent将为null。

START_NOT_STICKY:“非粘性的”。如果在执行完onStartCommand后,服务被异常kill掉,系统不会自动重启该服务。
START_REDELIVER_INTENT:使用这个返回值时,如果未执行完onStartCommand,服务在调用stopSelf之前被kill掉,系统会自动重启该服务,并将Intent的值传入。

参考:http://www.krislq.com/2013/05/android-class-return-value-of-onstartcommand/

启动和停止服务

调用startService方法可以启动服务:

private void explicitStart() {// Explicitly start My ServiceIntent intent = new Intent(this, MyService.class);// TODO Add extras if required.startService(intent);
}
private void implicitStart() {// Implicitly start a music ServiceIntent 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到Activity

首先,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 parametersNotification notification = new Notification(R.drawable.icon, “Starting Playback”, System.currentTimeMillis());notification.setLatestEventInfo(this, album, artist, pi);// Set the Notification as ongoingnotification.flags = notification.flags | Notification.FLAG_ONGOING_EVENT;// Move the Service to the ForegroundstartForeground(NOTIFICATION_ID, notification);
}

使用stopForeground方法可以取消Service的前台属性:

public void pausePlayback() {// Move to the background and remove the NotificationstopForeground(true);
}

使用后台线程

Service和Activity一样,也是在主线程中运行的,为了更好地响应用户,我们需要使用后台线程的方式执行Service。Android提供了两个抽象类来帮助我们实现:AsyncTask和IntentService。

使用AsyncTask

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方法。这三个方法的说明:

  • doInBackground: 这个方法用于执行需要在后台线程中长期运行的操作,可以通过publishProgress方法传递参数给onProgressUpdate;在这个方法执行完毕之后,此方法将返回值传递给onProgressUpdate。
  • onProgressUpdate: 接收publishProgress方法传入的参数,更新UI。
  • onPostExecute: doInBackground执行结束后,将返回值传入此方法。

执行AsyncTask

String input = “redrum ... redrum”;
new MyAsyncTask().execute(input);

Intent Service简介

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.}@Overridepublic void onCreate() {super.onCreate();// TODO: Actions to perform when service is created.}@Overrideprotected 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简介

Loader是一个抽象类,封装了异步加载数据的最佳实践,最典型的就是CursorLoader了。Android中创建Loader类的简单方法是继承AsyncTaskLoader类,并实现这两个功能:

  • 异步加载数据
  • 监测数据源的变化并及时更新

手动创建线程及GUI线程同步

尽管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 ... ]
}

与GUI线程同步:

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);

使用ALARMS

与Timer不太,Alarms属于系统服务,独立于应用程序。即使应用程序为启动,也可以使用Alarms启动应用程序并获取其服务,这样不仅减少了耦合,也减少了系统资源的占用。Android中Alarms常与Broadcast Receiver一起使用。创建Alarm之前,首先要创建AlarmManager:

AlarmManager alarmManager = (AlarmManager)getSystemService(Context.ALARM_SERVICE);

创建,设置和取消ALARMS

创建Alarm需要这些参数:alarm类型,触发时间,Alarm将要触发的Pending Intent。目前Alarm类型有这些:

  • RTC_WAKEUP:在指定时间启动指定Pending Intent,可以唤醒sleep中的设备。
  • RTC:在指定时间启动指定Pending Intent,但不能唤醒sleep中的设备。
  • ELAPSED_REALTIME:在某段时间后启动指定的Pending Intent,某段时间是从设备启动但还没有唤醒设备算起。
  • ELAPSED_REALTIME_WAKEUP: 这个和ELAPSED_REALTIME的区别没搞明白,以后遇到了再查吧。

下面是一个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);

取消Alarm

alarmManager.cancel(alarmIntent);

这里的alarmIntent是指使用Alarm启动的Pending Intent。

创建可重复的Alarm

使用setRepeating或setInexactRepeating方法替代前面的set方法,并传递响应的参数进去,就可以实现可重复的Alarm。

相比setRepeating,setInexactRepeating更省电,但不能指定某个具体的时间间隔。

setInexactRepeating可以接收的时间间隔参数:

  • INTERVAL_FIFTEEN_MINUTES
  • INTERVAL_HALF_HOUR
  • INTERVAL_HOUR
  • INTERVAL_HALF_DAY
  • INTERVAL_DAY

下面这个例子指定半小时后启动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);

转载于:https://www.cnblogs.com/jubincn/p/3521452.html

Android 4 学习(19):Services相关推荐

  1. Android SurfaceFlinger 学习之路(五)----VSync 工作原理

    原址 VSync信号的科普我们上一篇已经介绍过了,这篇我们要分析在SurfaceFlinger中的作用.(愈发觉得做笔记对自己记忆模块巩固有很多帮助,整理文章不一定是用来给别人看的,但一定是为加强自己 ...

  2. android service 学习(上)

    转载自:http://www.cnblogs.com/allin/archive/2010/05/15/1736458.html Service是android 系统中的一种组件,它跟Activity ...

  3. Android:学习AIDL,这一篇文章就够了(下)

    前言 上一篇博文介绍了关于AIDL是什么,为什么我们需要AIDL,AIDL的语法以及如何使用AIDL等方面的知识,这一篇博文将顺着上一篇的思路往下走,接着介绍关于AIDL的一些更加深入的知识.强烈建议 ...

  4. android java服务,Android进阶学习必会:Java Binder中的系统服务

    前言 这个知识点是Android进阶学习必须掌握的知识点之一,也是高阶Android架构师经常问到的点.在这里分想给大家,希望对大家的工作和学习有所帮助.喜欢本文的记得点赞关注哦~ 在前面的Andro ...

  5. android ApiDemos学习1 主界面动态ListView显示

    0 Android提供了一个供开发者学习使用的示例程序.其界面如下.图中可以看到,应用列表应为ListView,看其源码发现,并非为简单的ListView,而是采用动态加载的方式. 1 主界面代码如下 ...

  6. android开发学习之路——连连看之游戏逻辑(五)

    GameService组件则是整个游戏逻辑实现的核心,而且GameService是一个可以复用的业务逻辑类. (一)定义GameService组件接口 根据前面程序对GameService组件的依赖, ...

  7. 修改android framework学习

    2019独角兽企业重金招聘Python工程师标准>>> 1:android平台编译自己编写的framework级service server实录 http://blog.sina.c ...

  8. Android 布局学习之——Layout(布局)详解一

    layout(布局)定义了用户界面的可视化结构(visual structure),如Activity的UI,应用窗口的UI. 有两种方式声明layout: 1.在xml文件中声明UI组件. 2.在运 ...

  9. android博客导航总结,以及个人常用android免费学习干货(文章,视频,矢量图,字体等)资源分享?

    android博客导航总结与资源分享 1.博客总结 1.mob平台的使用 2.QMUI部分功能实现 3.XUI部分功能实现 4.其他功能 5.Flutter博客总结: 2.资源分享 1.文章类型资源分 ...

最新文章

  1. Qt中文手册 之 QApplication
  2. 一个简单的Spring的AOP例子(JAVA面向切面编程)
  3. openresty开发系列25--openresty中使用json模块
  4. 《Ruby程序员修炼之道》(第2版)目录—导读
  5. qt5 窗体显示完毕信号_iPhone手机信号不好?试试这样设置,随时随地让你的手机信号满格...
  6. Reproxy:边缘服务器反向代理工具
  7. 银行java程序员面试题_Java程序员面试题集精选
  8. 计算机实验室安全知识心得体会,浅谈高校计算机实验室的安全管理
  9. Paraview:Python Calculator Filter
  10. Linux 中 $符号是什么意思,代表什么含义
  11. 基于单片机的脉搏心率远程监测
  12. 数据库设计规范(详细)
  13. 无法使用计算机名访问共享,局域网内无法用计算机名访问共享的解决办法
  14. 工业控制信息系统中的商用密码应用思考
  15. linux 6.5光驱是什么意思,linux 6和5有什么不同
  16. rrpp协议如何修改_RRPP配置注意事项
  17. java好学么_java是什么好学吗
  18. iOS开发--音频播放、录音、视频播放、拍照、视频录制
  19. 用html将竖的图片打横,【收藏】让竖版图片变横版不变形的两种方法
  20. 立体几何中常见的建系类型汇总

热门文章

  1. java hive demo_java 操作hive通过jdbc
  2. java 主备切换_keepalived 实现 Java 服务的高可用(主备切换)
  3. mysql 学生成绩等级_JSP+SSM+Mysql实现的学生成绩管理系统
  4. moel vue 自定义v_vue在自定义组件中使用v-model的方法
  5. js正则表达式限制文本框只能输入数字,小数点,英文字母
  6. go语言一天入门(下)
  7. IOS内购流程从0-1手把手教会
  8. 矩阵论-范数理论及其应用
  9. 《Python Cookbook 3rd》笔记(5.14):忽略文件名编码
  10. C++ std::iota递增