Android的Service 的使用教程(实例)

来源:互联网 发布:价格监控软件开发 编辑:程序博客网 时间:2024/05/16 05:26

Android的服务教程

拉尔斯· 沃格尔

2.6版

2013年5月22日

修订历史修订0.107.03.2011拉尔斯 
沃格尔 
创建修订0.2 - 2.62011年3月8日 - 2013年5月22日拉尔斯 
沃格尔 
错误修正和增强功能

在Android发展自己的服务和使用的系统服务

本教程介绍了如何创建和使用Android服务。 它是基于Eclipse的4.2,JAVA 1.6和Android 4.2。


篇目

1。 Android的服务
1.1。 服务
1.2。 Android平台服务
1.3。 定义新服务
2。 定义服务
2.1。 声明自己的服务
2.2。 运行在自己的进程服务
2.3。 当运行一个单独的进程中的服务吗?
2.4。 意向书服务
3。 广播接收器
4。 启动服务
4.1。 启动服务
4.2。 停止服务
4.3。 活动和本地服务之间的结合
4.4。 定期通过AlarmManager的启动服务
5。 沟通与服务
5.1。 活动结合于本地服务
5.2。 使用接收器
5.3。 在不同的进程服务AIDL
5.4。 发送意向数据和捆绑服务
5.5。 处理程序和Messenger
6。 教程:使用IntentService
7。 教程:定义和使用本地服务
8。 谢谢
9。 问题与讨论
10。 链接和文学
10.1。 源代码
10.2。 Android的资源
10.3。 vogella资源

1。 Android的服务

1.1。 服务

服务是一个组件,它在后台运行,不直接与用户的交互。 Android平台提供和运行预定义的系统服务,每一个Android应用程序可以使用它们,给予正确的权限。

一个Android应用程序,除了消耗现有的Android平台服务,定义和使用新服务 。

1.2。 Android平台服务

Android平台提供预先定义的服务 ,通常是通过特定的管理类暴露。 对它们的访问可以通过getSystemService()方法获得。

1.3。 定义新服务

每一个Android应用程序可以定义并启动新服务

如果您使用相应的线程异步处理的活动片段仍然连接到相应的活动的生命周期。 Android系统可能会决定终止他们在任何时间点。

服务运行具有更高优先级比无效或无形的活动 ,因此它不太可能是Android系统终止。

定义自己的服务,让您设计非常敏感的应用。 您可以获取该应用程序通过一个服务 ,一旦应用程序由用户启动的,它可以提出新的数据给用户。

2。 定义服务

2.1。 声明自己的服务

一个服务需要在AndroidManifest.xml声明和实现类必须扩展Service类或它的一个子类。 下面的代码显示了一个服务宣言及其实施的一个例子。

  <服务  机器人:名称=“MyService”的  安卓图标=“@绘制/图标”   Android版 ​​本:标签=“@字符串/ SERVICE_NAME”   > </服务> 

  公共类 MyService 延伸服务{   @覆盖   公众诠释的 onStartCommand(意向意图,int标志的, 诠释 startId的){     / / TODO做些有益的事     返回 Service.START_NOT_STICKY;   }   @覆盖   公众的IBinder onBind(意向书意图){   / / TODO通信返回的IBinder实施     返回 null;   } } 

默认情况下为应用程序在同一进程中运行服务 。 在自己的线程。

因此,你需要在服务中使用异步处理,在后台执行资源密集型任务。

运行的应用程序的过程中,有时被称为本地services 。

2.2。 运行在自己的进程服务

您也可以指定你的Service运行在一个单独的进程通过android:process=":process_description"属性。

  <服务  机器人:名称=的“WordService”   Android版 ​​本:过程“:my_process”   安卓图标=“@绘制/图标”   Android版 ​​本:标签=“@字符串/ SERVICE_NAME”   > </服务> 

冒号前缀的名称前告诉Android的Service是私有声明应用。 如果不使用冒号的Service将是一个全球性的过程中,可以使用的其他Android应用程序。

运行在自己的进程服务不会阻止应用程序的情况下进行长时间运行的服务业务在其主线程。 但是,作为服务运行在自己的进程,你需要使用一些进程间通信(IPC)的沟通为您服务的其他部分。

即使服务运行在其自己的过程中,你需要使用异步处理,执行网络访问,因为Android不允许在主线程中的一个进程的网络访问。

2.3。 当运行一个单独的进程中的服务吗?

运行在自己的进程的服务给它自己的内存地址空间和在这个过程中的虚拟机的垃圾收集器不影响应用程序的过程。

应用程序很少需要运行在自己的进程服务 。 运行在自己的进程的服务使其他Android组件的通信和服务更难实现。

如果你想使其他Android应用程序提供的服务 ,他们必须在自己的进程中运行。

2.4。 意向书服务

您还可以扩展为您服务实现IntentService类 ​​。

IntentService是用来执行特定任务,在后台。 一旦完成,实例IntentService自动终止本身。 它的使用情况的实施例将是从互联网上下载目标的资源。

IntentService类 ​​提供了onHandleIntent()方法将异步调用Android系统。

3。 广播接收器

BroadcastReceiver引入,请参阅Android广播接收机的教程 。

4。 启动服务

4.1。 启动服务

一个Android组件(服务,接收器,活动)可以启动和触发服务通过startService(intent)方法。 此方法调用启动服务 ,如果它没有运行。

 意向书服务= 新的意向书(的背景下,为MyService  ​​); context.startService(服务); 

如果启动该服务 onCreate()方法被调用。

一旦启动该服务的方法调用,触发启动服务 startService(intent)方法在服务 。 它传递IntentstartService(intent)调用的Intent 。

如果startService(intent) 服务正在运行时,被称为onStartCommand()也被称为。 因此,您的服务onStartCommand()可以被多次调用,需要做好准备。 在主用户界面线程,因此它不能被称为从两个不同的线程同时调用此方法。

startService(intent)或者你也可以开始通过bindService()方法调用服务 。 这使您可以直接沟通与服务

4.2。 停止服务

停止服务,通过stopService()方法。 不管你如何频繁启动服务 startService(intent)调用stopService()停止。

停止服务可以通过调用stopSelf()方法。

4.3。 活动和本地服务之间的结合

如果活动要与服务交互,它可以使用bindService()方法来启动服务 。

此方法要求参数a ServiceConnection对象,它允许连接到服务 。 服务onBind()方法被调用。 此方法返回IBinder对象ServiceConnection 。

可以用于此IBinder对象的活动,与服务进行通信。

之后绑定做onStartCommand()方法被调用的Intent活动所提供的数据。

startService()也允许你提供一个标志,它决定了重新启动的服务行为。 Service.START_STICKY用于服务是显性的启动或停止。 如果这些服务被终止了Android系统,它们被重新启动,如果有足够的资源再次可用。

开始Service.START_NOT_STICKY服务不会自动重新启动,如果终止了Android系统。

4.4。 定期通过AlarmManager的启动服务

正如活动的Android系统可能终止服务的过程中,在任何时间,以节省资源。 出于这个原因,你不能简单的使用TimerTask服务,以确保它是定期执行。

为了正确的调度Service使用AlarmManager类,。 下面的代码演示了如何做到这一点。

 日历CAL = Calendar.getInstance();意向意图= 新的意图( 这一点 ,则将MyService  ​​); PendingIntent pintent = PendingIntent.getService(,0,意图,0); AlarmManager的报警器=(AlarmManager的)getSystemService(Context.ALARM_SERVICE); / /开始每隔30秒 alarm.setRepeating(AlarmManager.RTC_WAKEUP cal.getTimeInMillis(),30 * 1000,pintent); 

5。 沟通与服务

有几种方法的活性的通信服务 ,反之亦然。 本节dicusses的不同方法,并给出了建议使用。

5.1。 活动结合于本地服务

如果Service在同一进程中开始的活动 , 活动可以直接绑定到该服务。 这是一个相对简单的和有效的方式进行通信。

5.2。 使用接收器

您还可以使用动态注册接收的通信。 例如您的活动可以动态注册一个接收器服务发送超时相应的事件。

5.3。 在不同的进程服务AIDL

绑定到一个服务运行在不同的进程,你需要使用,需要将数据发送给不同的进程之间的进程间通信(IPC)。 为此,您需要创建一个类似于Java接口,但.aidl文件扩展名结尾,只允许延长其他AIDL文件AIDL文件。

这种方法是必需的,如果你的服务,应提供给其他应用程序,否则你应该更喜欢本地服务。

5.4。 发送意向数据和捆绑服务

服务接收数据从起始的电子组件,可以使用这些数据。

5.5。 处理程序和Messenger

如果该服务应交流的活动 ,它可以接收通过从活动Messenger Intent收到数据对象类型Messenger 如果Messenger绑定到一个Handler活动service对象发送Message类型活动 。

Å的Messenger是parcelable的,这意味着它可以被传递给另一个进程发送MessagesHandler中的活动,你可以使用此对象。

Messenger还提供的方法getBinder()它允许通过Messenger 活动 。 因此活动可以发送Messages到该服务 。

6。 教程:使用IntentService

下面的例子演示了如何使用IntentService类 ​​从互联网上下载文件。 一旦完成IntentService使用Messenger类的一个实例,告知活动启动服务下载的文件的位置。

创建名为MainActivity一个活动 ,一个新的项目名为de.vogella.android.intentservice.download。

创建“下载服务”的服务,通过创建下面的类和AndroidManifest.xml中的条目。 另外添加权限写入到外部存储和访问Internet的文件。

   de.vogella.android.intentservice.download; 进口的java.io.File; 导入 java.io.FileOutputStream; 进口 java.io.IOException异常; 导入的java.io.InputStream; 进口 java.io.InputStreamReader; 导入的java.net.URL; 导入 android.app.Activity; 进口 android.app.IntentService; 导入 android.content.Intent; 导入 android.net.Uri; 进口 android.os.Bundle; 导入 android.os.Environment; 导入 android.os.Message; 导入 android.os.Messenger; 导入 android.util.Log; 公共类下载服务延伸 IntentService {   私人结果= Activity.RESULT_CANCELED;   的公共下载服务(){      (“下载服务”);   }   / /异步调用的是Android   @覆盖   受保护的无效 onHandleIntent的(意向书意图){    乌里数据= intent.getData();    字符串urlPath = intent.getStringExtra(“urlpath);    字符串文件名= data.getLastPathSegment();    文件输出= 新的文件(Environment.getExternalStorageDirectory()        文件名);     ,如果 (output.exists()){       output.delete();     }     InputStream的流= NULL;    文件输出流FOS = NULL;     尝试 {      网址URL = 新的 URL(urlPath)的;      流= url.openConnection()的getInputStream();      读卡器= 的InputStreamReader InputStreamReader的(流);       FOS = 新的文件输出流(output.getPath());       = - 1;        ((第二天reader.read())= - 1){         fos.write(下);       }       / / SUCESSFUL成品      导致= Activity.RESULT_OK;     } 赶上 (例外五){       e.printStackTrace();     最后 } {       (流!= NULL){         尝试 {           stream.close();         } 赶上 (IOException异常E){           e.printStackTrace();         }       }       (FOS = NULL){         尝试 {           fos.close();         } 赶上 (IOException异常E){           e.printStackTrace();         }       }     }    捆绑附加功能= intent.getExtras器();     (临时演员!= NULL){      信使信使中=(信使)extras.get(“信使”);      留言味精= Message.obtain();       msg.arg1 =结果;       msg.obj = output.getAbsolutePath();       尝试 {         messenger.send(MSG);       } 赶上 (E1 android.os.RemoteException){         Log.w(的getclass:()。的getName(),“异常发送消息”,E1);       }     }   } } 

  <?XML版本=“1.0”编码=“UTF-8”? <舱单的xmlns:机器人=“http://schemas.android.com/apk/res/android”      =“de.vogella.android.intentservice.download”     Android版 ​​本:VERSIONCODE =“1”     Android版 ​​本:VERSIONNAME =“1.0”>     <uses-sdk android:minSdkVersion= "15" />     <uses-permission android:name= "android.permission.INTERNET" />     <uses-permission android:name= "android.permission.WRITE_EXTERNAL_STORAGE" />     <应用程序        安卓图标=“@绘制/ ic_launcher的”        机器人:标签=“@字符串/ APP_NAME”>         <活动            机器人:名称=“MainActivity”            机器人:标签=“@字符串/ APP_NAME”>             <intent-filter>                 <action android:name= "android.intent.action.MAIN" />                 <category android:name= "android.intent.category.LAUNCHER" />             </意图过滤器>         </活动>         <service android:name= "DownloadService">         </服务>     </> </清单> 

更改main.xml布局下面的内容。

  <?XML版本=“1.0”编码=“UTF-8”? <的LinearLayout XMLNS:机器人=“http://schemas.android.com/apk/res/android”    机器人:layout_width =“match_parent”    机器人:layout_height =“match_parent”    机器人:方向=“垂直”>     <按钮         Android版 ​​本:ID =“@ + id/button1”        机器人:layout_width =“wrap_content”        机器人:layout_height =“wrap_content”        安卓的onClick =“的onClick”         Android版 ​​本:文本=“按钮”/> </ LinearLayout中> 

MainActivity下面的内容。

   de.vogella.android.intentservice.download; 导入 android.app.Activity; 导入 android.content.Intent; 导入 android.net.Uri; 进口 android.os.Bundle; 导入 android.os.Handler; 导入 android.os.Message; 导入 android.os.Messenger; 导入 android.view.View; 导入 android.widget.Toast; 公共类 MainActivity 活动 {   私人处理程序处理程序= 新的Handler(){     公共无效的handleMessage(消息消息){      对象路径message.obj;       (message.arg1 ==的RESULT_OK &&路径!= NULL){         Toast.makeText(MainActivity.              “下载”+ path.toString(),Toast.LENGTH_LONG)            秀();       } {         Toast.makeText(MainActivity. 这个 “下载失败。”             Toast.LENGTH_LONG)。的show();       }     };   };   @覆盖   公共无效的onCreate(捆绑savedInstanceState){     超级倚仗(savedInstanceState),;    的setContentView(R.layout.main);   }   公共无效的onClick(查看视图){    意向意图= 新的意图( 这一点 ,下载服务 );     / /创建一个新的通信回使者    信使信使= 新的信使(处理器);     intent.putExtra(“信使”信使);     intent.setData(Uri.parse(“http://www.vogella.com/index.html));     intent.putExtra(“urlpath”,“http://www.vogella.com/index.html”);    的StartService(意向);   } } 

如果你运行你的榜样,并按下按钮,下载应执行的Service ,一旦做活动应该表现出吐司的文件名 ​​。

7。 教程:定义和使用本地服务

下面的章节演示了如何创建和使用服务活动 。 服务在启动时发端定期获取数据。 activity本身绑定服务和使用连接到沟通与服务。

创建一个新的项目与活动名为MainActivity名为de.vogella.android.ownservice.local的 。

创建LocalWordService类。

   de.vogella.android.ownservice.local; 进口的java.util.ArrayList; 进口的java.util.List; 导入了java.util.Random; 导入 android.app.Service; 导入 android.content.Intent; 进口 android.os.Binder; 进口 android.os.IBinder; 公共类 LocalWordService的延伸服务{   私人最终的IBinder mBinder =  MyBinder();   私人的 ArrayList <STRING>列表=  ArrayList <STRING>的();   @覆盖   公众诠释的 onStartCommand(意向意图,int标志的, 诠释 startId的){    随机随机= 新的随机();     ,如果 (random.nextBoolean()){      将对List.Add(“Linux”的 );     }     ,如果 (random.nextBoolean()){      将对List.Add(“机器人”);     }     ,如果 (random.nextBoolean()){      将对List.Add(“iPhone”);     }     ,如果 (random.nextBoolean()){      将对List.Add(“Windows7的”);     }     (则为list.size()> = 20){       list.remove(0);     }     返回 Service.START_NOT_STICKY;   }   @覆盖   公众的IBinder onBind(arg0的意向){     返回 mBinder;   }   公共类 MyBinder 延伸粘结剂{     LocalWordService GetService的(){       返回 LocalWordService;     }   }   公共的名单<String> getWordList(){     返回列表;   } } 

创建以下两类,将被登记为BroadcastReceivers 。

   de.vogella.android.ownservice.local; 导入的java.util.Calendar; 进口 android.app.AlarmManager; 导入 android.app.PendingIntent; 导入 android.content.BroadcastReceiver; 导入 android.content.Context; 导入 android.content.Intent; 公共类 MyScheduleReceiver 延伸 BroadcastReceiver的{   / /重新启动服务,每30秒   私有静态最终长 REPEAT_TIME = 1000 * 30;   @覆盖   公共无效 onReceive(上下文的背景下,意图意图){     AlarmManager的服务=(AlarmManager的)上下文         getSystemService(Context.ALARM_SERVICE);    意向书I = 新的意向书(上下文,MyStartServiceReceiver  );     PendingIntent = PendingIntent.getBroadcast(上下文,0,我待,         PendingIntent.FLAG_CANCEL_CURRENT);    日历CAL = Calendar.getInstance();     / /开始30秒完成开机后     cal.add(Calendar.SECOND,30);     / /     / /取每30秒     / / InexactRepeating的允许安卓优化能源消费     service.setInexactRepeating(AlarmManager.RTC_WAKEUP,         cal.getTimeInMillis(),REPEAT_TIME,待定);     / / service.setRepeating的(AlarmManager.RTC_WAKEUP,cal.getTimeInMillis()     / / REPEAT_TIME的,待定);   } } 

   de.vogella.android.ownservice.local; 导入 android.content.BroadcastReceiver; 导入 android.content.Context; 导入 android.content.Intent; 公共类 MyStartServiceReceiver 延伸 BroadcastReceiver的{   @覆盖   公共无效 onReceive(上下文的背景下,意图意图){    意向书服务= 新的意图(上下文,LocalWordService。  );     context.startService(服务);   } } 

  <?XML版本=“1.0”编码=“UTF-8”? <舱单的xmlns:机器人=“http://schemas.android.com/apk/res/android”      =“de.vogella.android.ownservice.local”     Android版 ​​本:VERSIONCODE =“1”     Android版 ​​本:VERSIONNAME =“1.0”>     <uses-sdk android:minSdkVersion= "10" />     <uses-permission android:name= "android.permission.RECEIVE_BOOT_COMPLETED" />     <应用程序        安卓图标=“@绘制/图标”        机器人:标签=“@字符串/ APP_NAME”>         <活动            机器人:名称=“MainActivity”            机器人:标签=“@字符串/ APP_NAME”>             <intent-filter>                 <action android:name= "android.intent.action.MAIN" />                 <category android:name= "android.intent.category.LAUNCHER" />             </意图过滤器>         </活动>         <服务            机器人:名称=“LocalWordService”            安卓图标=“@绘制/图标”            机器人:标签=“@串/ SERVICE_NAME”>         </服务>         <receiver android:name= "MyScheduleReceiver">             <intent-filter>                 <action android:name= "android.intent.action.BOOT_COMPLETED" />             </意图过滤器>         </接收器>         <receiver android:name= "MyStartServiceReceiver">         </接收器>     </> </清单> 

更改布局文件,下面的例子类似的活动 。

  <?XML版本=“1.0”编码=“UTF-8”? <的LinearLayout XMLNS:机器人=“http://schemas.android.com/apk/res/android”    机器人:layout_width =“match_parent”    机器人:layout_height =“match_parent”    机器人:方向=“垂直”>     <TextView的        机器人:layout_width =“match_parent”        机器人:layout_height =“wrap_content”        机器人:文本=“@字符串/你好”/>     <按钮         Android版 ​​本:ID =“@ + id/button1”        机器人:layout_width =“wrap_content”        机器人:layout_height =“wrap_content”        的android:的onClick = showServiceData“:         Android版 ​​本:文本=“按钮”>     </按钮>     <的ListView         android的:ID =“@ ID / Android版 ​​本:名单”        机器人:layout_width =“match_parent”        机器人:layout_height =“wrap_content”>     </ ListView中> </ LinearLayout中> 

改变活动类下面的代码。

   de.vogella.android.ownservice.local; 进口的java.util.ArrayList; 进口的java.util.List; 导入 android.app.ListActivity; 导入 android.content.ComponentName; 导入 android.content.Context; 导入 android.content.Intent; 导入 android.content.ServiceConnection; 进口 android.os.Bundle; 进口 android.os.IBinder; 导入 android.view.View; 进口 android.widget.ArrayAdapter; 导入 android.widget.Toast; 公共类 MainActivity 扩展 ListActivity的{   私人 LocalWordService秒;  
/ **活动是第一次创建时调用。 * /
@覆盖 公共无效的onCreate(捆绑savedInstanceState){ 超级倚仗(savedInstanceState),; 的setContentView(R.layout.main); WORDLIST = ArrayList <STRING>的(); 适配器= ArrayAdapter <STRING>( android.R.layout.simple_list_item_ 1,android.R.id.text1 WORDLIST); setListAdapter(适配器); doBindService(); } 私人 ServiceConnection mConnection的 ServiceConnection(){ 公共无效 onServiceConnected(className的单元名的IBinder粘结剂){ Ş=((LocalWordService.MyBinder)粘合剂)GetService的(); Toast.makeText( MainActivity.,“关”, Toast.LENGTH_SHORT)显示(); } 公共无效 onServiceDisconnected的(单元名类名){ = NULL; } }; 私人 ArrayAdapter的的<STRING>适配器; 私人名单 <String> WORDLIST; 的无效 doBindService(){ bindService( 意图( ,LocalWordService。 ),mConnection Context.BIND_AUTO_CREATE); } 公共的无效 showServiceData(查看视图){ (!= NULL){ Toast.makeText(“元素的数量”+ s.getWordList()的大小(), Toast.LENGTH_SHORT)显示(); wordList.clear(); wordList.addAll(s.getWordList()); adapter.notifyDataSetChanged(); } } }

8。 谢谢

请帮我支持这篇文章:

Flattr this

9。 问题与讨论

提问之前,请见vogella常见问题 。 如果您有疑问或发现错误在这篇文章中,请使用谷歌www.vogella.com集团 。 我已经创建了一个简短的清单, 如何创造良好的问题,这也可能有助于你。

10。 链接和文学

10.1。 源代码

例子的源代码

10.2。 Android的资源

Android开发教程

Android的ListView和ListActivity的

Android的位置API和谷歌地图

Android的意图

Android和网络

Android的后台处理线程和异步任务

从谷歌的远程信使服务

10.3。 vogella资源

vogella训练 Android和Eclipse的培训从vogella团队

Android的教程介绍android编程

GWT教程程序在Java编译成JavaScript和HTML

Eclipse RCP的教程创建Java的本机应用程序

JUnit的教程测试您的应用程序

Git的教程将你拥有的一切在分布式版本控制系统