Service一
- Service在后台运行,不可以与用户直接交互;
- 一个服务不是一个单独的进程。服务对象本身并不意味着它是在自己的进程中运行,除非另有规定,否则它与运行程序是同在一个进程中;
- 一个服务不是一个单独的线程。Service和其他组件一样,默认情况下,Service中的所有代码都是运行在主线程中;
- Service存在的价值虽然不如Activity那么清晰。但是一般都让Service执行耗时较长的操作。例如:播放音乐、下载文件、上传文件等等。但是因为Service默认运行在主线程中,因此不能直接用它来做耗时的请求或者动作,最好在Service中启动新线程来运行耗时的任务;
- 需要通过某一个Activity或其他Context对象来启动Service。context.startService() 或 context.bindService();
- Service很大程度上充当了应用程序后台线程管理器的角色。(如果Activity中新开启一个线程,当该Acitivyt关闭后,该线程依然在工作,但是与开启它的Activity失去联系。也就是说此时的这个线程处于失去管理的状态。但是使用Service,则可以对后台运行的线程有效地管理。)
- 1、Service可以放在独立的进程中,所以更安全;
- 2、使用Service可以依赖现有的binder机制,不需要在应用层面上处理线程同步的繁杂工作;
- 3、系统可以重新启动异常死去的Service。
- 不同点:Activity是与用户交互的组件,即可以看到UI界面,而Service是在后台运行、无需界面;
- 相同点:使用Activity 时我们需要在配置文件中声明<activity>标签,同样的使用Service 也需要在配置文件中声明<service>标签。都具有一定的生命周期。
- Started Service:被启动的服务
-
- 被启动的服务是由其它组件调用startService()方法而启动的,该方法会导致被启动服务的生命周期方法onStartCommand()被回调。当服务是被启动状态后,其生命周期与启动它的组件无关,即使启动服务的组件(Activity,BroadcastReceiver)已经被销毁,该服务还可以在后台无限期运行。除非调用stopSelf()或stopService()来停止该服务。
- Bound Service:被绑定的服务
-
- 绑定服务是允许其它应用程序绑定并且与之交互的Service的实现类。为了提供绑定,必须实现onBind()回调方法。该方法返回IBinder对象,它定义了服务类与Activity交互的程序接口。
- Activity通过bindService()方法绑定到服务类,同时Activity必须提供ServiceConnection接口的实现类,它监视Activity与服务类之间的连接。在重写ServiceConnection接口的onServiceConnected()方法时,实现了将服务类顺利赋值到了Activity中,实现了在Activity中使用该服务类并执行其中的方法。
- START_STICKY(常量值:1):sticky的意思是“粘性的”。使用这个返回值时,我们启动的服务跟应用程序"粘"在一起,如果在执行完onStartCommand后,服务被异常kill掉,系统会自动重启该服务。当再次启动服务时,传入的第一个参数将为null;
- START_NOT_STICKY(常量值:2):“非粘性的”。使用这个返回值时,如果在执行完onStartCommand后,服务被异常kill掉,系统不会自动重启该服务。
- START_REDELIVER_INTENT(常量值:3):重传Intent。使用这个返回值时,如果在执行完onStartCommand后,服务被异常kill掉,系统会自动重启该服务,并将Intent的值传入。
- START_STICKY:(常量值:1)车祸后自己苏醒,但是失忆;
- START_NOT_STICKY:(常量值:2)车祸后再也没有苏醒;
- START_REDELIVER_INTENT:(常量值:3)车祸后自己苏醒,依然保持记忆。
(三)、Service的生命周期:
- onCreate():创建服务
- onStartCommand():服务开始运行(在2.0以前版本中,使用onStart()回调方法)
- onDestroy() :服务被停止
- 在程序中调用:context.startService() 会触发执行Service生命周期中的onCreate()、onStartCommand()回调方法,此时服务就开始正式运行;
- 如果Service还没有运行,则android先调用onCreate()然后调用onStartCommand();如果Service已经运行,则只调用onStartCommand(),所以一个Service的onStartCommand方法可能会重复调用多次;
- 如果在程序中调用:context.stopService()会触发执行Service生命周期中的onDestroy()回调方法,会让服务停止;
- stopService()的时候直接onDestroy,如果是调用者自己直接退出而没有调用stopService()的话,Service会一直在后台运行。该Service的调用者再启动该Service后可以通过stopService关闭Service;stopSelf()
- 所以StartService的生命周期为:onCreate --> onStartCommand(可多次调用) --> onDestroy。
- onCreate():创建服务
- onBind():绑定服务,服务开始运行
- onUnbind():取消绑定
- onDestroy() :服务被停止
- 在程序中调用:context.bindService()会触发执行Service生命周期中的onCreate()、onBind()回调方法,此时服务开始运行;
- onBind将返回给客户端一个IBind接口实例,IBind允许客户端回调服务的方法,比如得到Service运行的状态或其他操作。此后调用者(Context,例如Activity)会和Service绑定在一起;
- 如果调用Service的调用者Context退出了,那么会依次调用Service生命周期中的onUnbind()、onDestroy()回调方法,会让服务停止;
- 所以BindService的生命周期为:onCreate --> onBind(只一次,不可多次绑定) --> onUnbind --> onDestory。
- Service是不能自己启动的,只有通过 Context 对象调用startService() 和bindService() 方法来启动。
- 在Service每一次的开启关闭过程中,只有onStartCommand()可被多次调用(通过多次startService调用),其他onCreate()、onBind()、onUnbind()、onDestory()在一个生命周期中只能被调用一次。
- Service可以在和多场合的应用中使用,比如播放多媒体的时候用户启动了其他Activity这个时候程序要在后台继续播放,比如检测SD卡上文件的变化,再或者在后台记录你地理信息位置的改变等等,总之服务总是藏在后头的。
- 1、写xml布局文件;
- 2、写MainActivity文件,通过按钮点击事件启动Service;
- 3、写继承于Service的StartService类文件:重写onCreate()/onStartCommand()/onDestroy()回调方法。
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<Button
android:id="@+id/button_main_play"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="clickButton"
android:text="播放音乐"/>
<Button
android:id="@+id/button_main_pause"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="clickButton"
android:text="暂停音乐"/>
<Button
android:id="@+id/button_main_stop"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="clickButton"
android:text="停止音乐"/>
<Button
android:id="@+id/button_main_exit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="clickButton"
android:text="关闭当前窗体"/>
<Button
android:id="@+id/button_main_stopservice"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="clickButton"
android:text="停止服务"/>
</LinearLayout>
publicclass MainActivity extends Activity {
privatestaticfinal String TAG = "MainActivity";
private Intent intent = null;
@Override
protectedvoid onCreate(Bundle savedInstanceState) {
Log.i(TAG, "==onCreate执行");
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
intent = new Intent(this, StartServicePlayMusic.class);
}
@Override
protectedvoid onDestroy() {
Log.i("MainActivty", "==onDestroy()");
super.onDestroy();
if (intent != null) {
// 停止服务可以通过stopService(intent)来停止,也可以intent到Service程序中,通过stopSelf()来停止。
stopService(intent);
}
}
publicvoid clickButton(View view) {
int type = 0;
switch (view.getId()) {
case R.id.button_main_play:
type = 1;
break;
case R.id.button_main_pause:
type = 2;
break;
case R.id.button_main_stop:
type = 3;
break;
case R.id.button_main_exit:
finish();
break;
case R.id.button_main_stopservice:
// 停止服务可以通过stopService(intent)来停止,也可以intent到Service程序中,通过stopSelf()来停止
// stopService(intent);
// finish();
type = 4;
break;
}
Bundle bundle = new Bundle();
bundle.putInt("type", type);
intent.putExtras(bundle);
startService(intent);
}
}
publicclass StartServicePlayMusic extends Service {
privatestaticfinal String TAG = "StartServicePlayMusic";
private MediaPlayer mediaPlayer;
@Override
public IBinder onBind(Intent intent) {
Log.i(TAG, "==onBind执行");
returnnull;
}
@Override
publicvoid onCreate() {
Log.i(TAG, "==onCreate执行");
super.onCreate();
if (mediaPlayer == null) {
mediaPlayer = MediaPlayer.create(this, R.raw.hitta);
mediaPlayer.setLooping(false);
}
}
@Override
publicint onStartCommand(Intent intent, int flags, int startId) {
Log.i(TAG, "==onStartCommand执行");
if (intent != null) {
Bundle bundle = intent.getExtras();
int type = bundle.getInt("type");
switch (type) {
case 1:
play();
break;
case 2:
pause();
break;
case 3:
stop();
break;
case 4:
stopSelf();
break;
}
}
returnSTART_STICKY;
}
@Override
publicvoid onDestroy() {
Log.i(TAG, "==onDestroy执行");
super.onDestroy();
if (mediaPlayer != null) {
mediaPlayer.stop();
mediaPlayer.release();
}
}
publicvoid play() {
if (!mediaPlayer.isPlaying()) {
mediaPlayer.start();
}
}
publicvoid pause() {
if (mediaPlayer.isPlaying()) {
mediaPlayer.pause();
}
}
publicvoid stop() {
if (mediaPlayer != null) {
mediaPlayer.stop();
}
}
}
<service
android:name=".StartServicePlayMusic">
<intent-filter>
<actionandroid:name="com.steven.startservice.playmusic"/>
</intent-filter>
</service>
- Activity页面中需要startService(intent) 和 stopService(intent)两个方法来启动Service和停止Service;
- 继承于Service类的自定义子类——MyStartService类中,生命周期回调方法有:onCreate() 、onStartCommand() 、onDestroy();
- 如果停止服务,可以在Activity中调用stopService(intent),也可以intent到Service中执行stopSelf()方法;
- 执行停止服务方法,会回调Service生命周期中的onDestroy()方法;
- 如果希望关闭Activity窗体,服务也停止,那么在Activity的onDestroy()方法中执行stopService()方法。如果希望关闭窗体后,服务还继续,那么Activity的onDestroy()中不执行停止服务即可;
- 在StartService中不会回调onBind()方法;
- 在停止服务后,如果再次点击“播放”,可以重新启动StartService。
- Creates a default worker thread that executes all intents delivered to onStartCommand() separate from your application's main thread.
- 生成一个默认的且与主线程互相独立的工作者线程来执行所有传送至 onStartCommand() 方法的Intetnt
- Creates a work queue that passes one intent at a time to your onHandleIntent() implementation, so you never have to worry about multi-threading.
- 生成一个工作队列来传送Intent对象给你的onHandleIntent()方法,同一时刻只传送一个Intent对象,这样一来,你就不必担心多线程的问题。
- Stops the service after all start requests have been handled, so you never have to call stopSelf().
- 在所有的请求(Intent)都被执行完以后会自动停止服务,所以,你不需要自己去调用stopSelf()方法来停止该服务
- Provides default implementation of onBind() that returns null.
- 提供了一个onBind()方法的默认实现,它返回null
- Provides a default implementation of onStartCommand() that sends the intent to the work queue and then to your onHandleIntent() implementation
- 提供了一个onStartCommand()方法的默认实现,它将Intent先传送至工作队列,然后从工作队列中每次取出一个传送至onHandleIntent()方法,在该方法中对Intent对相应的处理
publicclass DownloadService extends IntentService {
privatestaticfinal String TAG = "DownloadService";
private String urlString = "https://www.google.com.hk/images/srpr/logo11w.png";
private NotificationCompat.Builder builder = null;
private NotificationManager manager = null;
public DownloadService() {
super("");
}
@Override
protectedvoid onHandleIntent(Intent intent) {
manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
builder = new NotificationCompat.Builder(getApplicationContext());
builder.setSmallIcon(R.drawable.ic_launcher);
builder.setContentTitle("提示:");
builder.setContentText("图片加载完成,请点击查看!");
builder.setTicker("图片加载完成");
builder.setAutoCancel(true);
Intent intent2 = new Intent(getApplicationContext(), MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pIntent = PendingIntent.getActivity(
getApplicationContext(), 0, intent2,
PendingIntent.FLAG_ONE_SHOT);
builder.setContentIntent(pIntent);
byte[] data = HttpClientHelper.loadByteFromURL(urlString);
boolean flag = SDCardHelper.saveFileToSDCard(data, "Download",
"logo11w.png");
if (flag) {
manager.notify(1, builder.build());
}
}
}
publicclass DownloadService extends Service {
privatestaticfinal String TAG = "DownloadService";
private String urlString = "https://www.google.com.hk/images/srpr/logo11w.png";
private NotificationCompat.Builder builder = null;
private NotificationManager manager = null;
@Override
public IBinder onBind(Intent intent) {
returnnull;
}
@Override
publicvoid onCreate() {
super.onCreate();
manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
builder = new NotificationCompat.Builder(getApplicationContext());
builder.setSmallIcon(R.drawable.ic_launcher);
builder.setContentTitle("提示:");
builder.setContentText("图片加载完成,请点击查看!");
builder.setTicker("图片加载完成");
builder.setAutoCancel(true);
Intent intent = new Intent(getApplicationContext(), MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pIntent = PendingIntent
.getActivity(getApplicationContext(), 0, intent,
PendingIntent.FLAG_ONE_SHOT);
builder.setContentIntent(pIntent);
}
@Override
publicint onStartCommand(Intent intent, int flags, int startId) {
new Thread(new Runnable() {
@Override
publicvoid run() {
byte[] data = HttpClientHelper.loadByteFromURL(urlString);
boolean flag = SDCardHelper.saveFileToSDCard(data, "Download",
"logo11w.png");
if (flag) {
manager.notify(1, builder.build());
stopSelf();
}
}
}).start();
returnSTART_STICKY;
}
@Override
publicvoid onDestroy() {
super.onDestroy();
}
}
- 1、写xml布局文件;
- 2、写MainActivity文件,构建ServiceConnection对象,重写其中的抽象方法onServiceDisconnected()和onServiceConnected();
- 3、写继承于Service的BindService类文件,定义继承于Binder的内部类MyBinder,在其中定义方法getService();
- 4、BindService类中重写onCreate()方法、重写onBind()回调方法,onBind()方法返回MyBinder对象,重写onDestroy()方法;
publicclass MainActivity extends Activity {
privatestaticfinal String TAG = "MainActivity";
private Intent intent;
private ServiceConnection conn = null;
private BindServicePlayMusic musicService;
@Override
protectedvoid onCreate(Bundle savedInstanceState) {
Log.i(TAG, "==onCreate执行");
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 启动服务有多种写法:
// 可以通过new Intent(action字符串)来实现;
// intent = new Intent("com.steven.bindservice.playmusic");
intent = new Intent(this, BindServicePlayMusic.class);
conn = new ServiceConnection() {
@Override
publicvoid onServiceDisconnected(ComponentName name) {
musicService = null;
}
@Override
publicvoid onServiceConnected(ComponentName name, IBinder service) {
musicService = ((BindServicePlayMusic.MyBinder) service)
.getService();
if (musicService != null) {
musicService.play();
}
}
};
}
publicvoid clickButton(View view) {
switch (view.getId()) {
case R.id.button_main_play:
if (musicService == null) {
bindService(intent, conn, Context.BIND_AUTO_CREATE);
} else {
musicService.play();
}
break;
case R.id.button_main_pause:
if (musicService != null) {
musicService.pause();
}
break;
case R.id.button_main_stop:
if (musicService != null) {
musicService.stop();
}
break;
case R.id.button_main_exit:
finish();
break;
case R.id.button_main_stopservice:
// BindService中stopService(intent)不起作用,要通过undbindService来停止服务
// stopService(intent);
// musicService = null的目的是如果停止服务后,再次”播放“,可以正常执行。
// 如果不将musicService设置为null,再次播放时,将直接执行musicService.play(),而不执行bindService(),那么会导致异常
musicService = null;
unbindService(conn);
break;
}
}
}
publicclass BindServicePlayMusic extends Service {
privatestaticfinal String TAG = "BindServicePlayMusic";
private MediaPlayer mediaPlayer;
private IBinder binder = null;
@Override
publicvoid onCreate() {
Log.i(TAG, "==onCreate执行");
super.onCreate();
if (mediaPlayer == null) {
mediaPlayer = MediaPlayer.create(this, R.raw.heavencity);
mediaPlayer.setLooping(false);
}
binder = new MyBinder();
}
class MyBinder extends Binder {
public BindServicePlayMusic getService() {
return BindServicePlayMusic.this;
}
};
@Override
public IBinder onBind(Intent intent) {
Log.i(TAG, "==onBind执行");
play();
returnbinder;
}
@Override
publicboolean onUnbind(Intent intent) {
Log.i(TAG, "==onUnbind执行");
returnsuper.onUnbind(intent);
}
@Override
publicvoid onDestroy() {
Log.i(TAG, "==onDestroy执行");
super.onDestroy();
if (mediaPlayer != null) {
mediaPlayer.stop();
mediaPlayer.release();
}
}
publicvoid play() {
if (!mediaPlayer.isPlaying()) {
mediaPlayer.start();
}
}
publicvoid pause() {
if (mediaPlayer.isPlaying()) {
mediaPlayer.pause();
}
}
publicvoid stop() {
if (mediaPlayer != null) {
mediaPlayer.stop();
}
}
}
<service
android:name=".BindServicePlayMusic">
<intent-filter>
<actionandroid:name=“com.steven.bindservice.playmusic"/>
</intent-filter>
</service>
- 与用户正发生交互;
- 它控制一个与用户交互的必须的基本的服务;
- 一个正在调用生命周期回调方法的ervice(如onCreate()、onStar()、onDestroy());
- 一个正在运行onReceive()方法的广播接收对象。
Service二——Android系统服务
(二)、DownloadManager主要提供了下面几个接口:
1、public long enqueue(Request request)执行下载,返回downloadId,downloadId可用于后面查询下载信息。若网络不满足条件、Sdcard挂载中、超过最大并发数等异常会等待下载,正常则直接下载。
2、public int remove(long… ids)删除下载,若下载中取消下载。会同时删除下载文件和记录。
4、public static LonggetRecommendedMaxBytesOverMobile(Context context通过移动网络下载的最大字节数
5、public String getMimeTypeForDownloadedFile(long id)得到下载的mimeType,如何设置后面会进行介绍
其它:通过查看代码我们可以发现还有个CursorTranslator私有静态内部类。这个类主要对Query做了一层代理。将DownloadProvider和DownloadManager之间做个映射。将DownloadProvider中的十几种状态对应到了DownloadManager中的五种状态,DownloadProvider中的失败、暂停原因转换为了DownloadManager的原因。
DownloadManager downloadManager = (DownloadManager)getSystemService(DOWNLOAD_SERVICE);
String apkUrl = "http://img.meilishuo.net/css/images/AndroidShare/Meilishuo_3.6.1_10006.apk";
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(apkUrl));
request.setDestinationInExternalPublicDir("Trinea", "abc.mp4");
设置下载文件保存的路径
// request.setTitle("文件下载");
设置下载中通知栏提示的标题
// request.setDescription("保存的文件名称");
设置下载中通知栏提示的介绍
// request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
表示下载进行中和下载完成的通知栏是否显示。默认只显示下载中通知。VISIBILITY_VISIBLE_NOTIFY_COMPLETED表示下载完成后显示通知栏提示。
// request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_HIDDEN);
VISIBILITY_HIDDEN表示不显示任何通知栏提示,这个需要在AndroidMainfest中添加权限android.permission.DOWNLOAD_WITHOUT_NOTIFICATION.
// request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI);
表示下载允许的网络类型,默认在任何网络下都允许下载。有NETWORK_MOBILE、NETWORK_WIFI、NETWORK_BLUETOOTH三种及其组合可供选择。如果只允许wifi下载,而当前网络为3g,则下载会等待。
// request.setMimeType("video/mp4");
设置下载文件的mineType。因为下载管理Ui中点击某个已下载完成文件及下载完成点击通知栏提示都会根据mimeType去打开文件,所以我们可以利用这个属性。比如上面设置了mimeType为application/cn.trinea.download.file,我们可以同时设置某个Activity的intent-filter为application/cn.trinea.download.file,用于响应点击的打开文件。
long downloadId = downloadManager.enqueue(request);
调用downloadManager的enqueue接口进行下载,返回唯一的downloadId。一般使用传感器都有以下5个步骤:
1、调用Context的getSystemService(Context.SENSOR_SERVICE)方法获取SensorManager对象;
2、调用SensorManager的getDefaultSensor(int type)方法获取指定类型的传感器;
3、在onCreate()生命周期方法中调用SensorManager的registerListener()方法为指定的传感器注册监听;
4、实例化SensorEventListener接口,作为registerListener()方法的第一个参数。重写SensorEventListener接口中onSensorChanged()方法;
5、在onDestroy()生命周期方法中调用SensorManager对象的unregisterListener()方法释放资源。
六、TelephonyManager:【详见监听来电广播一章】
(一)、基本用法:
1、获取电话状态:
TelephonyManager manager = (TelephonyManager) context .getSystemService(Service.TELEPHONY_SERVICE);
int state = manager.getCallState();Service二——跨进程访问AIDL
publicclass InCallReceiver extends BroadcastReceiver {
private TelephonyManager manager = null;
@Override
publicvoid onReceive(Context context, Intent intent) {
manager = (TelephonyManager) context
.getSystemService(Service.TELEPHONY_SERVICE);
switch (manager.getCallState()) {
case TelephonyManager.CALL_STATE_RINGING:
String incomingNumber = intent.getStringExtra("incoming_number");
if ("12345678".equals(incomingNumber)) {
try {
// 获得TelephonyManager的class对象
Class<TelephonyManager> telephonyManagerClass = TelephonyManager.class;
// 获得TelephonyManager.getITelephony方法的Method对象
Method telephonyMethod = telephonyManagerClass
.getDeclaredMethod("getITelephony", (Class[]) null);
// 允许访问私有的方法
telephonyMethod.setAccessible(true);
// 调用getITelephony()方法返回ITelephony对象
ITelephony telephony = (com.android.internal.telephony.ITelephony) telephonyMethod
.invoke(manager, (Object[]) null);
// 挂断电话
telephony.endCall();
} catch (Exception e) {
Toast.makeText(context, e.getMessage(), Toast.LENGTH_LONG)
.show();
}
}
break;
}
}
}