service有两种类型:
本地服务(Local Service):用于应用程序内部
远程服务(Remote Sercie):用于android系统内部的应用程序之间
前者用于实现应用程序自己的一些耗时任务,比如查询升级信息,并不占用应用程序比如Activity所属线程,而是单开线程后台执行,这样用户体验比较好。
后者可被其他应用程序复用,比如天气预报服务,其他应用程序不需要再写这样的服务,调用已有的即可。
编写不需和Activity交互的本地服务示例
本地服务编写比较简单。首先,要创建一个Service类,该类继承android的Service类。这里写了一个计数服务的类,每秒钟为计数器加一。在服务类的内部,还创建了一个线程,用于实现后台执行上述业务逻辑。
Service代码:
import android.app.Service; import android.content.Intent; import android.os.IBinder; import android.util.Log; public class CountService extends Service { private boolean threadDisable; private int count; @Override public IBinder onBind(Intent intent) { return null; } @Override public void onCreate() { super.onCreate(); new Thread(new Runnable() { public void run() { while (!threadDisable) { try { Thread.sleep(1000); } catch (InterruptedException e) { } count++; System.out.println(" CountService Count is " + count); } } }).start(); } @Override public void onDestroy() { super.onDestroy(); this.threadDisable = true; Log.v(" CountService ", " on destroy "); } } 将该服务注册到配置文件AndroidManifest.xml中 <service android:name="CountService" /> 在Activity中启动和关闭本地服务 import android.app.Activity; import android.content.Intent; import android.os.Bundle; public class LocalServiceDemoActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); this.startService(new Intent(this, CountService.class)); } @Override protected void onDestroy() { super.onDestroy(); this.stopService(new Intent(this, CountService.class)); } }
编写本地服务和Activity交互的示例
上面的示例是通过startService和stopService启动关闭服务的。适用于服务和activity之间没有调用交互的情况。如果之间需要传递参数或者方法调用。需要使用bind和unbind方法。
具体做法是,服务类需要增加接口,比如ICountService,另外,服务类需要有一个内部类,这样可以方便访问外部类的封装数据,这个内部类需要继承Binder类并实现ICountService接口。还有,就是要实现Service的
onBind方法,不能只传回一个null了。
新建立的接口代码:
public interface ICountService { public abstract int getCount(); } CountService代码: import android.app.Service; import android.content.Intent; import android.os.Binder; import android.os.IBinder; import android.util.Log; public class CountService extends Service implements ICountService { private boolean threadDisable; private int count; private ServiceBinder serviceBinder = new ServiceBinder(); public class ServiceBinder extends Binder implements ICountService { // @Override public int getCount() { return count; } } @Override public IBinder onBind(Intent intent) { return serviceBinder; } @Override public void onCreate() { super.onCreate(); new Thread(new Runnable() { // @Override public void run() { while (!threadDisable) { try { Thread.sleep(1000); } catch (InterruptedException e) { } count++; System.out.println("CountService Count is " + count); } } }).start(); } @Override public void onDestroy() { super.onDestroy(); this.threadDisable = true; Log.v(" CountService ", " on destroy "); } // @Override public int getCount() { return count; } }
服务的注册也要做改动,AndroidManifest.xml文件:
<service android:name="CountService" > <intent-filter> <action android:name="com.phone.jiaohuservice.CountService" /> </intent-filter> </service> Acitity代码不再通过startSerivce和stopService启动关闭服务,另外,需要通过ServiceConnection的内部类实现来连接Service和Activity。 import android.app.Activity; import android.content.ComponentName; import android.content.Intent; import android.content.ServiceConnection; import android.os.Bundle; import android.os.IBinder; public class LocalServiceDemoActivity extends Activity { private ServiceConnection serviceConnection = new ServiceConnection() { // @Override public void onServiceConnected(ComponentName name, IBinder service) { countService = (ICountService) service; System.out.println(" CountService on serivce connected, count is " + countService.getCount()); } // @Override public void onServiceDisconnected(ComponentName name) { countService = null; } }; private ICountService countService; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); this.bindService(new Intent("com.phone.jiaohuservice.CountService"), this.serviceConnection, BIND_AUTO_CREATE); } @Override protected void onDestroy() { this.unbindService(serviceConnection); super.onDestroy(); // 注意先后 } }
编写传递基本型数据的远程服务
上面的示例,可以扩展为,让其他应用程序复用该服务。这样的服务叫远程(remote)服务,实际上是进程间通信(RPC)。
这时需要使用android接口描述语言(AIDL)来定义远程服务的接口,而不是上述那样简单的java接口。扩展名为aidl而不是java。可用上面的ICountService改动而成ICountSerivde.aidl,eclipse会自动生成相关的java文件。
远端代码:
ICountService.aidl
package com.phone.remoteservice.aidl; interface ICountService { int getCount(); }
CountService.java
import com.phone.remoteservice.aidl.ICountService; import android.app.Service; import android.content.Intent; import android.os.IBinder; import android.os.RemoteException; import android.util.Log; public class CountService extends Service { private boolean threadDisable; private int count; private ICountService.Stub serviceBinder = new ICountService.Stub() { // @Override public int getCount() throws RemoteException { return count; } }; // @Override public IBinder onBind(Intent intent) { return serviceBinder; } @Override public void onCreate() { super.onCreate(); new Thread(new Runnable() { // @Override public void run() { while (!threadDisable) { try { Thread.sleep(1000); } catch (InterruptedException e) { } count++; Log.i("aa", "---" + count + "---"); } } }).start(); } // @Override public void onDestroy() { super.onDestroy(); this.threadDisable = true; Log.v(" CountService ", " on destroy "); } }
配置文件AndroidManifest.xml
<service android:name=".CountService" > <intent-filter> <action android:name="com.phone.remoteservice.CountService" /> </intent-filter> </service>
本地代码:
拷贝远端代码gen:com.phone.remoteservice.aidl包名及内部生成的ICountService.java文件到本地,注意包名不要变,java文件名也不要变。
测试代码
import com.phone.remoteservice.aidl.ICountService; import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; import android.app.Activity; import android.content.ComponentName; import android.content.Intent; import android.content.ServiceConnection; import android.view.Menu; public class RemoteServiceTest extends Activity { private ICountService countService; private boolean SreviceDisable; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); bindService(new Intent("com.phone.remoteservice.CountService"), this.serviceConnection, BIND_AUTO_CREATE); } @Override protected void onDestroy() { this.unbindService(serviceConnection); SreviceDisable = true; super.onDestroy(); // 注意先后 } private ServiceConnection serviceConnection = new ServiceConnection() { public void onServiceConnected(ComponentName name, IBinder service) { countService = ICountService.Stub.asInterface(service); new Thread(new Runnable() { // @Override public void run() { while (!SreviceDisable) { try { System.out .println(" CountService on serivce connected, count is " + countService.getCount()); } catch (RemoteException e) { e.printStackTrace(); } try { Thread.sleep(1000); } catch (InterruptedException e) { } } } }).start(); } public void onServiceDisconnected(ComponentName name) { countService = null; } }; }
在Activity中使用服务的差别不大,只需要对ServiceConnection中的调用远程服务的方法时,要捕获RemoteException 异常。
这样就可以在同一个应用程序中使用远程服务的方式和自己定义的服务交互了。 如果是另外的应用程序使用远程服务,需要做的是复制上面的aidl文件和相应的包构到应用程序中,其他调用等都一样。
编写传递复杂数据类型的远程服务
远程服务往往不只是传递java基本数据类型。这时需要注意android的一些限制和规定:
1. android支持String和CharSequence
2. 如果需要在aidl中使用其他aidl接口类型,需要import,即使是在相同包结构下;
3. android允许传递实现Parcelable接口的类,需要import;
4. android支持集合接口类型List和Map,但是有一些限制,元素必须是基本型或者上述三种情况,不需要import集合html" target="_blank">接口类,但是需要对元素涉及到的类型import;
5. 非基本数据类型,也不是String和CharSequence类型的,需要有方向指示,包括in、out和inout,in表示由客户端设置,out表示由服务端设置,inout是两者均可设置。
这里将前面的例子中返回的int数据改为复杂数据类型:
import android.os.Parcel; import android.os.Parcelable; public class CountBean implements Parcelable { public static final Parcelable.Creator < CountBean > CREATOR = new Creator < CountBean > () { @Override public CountBean createFromParcel(Parcel source) { CountBean bean = new CountBean(); bean.count = source.readInt(); return bean; } @Override public CountBean[] newArray( int size) { return new CountBean[size]; } }; public int count; @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt( this .count); } @Override public int describeContents() { return 0 ; } }
以上就是小编为大家带来的Service Activity的三种交互方式(详解)的全部内容了,希望对大家有所帮助,多多支持小牛知识库~
本文向大家介绍详解android与服务端交互的两种方式,包括了详解android与服务端交互的两种方式的使用技巧和注意事项,需要的朋友参考一下 做Android开发的程序员必须知道android客户端应该如何与服务端进行交互,这里主要介绍的是使用json数据进行交互。服务端从数据库查出数据并以json字符串的格式或者map集合的格式返回到客户端,客户端进行解析并输出到手机屏幕上。 此处介绍两种方式
本文向大家介绍iconfont的三种使用方式详解,包括了iconfont的三种使用方式详解的使用技巧和注意事项,需要的朋友参考一下 在我们项目中经常要使用到iconfont,在此我们使用阿里巴巴矢量库提供的icon图标,此图标库足够为我们提供大量的图标,我们首先需要的事在阿里巴巴矢量图标库新建一个自己的账号,并且新建一个项目,这个项目包含了你所有要用到的图标。我们需要选中需要的图标放到自己的项目中
本文向大家介绍WKWebView、WebView和JS的交互方式详解,包括了WKWebView、WebView和JS的交互方式详解的使用技巧和注意事项,需要的朋友参考一下 由于Xcode8发布之后,编译器开始不支持iOS 7了,这样我们的app也改为最低支持iOS 8.0,既然需要与web交互,那自然也就选择使用了 iOS 8.0之后 才推出的新控件 WKWebView. 相比与 UIWebVie
本文向大家介绍Spring Bean三种注入方式详解,包括了Spring Bean三种注入方式详解的使用技巧和注意事项,需要的朋友参考一下 在Spring容器中为一个bean配置依赖注入有三种方式: 使用属性的setter方法注入 这是最常用的方式; 使用构造器注入; 使用Filed注入(用于注解方式). Field注入是最常见的一种方式,可以采用 @Autowired 对Bean类的接口
本文向大家介绍详解flask表单提交的两种方式,包括了详解flask表单提交的两种方式的使用技巧和注意事项,需要的朋友参考一下 一.通用方式 通用方式就是使用ajax或者$.post来提交。 前端html 将操作绑定 这样通过js来实现提交表单的功能,然后flask后端 通用方式的好处就是在其他框架中也适用。而且也并不复杂。 二.比较正宗的flask方式 前端html: 前端这时候可以不用绑定操作
本文向大家介绍详解SpringBoot工程的三种搭建方式,包括了详解SpringBoot工程的三种搭建方式的使用技巧和注意事项,需要的朋友参考一下 SpringBoot的主要目的是简化配置文件,通过少量配置即可运行Java程序,其强大的自动配置功能帮助开发者轻松实现配置装配,通过引入SpringBoot的 starter 就能实现想要的功能,不需要额外的配置。 目前SpringBoot工程有三种搭