Android基础学习之Service
2015-10-11 17:15
477 查看
Android四大应用组件:
Activity 可见可交互 前台 界面处理
Service 不可见不可交互 后台管理(耗时任务)
BroadcastRceiver 通信机制(活动和服务,应用和应用,应用和系统)
ContentProvider 数据共享机制
它们之间的共同之处:
用法相似
跨进程交互
使用intent来交互
Service类
java.lang.Object
android.content.Context
android.content.ContextWrapper
android.app.Service
ServiceConnection 接口
Service的特点:
1)与Activity是同级
2)不是一个单独的进程(默认没有特别指定,就在自己应用的进程空间中)
3)不是一个单独的线程(默认没有特别指定,就在主线程中运行,service中代码不能阻塞)
4)后台工作,不可见
服务的分类:
本地服务:同一个进程访问,当进程结束一起结束
远程服务:在不同进程访问,通过AIDL(接口)实现 当访问进程结束还可以在后台继续运行。
跨进程的进行服务访问图示:
service用两种用法 :
1.非绑定
2.绑定
service使用:
用法1:非绑定方式
1.启动
一般从活动中调用 startService() ==> 服务调用 onCreate()(创建时只调用一次)
onStartCommand() (可调用多次)
2.停止
一般从活动中调用 stopService() ==> 服务调用 onDestroy() (只调用一次) 或 服务直接调用stopSelf()
如果有绑定服务,不能停止服务
用法2:绑定方式
启动
绑定
一般从活动中调用 bindService() ==>服务调用 onBind() (只调用一次) 如果服务没有创建一般自动创建
松绑
一般从活动中调用 unbindService() ==>服务调用 onUnBind() 如果所有客户端都松绑服务还会调用
onDestroy()
停止
非绑定方式:
绑定方式:
注:图中ICount接口为自定义接口
基于本地服务示例
示例1:
使用非绑定的方式实现使用服务端运行两个子线程,分别做播放音乐和打印信息。
服务端:
活动端:
清单文件进行服务的注册和定义动作字符串:(组件的注册在< application>< /application>标签中)
示例2:
使用绑定的方式实现使用服务执行任务,并返回反馈信息。服务做打印任务,活动可以获取服务任务进度。
首先定义一个接口(因为Binder子类MyBinder已经继承),两个方法分别是取值和设置值:
服务端:
活动端:
清单文件服务的注册和动作设置见示例1。
示例3:
使用广播进行活动和服务进行通信,需要创建广播的子类和在服务端注册广播接收器。
本例原理图示
java代码:
服务端
活动端
效果:
基于远程服务
基于远程,就是服务和使用服务的活动不是一个进程(一个app)内。在android中每个应用都运行自己进程中,一个应用不能直接访问其他应用内存空间。为了在应用之间进行通信,android提供一种IPC的实现:AIDL (android interface definition language),是IPC轻量级实现。采用java开发语法规则来定义AIDL文件,并提供一个工具(aidl.exe)生成stub存根(java代码文件)。
AIDL 用来让应用(client端)能够被其他应用service(server端)的方法。
AIDL是一种代理模式,应用在远程代理的实现。
代理模式示意图:
应用使用原理图:
.aidl文件过程:
AIDL支持有限的数据类型:
1.java 简单类型 int
2.java 引用类型 String CharSquence
3.List和Map
如果自定义类型在AIDL中使用,必须定义自定义类型的aidl文件。
AIDL文件语法:
类似java 接口定义
支持java 常见类型
自定义类型必须Pacelable序列化(Parcelable接口是在android中实现序列化的接口)
创建AIDL步骤:
1.工程中创建.aidl文件 类似java语法
不能加public
客户端设置 in
服务端设置 out
客户/服务端 inout
支持基本数据类型,不支持 流类 InputStream类.
2.如果.aidl文件编写正确ADT生成java接口文件
不用关心具体内容自动维护
远程调用步骤
客户端:
1.定义aidl文件(代理对象) 定义需要服务端提供功能方法
2.通过ServiceConnection接口的onServiceConnected() 获得代理对象,用aidl生成java代码中方法来获得
3.使用代理对象访问服务端的方法
服务端:
1.定义aidl文件(代理对象) 定义需要服务端提供功能方法
2.在onBind() 定义重写stub中的方法来构造stub子类对象
return new YourService.Stub(){
void foo1(){}
void foo2(){}
void foo3(){}
}
示例1:
使用代理对象来远程连接服务,示例实现服务的加法任务。
注:.aidl文件包名,cilent端必须要和service端一致,否则报错
如:
本例原理图和示意图:
代码:
服务端:
(别忘了注册服务和设置服务动作字符串)
1.编写.aidl文件,文件名IAddService.aidl。
2.服务java代码
client端:
1.编写.aidl文件(与服务端的一致)
2.活动java代码
效果:
示例2
本例演示自定义类型在AIDL中的使用,自定义类型中有三个对象。
用法步骤:
1.编写自定义bean类,必须实现Parcelable接口进行序列化
2.编写bean类的.aidl文件
3.加入.aidl代理文件
自定义bean类写法步骤:
1.实现Parcelable接口,重写writeToParcel(Parcel dest, int flags)方法。
2.要有一个带Parcel类型参数的构造方法
public XXX(Parcel in) {
}
3.定义常量CREATOR给aidl生成的代码用到的(这是个写死了的写法,照着写。范型类XXX为你的bean类)
测试demo
1.定义bean类,文件名:Product.java
2.编写bean的.aidl文件,文件名:Product.aidl
3.加入代理.aidl文件,文件名:IAddService.aidl
要导入具体包名和类名,它不会自动寻找类所在位置
说明:
文件中定义了一个Product类型(自定义类型)的getProduct()方法,一个Map类型的getMap()方法。
4.服务端java代码
以下为另一个应用的代码,用于测试连接远程服务
1.自定义bean,自定义bean的.aidl 文件和代理.aidl文件和服务端的一致(包名也要一致)。
2.活动测试代码
效果:
(此处未整理)
当service被意外销毁时如何处理?
1.使用本地绑定service(activity和service绑定) 随activity销毁而销毁.
2.服务被系统意外销毁后,继续服务处理
public int onStartCommand (Intent intent, int flags, int startId)
返回值决定重启服务的方式:
2.1 START_STICKY 默认 销毁服务,重新创建服务会按空的intent对象执行任务
2.2 START_NOT_STICKY 不重启
2.3 START_STICKY_COMPATIBILITY 根据之前intent来启动
service 要指定其他进程运行,可设置:
android:process=”:remote” 可将服务放在单独的进程中,参数:用包名:retmote(如无包名表示本进程)
上文中代理模式示意图demo在这里:
main.java
Printable.java
Printer.java
PrintProxy.java
Activity 可见可交互 前台 界面处理
Service 不可见不可交互 后台管理(耗时任务)
BroadcastRceiver 通信机制(活动和服务,应用和应用,应用和系统)
ContentProvider 数据共享机制
它们之间的共同之处:
用法相似
跨进程交互
使用intent来交互
Service类
java.lang.Object
android.content.Context
android.content.ContextWrapper
android.app.Service
ServiceConnection 接口
private ServiceConnection conn=new ServiceConnection() { @Override //当检测到C/S连接断开调用该方法 public void onServiceDisconnected(ComponentName name) { // TODO Auto-generated method stub } @Override //1.当检测到客户端(activity)和服务端(service)连接成功就会调用该方法 //2.当调用该方法是会传入一个IBinder对象service public void onServiceConnected(ComponentName name, IBinder service) { // TODO Auto-generated method stub } };
Service的特点:
1)与Activity是同级
2)不是一个单独的进程(默认没有特别指定,就在自己应用的进程空间中)
3)不是一个单独的线程(默认没有特别指定,就在主线程中运行,service中代码不能阻塞)
4)后台工作,不可见
服务的分类:
本地服务:同一个进程访问,当进程结束一起结束
远程服务:在不同进程访问,通过AIDL(接口)实现 当访问进程结束还可以在后台继续运行。
跨进程的进行服务访问图示:
service用两种用法 :
1.非绑定
2.绑定
service使用:
用法1:非绑定方式
1.启动
一般从活动中调用 startService() ==> 服务调用 onCreate()(创建时只调用一次)
onStartCommand() (可调用多次)
2.停止
一般从活动中调用 stopService() ==> 服务调用 onDestroy() (只调用一次) 或 服务直接调用stopSelf()
如果有绑定服务,不能停止服务
用法2:绑定方式
启动
绑定
一般从活动中调用 bindService() ==>服务调用 onBind() (只调用一次) 如果服务没有创建一般自动创建
松绑
一般从活动中调用 unbindService() ==>服务调用 onUnBind() 如果所有客户端都松绑服务还会调用
onDestroy()
停止
非绑定方式:
绑定方式:
注:图中ICount接口为自定义接口
基于本地服务示例
示例1:
使用非绑定的方式实现使用服务端运行两个子线程,分别做播放音乐和打印信息。
服务端:
public class MyService extends Service { private static final String TAG = "ql debug"; private MediaPlayer mediaPlayer; private Thread printThread;//打印线程 private int cnt = -1; private boolean active = false;//服务运行标识位 public MyService() { } @Override public IBinder onBind(Intent intent) { // TODO: Return the communication channel to the service. throw new UnsupportedOperationException("Not yet implemented"); } @Override public void onCreate() { super.onCreate(); mediaPlayer = MediaPlayer.create(this, R.raw.hold_my_hand); mediaPlayer.start(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { cnt = intent.getIntExtra("number", -1);//得到活动传过来的数值 active = true; printThread = new Thread() { @Override public void run() { while (active) { cnt--; try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } Log.d(TAG, "progress value--------->" + cnt); } } }; printThread.start(); return super.onStartCommand(intent, flags, startId); } @Override public void onDestroy() { super.onDestroy(); mediaPlayer.stop(); active=false; Log.e(TAG,"service destroy"); } }
活动端:
public class MainActivity extends Activity implements OnClickListener { int number = 100; private Button btn_satrtService; private Button btn_stopService; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); btn_satrtService = (Button) findViewById(R.id.btn_satrtService); btn_stopService = (Button) findViewById(R.id.btn_stopService); btn_satrtService.setOnClickListener(this); btn_stopService.setOnClickListener(this); } @Override public void onClick(View v) { Intent intent = new Intent(); switch (v.getId()) { case R.id.btn_satrtService: intent.setAction("com.ql.servicedemo.action"); intent.putExtra("number", number); startService(intent);// 启动服务 number++; break; case R.id.btn_stopService: intent.setAction("com.ql.servicedemo.action"); stopService(intent);//停止服务 break; default: break; } } }
清单文件进行服务的注册和定义动作字符串:(组件的注册在< application>< /application>标签中)
<service android:name="com.ql.servicedemo.MyService" android:enabled="true" android:exported="true" > <intent-filter > <action android:name="com.ql.servicedemo.action"/> </intent-filter> </service>
示例2:
使用绑定的方式实现使用服务执行任务,并返回反馈信息。服务做打印任务,活动可以获取服务任务进度。
首先定义一个接口(因为Binder子类MyBinder已经继承),两个方法分别是取值和设置值:
public interface ICount { public int getCount(); public void setCount(int cnt); }
服务端:
public class MyService extends Service { private static final String TAG = "ql debug"; private int cnt = 0; private boolean active = false; private class MyBinder extends Binder implements ICount{ @Override public int getCount() { return cnt; } @Override public void setCount(int cnt) { MyService.this.cnt = cnt; } } MyBinder binder = new MyBinder(); public MyService() { } @Override public IBinder onBind(Intent intent) { // TODO: Return the communication channel to the service.返回到服务的通信通道。 return binder; } @Override public void onCreate() { super.onCreate(); new Thread() { @Override public void run() { active = true; while (active) { cnt++; try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } Log.d(TAG, "progress value--------->" + cnt); } } }.start(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { return super.onStartCommand(intent, flags, startId); } @Override public void onDestroy() { super.onDestroy(); active=false; Log.e(TAG,"service destroy"); } }
活动端:
public class MainActivity extends Activity implements OnClickListener { int number = 100; private Button btn_satrtService; private Button btn_stopService; private TextView txt_result; private ICount count; private class MyConn implements ServiceConnection { @Override// 当远程绑定成功传入IBinder对象是一个代理对象service public void onServiceConnected(ComponentName name, IBinder binder) { count = (ICount) binder; } @Override//在service被系统意外回收才会调用 public void onServiceDisconnected(ComponentName name) { count = null; } } MyConn conn = new MyConn(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); Intent service=new Intent("com.ql.servicedemo2.action"); bindService(service, conn, BIND_AUTO_CREATE);//绑定服务 txt_result = (TextView) findViewById(R.id.txt_result); btn_satrtService = (Button) findViewById(R.id.btn_satrtService); btn_stopService = (Button) findViewById(R.id.btn_stopService); btn_satrtService.setOnClickListener(this); btn_stopService.setOnClickListener(this); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.btn_satrtService: txt_result.setText("来自service子线程的计数值:" + count.getCount());//获取服务任务进度 break; case R.id.btn_stopService: count.setCount(500);//改变服务任务的值 break; default: break; } } @Override protected void onDestroy() { super.onDestroy(); unbindService(conn);//松绑服务 } }
清单文件服务的注册和动作设置见示例1。
示例3:
使用广播进行活动和服务进行通信,需要创建广播的子类和在服务端注册广播接收器。
本例原理图示
java代码:
服务端
public class MyService extends Service { //两个常量,读和写 private static final String READREQ = "read service data request"; private static final String WRITEREQ = "write service data request"; private static final String TAG = "ql debug"; private int cnt = 0; private boolean active = false;//服务存活标识位(优化处理) /** * 用于通信的广播类 * * @author qinlang * */ private class MyReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { String command = intent.getStringExtra("command"); Log.v(TAG, "service receive command:" + command); Intent i = new Intent("com.activity.receiver.action"); if (READREQ.equals(command)) { i.putExtra("count", cnt); sendBroadcast(i);//发送广播 } if (WRITEREQ.equals(command)) { cnt = 0; } } } MyReceiver receiver = new MyReceiver(); IntentFilter filter = new IntentFilter(); public MyService() { } @Override public IBinder onBind(Intent intent) { // TODO: Return the communication channel to the service.返回到服务的通信通道。 // throw new UnsupportedOperationException("Not yet implemented"); return null; } @Override public void onCreate() { super.onCreate(); //动态注册广播 filter.addAction("com.service.receiver.action"); registerReceiver(receiver, filter);//注册activity用的广播接收器 new Thread() { @Override public void run() { active = true; while (active) { cnt++; try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } Log.d(TAG, "progress value--------->" + cnt); } } }.start(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { return super.onStartCommand(intent, flags, startId); } @Override public void onDestroy() { super.onDestroy(); active = false; unregisterReceiver(receiver);//移除广播注册 Log.e(TAG, "service destroy"); } }
活动端
public class MainActivity extends Activity implements OnClickListener { private static final String READREQ = "read service data request"; private static final String WRITEREQ = "write service data request"; int number = 100; private Button btn_satrtService; private Button btn_stopService; private TextView txt_result; /** * 用于通信的广播类 * @author qinlang * */ private class MyReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { // 这里可以操作UI线程的视图显示 txt_result.setText("service端子线程当前计数值为:" + intent.getIntExtra("count", -1)); } } MyReceiver receiver = new MyReceiver(); IntentFilter filter = new IntentFilter(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); //动态注册广播 filter.addAction("com.activity.receiver.action"); registerReceiver(receiver, filter);//注册service用的广播接收器 Intent service = new Intent("com.ql.servicedemo3.action"); startService(service);//启动服务 txt_result = (TextView) findViewById(R.id.txt_result); btn_satrtService = (Button) findViewById(R.id.btn_satrtService); btn_stopService = (Button) findViewById(R.id.btn_stopService); btn_satrtService.setOnClickListener(this); btn_stopService.setOnClickListener(this); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.btn_satrtService: sendBroadcastToService(READREQ);//读取服务端任务进度 break; case R.id.btn_stopService: sendBroadcastToService(WRITEREQ);//设置服务端任务值 break; default: break; } } private void sendBroadcastToService(String command) { Intent intent=new Intent("com.service.receiver.action"); intent.putExtra("command", command); sendBroadcast(intent);//发送广播 } @Override protected void onDestroy() { super.onDestroy(); } }
效果:
基于远程服务
基于远程,就是服务和使用服务的活动不是一个进程(一个app)内。在android中每个应用都运行自己进程中,一个应用不能直接访问其他应用内存空间。为了在应用之间进行通信,android提供一种IPC的实现:AIDL (android interface definition language),是IPC轻量级实现。采用java开发语法规则来定义AIDL文件,并提供一个工具(aidl.exe)生成stub存根(java代码文件)。
AIDL 用来让应用(client端)能够被其他应用service(server端)的方法。
AIDL是一种代理模式,应用在远程代理的实现。
代理模式示意图:
应用使用原理图:
.aidl文件过程:
AIDL支持有限的数据类型:
1.java 简单类型 int
2.java 引用类型 String CharSquence
3.List和Map
如果自定义类型在AIDL中使用,必须定义自定义类型的aidl文件。
AIDL文件语法:
类似java 接口定义
支持java 常见类型
自定义类型必须Pacelable序列化(Parcelable接口是在android中实现序列化的接口)
创建AIDL步骤:
1.工程中创建.aidl文件 类似java语法
不能加public
客户端设置 in
服务端设置 out
客户/服务端 inout
支持基本数据类型,不支持 流类 InputStream类.
2.如果.aidl文件编写正确ADT生成java接口文件
不用关心具体内容自动维护
远程调用步骤
客户端:
1.定义aidl文件(代理对象) 定义需要服务端提供功能方法
2.通过ServiceConnection接口的onServiceConnected() 获得代理对象,用aidl生成java代码中方法来获得
private class AddServiceConn implements ServiceConnection{ @Override public void onServiceConnected(ComponentName name, IBinder service) { // 当远程绑定成功传人IBinder对象是一个代理对象service proxy=IAddService.Stub.asInterface(service); proxy.foo1();//方法一 proxy.foo2();//方法二 proxy.foo3();//方法三 //... } @Override public void onServiceDisconnected(ComponentName name) { // TODO Auto-generated method stub proxy=null; } }
3.使用代理对象访问服务端的方法
服务端:
1.定义aidl文件(代理对象) 定义需要服务端提供功能方法
2.在onBind() 定义重写stub中的方法来构造stub子类对象
return new YourService.Stub(){
void foo1(){}
void foo2(){}
void foo3(){}
}
示例1:
使用代理对象来远程连接服务,示例实现服务的加法任务。
注:.aidl文件包名,cilent端必须要和service端一致,否则报错
如:
本例原理图和示意图:
代码:
服务端:
(别忘了注册服务和设置服务动作字符串)
1.编写.aidl文件,文件名IAddService.aidl。
package com.ql.testservice1; interface IAddService{ int add(in int value1,in int value2); }
2.服务java代码
public class MyService extends Service { public MyService() { } @Override public IBinder onBind(Intent intent) { // TODO: Return the communication channel to the service. return new IAddService.Stub() { @Override public int add(int value1, int value2) throws RemoteException { return value1 + value2; } }; } }
client端:
1.编写.aidl文件(与服务端的一致)
2.活动java代码
public class MainActivity extends Activity { private IAddService proxy;// 代理对象 private class ServiceConn implements ServiceConnection { @Override public void onServiceConnected(ComponentName name, IBinder service) { // 当远程绑定成功传入IBinder对象是一个代理对象service proxy = IAddService.Stub.asInterface(service); } @Override public void onServiceDisconnected(ComponentName name) { proxy = null; } } ServiceConn conn = new ServiceConn(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // 绑定服务 Intent intent = new Intent("com.ql.testservice.action"); bindService(intent, conn, BIND_AUTO_CREATE); final EditText editText1 = (EditText) findViewById(R.id.editText1); final EditText editText2 = (EditText) findViewById(R.id.editText2); final TextView textView = (TextView) findViewById(R.id.textView3); Button button = (Button) findViewById(R.id.button1); button.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { int v1, v2, res = -1; v1 = Integer.parseInt(editText1.getText().toString().trim()); v2 = Integer.parseInt(editText2.getText().toString().trim()); try { res = proxy.add(v1, v2);//步骤3的“使用代理对象访问服务端的方法” } catch (RemoteException e) { e.printStackTrace(); } textView.setText("计算结果:" + res); } }); } }
效果:
示例2
本例演示自定义类型在AIDL中的使用,自定义类型中有三个对象。
用法步骤:
1.编写自定义bean类,必须实现Parcelable接口进行序列化
2.编写bean类的.aidl文件
3.加入.aidl代理文件
自定义bean类写法步骤:
1.实现Parcelable接口,重写writeToParcel(Parcel dest, int flags)方法。
2.要有一个带Parcel类型参数的构造方法
public XXX(Parcel in) {
}
3.定义常量CREATOR给aidl生成的代码用到的(这是个写死了的写法,照着写。范型类XXX为你的bean类)
public static final Parcelable.Creator<XXX> CREATOR = new Parcelable.Creator<XXX>() { @Override public XXX createFromParcel(Parcel in) { return new XXX(in); } @Override public XXX[] newArray(int size) { return new XXX[size]; } };
测试demo
1.定义bean类,文件名:Product.java
//必须实现Parcelable接口否则AIDL编译出错 public class Product implements Parcelable { private int id; private String name; private float price; public Product() { } //2.将Parcel对象中数据取出来. public Product(Parcel in) { id = in.readInt(); name = in.readString(); price = in.readFloat(); } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public float getPrice() { return price; } public void setPrice(float price) { this.price = price; } @Override public int describeContents() { return 0; } @Override//1.将序列化用的数据写Parcel对象,dest是输出参数 public void writeToParcel(Parcel dest, int flags) { dest.writeInt(id); dest.writeString(name); dest.writeFloat(price); } // 3.定义常量 给aidl生成代码用到的. public static final Parcelable.Creator<Product> CREATOR = new Parcelable.Creator<Product>() { @Override public Product createFromParcel(Parcel in) { return new Product(in); } @Override public Product[] newArray(int size) { return new Product[size]; } }; }
2.编写bean的.aidl文件,文件名:Product.aidl
package com.ql.testservice2; parcelable Product;
3.加入代理.aidl文件,文件名:IAddService.aidl
要导入具体包名和类名,它不会自动寻找类所在位置
说明:
文件中定义了一个Product类型(自定义类型)的getProduct()方法,一个Map类型的getMap()方法。
package com.ql.testservice2; import com.ql.testservice2.Product; interface IAddService{ int add(in int value1,in int value2); Product getProduct(); Map getMap(in String country,in Product product); }
4.服务端java代码
public class MyService extends Service { public MyService() { } @Override public IBinder onBind(Intent intent) { //返回IBinder对象 对应客户端用来生成代理对象用的. return new IAddService.Stub() { @Override public Product getProduct() throws RemoteException { Product product=new Product(); product.setId(1000); product.setName("宝马"); product.setPrice(1000000); return product; } @Override public Map getMap(String country, Product product) throws RemoteException { Map map=new HashMap(); map.put("country", country); map.put("id",product.getId()); map.put("name", product.getName()); map.put("price", product.getPrice()); return map; } @Override public int add(int value1, int value2) throws RemoteException { return value1 + value2; } }; } }
以下为另一个应用的代码,用于测试连接远程服务
1.自定义bean,自定义bean的.aidl 文件和代理.aidl文件和服务端的一致(包名也要一致)。
2.活动测试代码
public class MainActivity extends Activity { private IAddService proxy;// 代理对象 private class ServiceConn implements ServiceConnection { @Override public void onServiceConnected(ComponentName name, IBinder service) { // 当远程绑定成功传入IBinder对象是一个代理对象service proxy = IAddService.Stub.asInterface(service); } @Override//在service被系统意外回收才会调用 public void onServiceDisconnected(ComponentName name) { proxy = null; } } ServiceConn conn = new ServiceConn(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // 绑定服务 Intent intent = new Intent("com.ql.testservice2.action"); bindService(intent, conn, BIND_AUTO_CREATE); final EditText editText1 = (EditText) findViewById(R.id.editText1); final EditText editText2 = (EditText) findViewById(R.id.editText2); final TextView textView = (TextView) findViewById(R.id.textView3); final TextView textView2 = (TextView) findViewById(R.id.result2); Button button = (Button) findViewById(R.id.button1); Button button2 = (Button) findViewById(R.id.button2); button.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { int v1, v2, res = -1; v1 = Integer.parseInt(editText1.getText().toString().trim()); v2 = Integer.parseInt(editText2.getText().toString().trim()); try { res = proxy.add(v1, v2); } catch (RemoteException e) { e.printStackTrace(); } textView.setText("计算结果:" + res); } }); button2.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { try { Product product = proxy.getProduct(); StringBuilder builder = new StringBuilder(); builder.append("product:" + product + "\n"); builder.append("id:" + product.getId() + "\n"); builder.append("name:" + product.getName() + "\n"); builder.append("price:" + product.getPrice() + "\n"); Map map = proxy.getMap("china", product); builder.append("map object:" + map); textView2.setText(builder.toString()); } catch (RemoteException e) { e.printStackTrace(); } } }); } }
效果:
(此处未整理)
当service被意外销毁时如何处理?
1.使用本地绑定service(activity和service绑定) 随activity销毁而销毁.
2.服务被系统意外销毁后,继续服务处理
public int onStartCommand (Intent intent, int flags, int startId)
返回值决定重启服务的方式:
2.1 START_STICKY 默认 销毁服务,重新创建服务会按空的intent对象执行任务
2.2 START_NOT_STICKY 不重启
2.3 START_STICKY_COMPATIBILITY 根据之前intent来启动
service 要指定其他进程运行,可设置:
android:process=”:remote” 可将服务放在单独的进程中,参数:用包名:retmote(如无包名表示本进程)
上文中代理模式示意图demo在这里:
main.java
public class Main { public static void main(String[] args) { Printable p=new PrintProxy("rose"); System.out.println("现在是:"+p.getPrinterName()); p.setPrinterName("alice"); System.out.println("现在是"+p.getPrinterName()); p.print("hello proxy world"); } }
Printable.java
public interface Printable { public abstract void setPrinterName(String name); public abstract String getPrinterName(); public abstract void print(String string); }
Printer.java
public class Printer implements Printable{ private String name; public Printer() { // TODO Auto-generated constructor stub heavyJob("正在产生Printer对象实例"); } public Printer(String name) { // TODO Auto-generated constructor stub this.name=name; heavyJob("正在产生Printer对象实例"); } private void heavyJob(String string) { // TODO Auto-generated method stub System.out.println(string); for(int i=0;i<5;i++){ try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.print("."); } System.out.println("完成"); } @Override public void setPrinterName(String name) { // TODO Auto-generated method stub this.name=name; } @Override public String getPrinterName() { // TODO Auto-generated method stub return this.name; } @Override public void print(String string) { // TODO Auto-generated method stub System.out.println("<<<"+this.name+">>>"); System.out.println(string); } }
PrintProxy.java
//代理:要用再建立 //不需要本人处理的工作交出去,需要建立一个代理 //代理能力有限的,遇到超出能力范围还是找本人来处理 public class PrintProxy implements Printable{ private String name; private Printer real;//委托对象 public PrintProxy() { // TODO Auto-generated constructor stub } public PrintProxy(String name) { // TODO Auto-generated constructor stub this.name=name; } @Override public void setPrinterName(String name) { // TODO Auto-generated method stub if(real!=null){ real.setPrinterName(name); } this.name=name; } @Override public String getPrinterName() { // TODO Auto-generated method stub return this.name; } @Override public void print(String string) { // TODO Auto-generated method stub realize(); real.print(string); } private void realize(){ //产生本人对象 if(real==null){ real=new Printer(name); } } }
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析