android中Service使用详解
2016-06-29 01:51
531 查看
service用于长期在后台处理任务,而不需要对用户可见。
service有2种基本的启动方式:
startService():使用这种方式,来进行单一的任务,不需要返回结果给调用者
bindService():与上面的相反。
一个简单的单一模式启动的服务图示:
当然除了上面的,也可以混合着使用,图示:
下面是一些关于服务的重要说明,非常值得详细了解的:
继承service,实现自己的service;
在manifest中声明service,服务位于主线程,并不会创建自己的子线程。
下面是一些重写的方法:
onCreate();当服务被创建时调用,只调用一次。
onStartCommand();它与startService()对应,当服务启动后调用。如果你重写了该方法,你就有责任自己去
当任务结束以后,调用stopSelf()或者stopService()来停止服务。如果你是绑定的服务,就不需重新该方法了。
onBind();它与bindService()对应,通过返回IBinder,来与service交流。如果你并不像绑定它,就直接返回null
onDestroy();当服务不再被使用时需要销毁时调用,你应该在这里用来停止线程,注销监听器,广播。
如果一个组件如activity使用的是 startService()来启动服务的话,就会触发 onStartCommand(),然后服务就会一直运行,直到任务结束;服务的停止需要
手动控制:在启动服务的组件中调用 stopService()或者在服务本类中调用stopSelf()
如果一个组件使用的是bindService()来启动服务的话,该服务就会运行,直到组件不约束它。
在系统内存很低的情况下,系统会强制停止服务,来恢复用于运行activity;但是下面这些情况下的服务不易被系统停止:服务与activity绑定或者
服务位于前台。但是如果服务最后还是被停止了,我们要重新启用服务。
使用intentservice,在任务结束后会自动关闭服务。
Intent intent = new Intent(this, HelloService.class);
startService(intent);
如果你的服务没有经过绑定,那么startService(intent)中的intent就是唯一的向service交互的方式;service中通过广播来向外发布回调。如果多次启动服务,会导致onStartCommand()被多次调用。
onStartCommand()必须返回一个整形值,描述这当系统杀掉服务时,系统该如何继续service
START_NOT_STICKY,杀掉后,不再重建
START_STICKY,杀掉后,自动重启,然后接收的intent=null
START_REDELIVER_INTENT,杀掉后,自动重启,然后接收的intent不为空;像文件下载
必须重写 onBind()方法返回IBinder,来与其他组件交流。在其他组件中获取该IBinder对象
有一种client-server的感觉,可以有多个客户端与server交流
客户端组件,必须创建ServiceConnection,用来监听与service的连接;
可以有多个客户端连接service,但是service的onBind只会执行一次,所以分发给其他客户端的都是同一个IBinder对象
只有在多个客户端都解绑了服务之后,服务才会被销毁。
使用这种服务有个最重要的地方就是定义IBinder;
有3种方式:
a.直接继承Binder,这也是一般app常用的一种方式,适用于你的服务与你的app是处于同一个进程中的。你的服务仅仅是为了
处理后台任务。
b.使用Messenger,适用于需要跨进程通讯且线程安全且非并发,同一个时间只能接受到一个请求,你可以使用Messenger和Handler这2个 类来进行service和client的交互。
服务端建立信使对象,通过通过onbind将服务端信使对象放在IBind中回调给客户端,这样子客户端就可以拿到服务端信使对象,使用服务端信使对象给服务端发信息了。
在客户端连接上服务端后,可以建立客户端信使对象,将客户端信使对象以消息的形式,发送给服务端,服务端拿到客户端信使对象后可以给客户端发消息。
这个是线程安全的。因为都是在同一个队列里,在同一个线程里进行的。它本身是基于AIDL构建的。
c.使用AIDL,适用于需要跨进程,且非线程安全,能够同一时间处理多个请求的场合。
它的使用是创建一个.aidl file文件,里面定义接口,然后android sdk tool使用它来生成一个抽象类,抽象类里实现各种接口方法。
注意:对于大多数应用,我们都不应该使用AIDL来bindservice.因为这会使得结果更复杂。
服务端:
客户端:
如果您希望 Activity 在后台停止运行状态下仍可接收响应,则可在 onCreate() 期间绑定,在 onDestroy() 期间取消绑定。请注意,这意味着您的 Activity 在其整个运行过程中(甚至包括后台运行期间)都需要使用服务,因此如果服务位于其他进程内,那么当您提高该进程的权重时,系统终止该进程的可能性会增加
下面是个完整的例子;客户端和服务端使用Messenger来通讯。
服务端:Server_Service
客户端:Client
基本流程:
与上面的使用信使一样,只不过IBinder的获取渠道不一样罢了,这里是使用创建.aidl文件来实现。
最重要的点:创建.aidl文件,里面定义一些接口,这些接口包括由服务端实现的,和客户端实现的。
服务端实现的接口,就是由.aidl文件生成的接口文件,我们在服务端继承该接口文件里定义的一个静态内部抽象类Stub,该类是Binder的子类,正好可以让我们在OnBind方法中返回给客户端。
如果你要服务端回调该客户端信息,你要再定义一个.aidl文件,里面包含回调方法。将该接口作为参数,在上面一个.aidl文件中定义注册和反注册方法;这样,当客户端连接成功服务端后,让客户端实现该接口对象,作为实参传递进来,最后就传给了服务端。服务端拿着对象往客户端发信息。
下面是一个例子:
例子结构图:
Book.java
Book.aidl
ICallBack.aidl
IBookManager.aidl
BookManagerService.java
MainActivity.java
activity_main.xml
AndroidManifest.xml
效果图:
service有2种基本的启动方式:
startService():使用这种方式,来进行单一的任务,不需要返回结果给调用者
bindService():与上面的相反。
一个简单的单一模式启动的服务图示:
当然除了上面的,也可以混合着使用,图示:
下面是一些关于服务的重要说明,非常值得详细了解的:
继承service,实现自己的service;
在manifest中声明service,服务位于主线程,并不会创建自己的子线程。
下面是一些重写的方法:
onCreate();当服务被创建时调用,只调用一次。
onStartCommand();它与startService()对应,当服务启动后调用。如果你重写了该方法,你就有责任自己去
当任务结束以后,调用stopSelf()或者stopService()来停止服务。如果你是绑定的服务,就不需重新该方法了。
onBind();它与bindService()对应,通过返回IBinder,来与service交流。如果你并不像绑定它,就直接返回null
onDestroy();当服务不再被使用时需要销毁时调用,你应该在这里用来停止线程,注销监听器,广播。
如果一个组件如activity使用的是 startService()来启动服务的话,就会触发 onStartCommand(),然后服务就会一直运行,直到任务结束;服务的停止需要
手动控制:在启动服务的组件中调用 stopService()或者在服务本类中调用stopSelf()
如果一个组件使用的是bindService()来启动服务的话,该服务就会运行,直到组件不约束它。
在系统内存很低的情况下,系统会强制停止服务,来恢复用于运行activity;但是下面这些情况下的服务不易被系统停止:服务与activity绑定或者
服务位于前台。但是如果服务最后还是被停止了,我们要重新启用服务。
service的创建和使用,
也可以使用IntentService,它是service子类,在处理后台任务时,不需要你自己开线程,可以直接在 onHandleIntent()中进行任务。<span style="font-size:14px;">1.<manifest ... > ... <application ... > <service android:name=".ExampleService" android:exported="false" /> ... </application> </manifest> public class HelloIntentService extends IntentService { A constructor is required, and must call the super IntentService(String) constructor with a name for the worker thread. public HelloIntentService() { super("HelloIntentService"); } * The IntentService calls this method from the default worker thread with * the intent that started the service. When this method returns, IntentService * stops the service, as appropriate. @Override protected void onHandleIntent(Intent intent) { // Normally we would do some work here, like download a file. // For our sample, we just sleep for 5 seconds. try { Thread.sleep(5000); } catch (InterruptedException e) { // Restore interrupt status. Thread.currentThread().interrupt(); } } }</span>
<span style="font-size:14px;"> </span>
使用intentservice,在任务结束后会自动关闭服务。
2.使用startService()来启动服务,一般在不需要交互的情况下使用这种方式,
在onStartCommand()中接受Intent ;Intent intent = new Intent(this, HelloService.class);
startService(intent);
如果你的服务没有经过绑定,那么startService(intent)中的intent就是唯一的向service交互的方式;service中通过广播来向外发布回调。如果多次启动服务,会导致onStartCommand()被多次调用。
onStartCommand()必须返回一个整形值,描述这当系统杀掉服务时,系统该如何继续service
START_NOT_STICKY,杀掉后,不再重建
START_STICKY,杀掉后,自动重启,然后接收的intent=null
START_REDELIVER_INTENT,杀掉后,自动重启,然后接收的intent不为空;像文件下载
3.使用bindService()启动;这种方式使用更加复杂,但也更加灵活。
当你需要与服务交互的时候,可以采用这种方式;必须重写 onBind()方法返回IBinder,来与其他组件交流。在其他组件中获取该IBinder对象
有一种client-server的感觉,可以有多个客户端与server交流
客户端组件,必须创建ServiceConnection,用来监听与service的连接;
可以有多个客户端连接service,但是service的onBind只会执行一次,所以分发给其他客户端的都是同一个IBinder对象
只有在多个客户端都解绑了服务之后,服务才会被销毁。
使用这种服务有个最重要的地方就是定义IBinder;
有3种方式:
a.直接继承Binder,这也是一般app常用的一种方式,适用于你的服务与你的app是处于同一个进程中的。你的服务仅仅是为了
处理后台任务。
b.使用Messenger,适用于需要跨进程通讯且线程安全且非并发,同一个时间只能接受到一个请求,你可以使用Messenger和Handler这2个 类来进行service和client的交互。
服务端建立信使对象,通过通过onbind将服务端信使对象放在IBind中回调给客户端,这样子客户端就可以拿到服务端信使对象,使用服务端信使对象给服务端发信息了。
在客户端连接上服务端后,可以建立客户端信使对象,将客户端信使对象以消息的形式,发送给服务端,服务端拿到客户端信使对象后可以给客户端发消息。
这个是线程安全的。因为都是在同一个队列里,在同一个线程里进行的。它本身是基于AIDL构建的。
c.使用AIDL,适用于需要跨进程,且非线程安全,能够同一时间处理多个请求的场合。
它的使用是创建一个.aidl file文件,里面定义接口,然后android sdk tool使用它来生成一个抽象类,抽象类里实现各种接口方法。
注意:对于大多数应用,我们都不应该使用AIDL来bindservice.因为这会使得结果更复杂。
首先我们看第一种方式;直接继承Binder,
例如一个场景一个app是用来音乐播放,它关联了一个activity。activity启用服务来后台播放音乐。服务端:
<span style="font-size:14px;">public class LocalService extends Service { // Binder given to clients private final IBinder mBinder = new LocalBinder(); // Random number generator private final Random mGenerator = new Random(); //Class used for the client Binder. Because we know this service always //runs in the same process as its clients, we don't need to deal with IPC. public class LocalBinder extends Binder { LocalService getService() { // Return this instance of LocalService so clients can call public methods return LocalService.this; } } @Override public IBinder onBind(Intent intent) { return mBinder; } //method for clients public int getRandomNumber() { return mGenerator.nextInt(100); } }</span>
客户端:
<span style="font-size:14px;">public class BindingActivity extends Activity { LocalService mService; boolean mBound = false; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } @Override protected void onStart() { super.onStart(); // Bind to LocalService Intent intent = new Intent(this, LocalService.class); bindService(intent, mConnection, Context.BIND_AUTO_CREATE); } @Override protected void onStop() { super.onStop(); // Unbind from the service if (mBound) { unbindService(mConnection); mBound = false; } } //** Called when a button is clicked (the button in the layout file attaches to // * this method with the android:onClick attribute) public void onButtonClick(View v) { if (mBound) { // Call a method from the LocalService. // However, if this call were something that might hang, then this request should // occur in a separate thread to avoid slowing down the activity performance. int num = mService.getRandomNumber(); Toast.makeText(this, "number: " + num, Toast.LENGTH_SHORT).show(); } } // Defines callbacks for service binding, passed to bindService() private ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName className, IBinder service) { // We've bound to LocalService, cast the IBinder and get LocalService instance LocalBinder binder = (LocalBinder) service; mService = binder.getService(); mBound = true; } @Override public void onServiceDisconnected(ComponentName arg0) { mBound = false; } }; }</span>
接下来我们看第二种方式;使用Messenger,
如果您只需要在 Activity 可见时与服务交互,则应在 onStart() 期间绑定,在 onStop() 期间取消绑定。如果您希望 Activity 在后台停止运行状态下仍可接收响应,则可在 onCreate() 期间绑定,在 onDestroy() 期间取消绑定。请注意,这意味着您的 Activity 在其整个运行过程中(甚至包括后台运行期间)都需要使用服务,因此如果服务位于其他进程内,那么当您提高该进程的权重时,系统终止该进程的可能性会增加
下面是个完整的例子;客户端和服务端使用Messenger来通讯。
服务端:Server_Service
<span style="font-size:14px;">package com.example.administrator.service_messenger; import android.app.Service; import android.content.Intent; import android.content.ServiceConnection; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.os.Messenger; import android.os.RemoteException; import android.widget.Toast; /** * 在manifest清单文件中声明service为另起新的进程。 */ public class Server_Service extends Service { private Messenger clientMessenger; /** * 服务端的handler */ class ServerHandler extends Handler { @Override public void handleMessage(Message msg) { switch (msg.what) { case Client.MSG_FROM_CLIENT: String fromClient = msg.getData().getString("msgFromClient"); //收到来自客户端的信息 Toast.makeText(getApplicationContext(), fromClient, Toast.LENGTH_SHORT).show(); //回复一下客户端 Message msgFromServer = Message.obtain(null, Client.MSG_FROM_SERVER); msgFromServer.arg1 =200; try { clientMessenger.send(msgFromServer); } catch (RemoteException e) { e.printStackTrace(); } break; case Client.MSG_FROM_CLIENT_MESSE: //得到客户端的信使对象 clientMessenger = msg.replyTo; break; } } } /** * 服务端的Messenger,使用服务端的handler做参数构造。 */ final Messenger serverMessenger = new Messenger(new ServerHandler()); /** * 我们在这里使用服务端的信使对象serverMessenger的IBinder,将其返回给客户端中的 * serviceConntected */ @Override public IBinder onBind(Intent intent) { Toast.makeText(getApplicationContext(), "客户端绑定服务端成功", Toast.LENGTH_SHORT).show(); return serverMessenger.getBinder(); } @Override public void unbindService(ServiceConnection conn) { super.unbindService(conn); Toast.makeText(getApplicationContext(), "客户端取消了服务绑定", Toast.LENGTH_SHORT).show(); } } </span>在manifest下配置:
<span style="font-size:14px;"><service android:name=".Server_Service" android:process=":v1"/></span>
客户端:Client
<span style="font-size:14px;">package com.example.administrator.service_messenger; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.os.Messenger; import android.os.RemoteException; import android.support.v7.app.AppCompatActivity; import android.view.View; import android.widget.Toast; import java.io.UnsupportedEncodingException; import java.util.Calendar; public class Client extends AppCompatActivity { public static final int MSG_FROM_CLIENT = 1; public static final int MSG_FROM_CLIENT_MESSE = 2; public static final int MSG_FROM_SERVER = 3; //在客户端里拿到了服务端的信使对象 Messenger serverMessenger = null; //标记是否已经连上了服务端 boolean mBound; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_client); //绑定服务 findViewById(R.id.bt_bind).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { bindService(); } }); //通过服务端的信使来发信息给服务端 findViewById(R.id.bt_send).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { try { sendInfoToServer(); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } } }); //手动解绑服务 findViewById(R.id.bt_unbind).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { unBindService(); } }); } @Override protected void onDestroy() { super.onDestroy(); //在activity销毁时,可以选择取消绑定服务 unBindService(); } //客户端的handler private Handler clientHandler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case MSG_FROM_SERVER: Toast.makeText(getApplicationContext(), "server received :"+msg.arg1+"", Toast.LENGTH_SHORT).show(); break; } } }; /** * 客户端的Messenger,使用客户的handler做参数构造。 */ final Messenger clientMessenger = new Messenger(clientHandler); private ServiceConnection mConnection = new ServiceConnection() { public void onServiceConnected(ComponentName className, IBinder service) { //当我们连接上服务端后,会调用该方法。在方法里会回调给我们IBinder对象, //由于bindservice绑定服务后,服务端返回给客户端的IBinder是同一个。 //所以这里我们可以利用IBinder来构建服务端里的信使对象。 //之后有了服务端的信使对象,就可以随便网服务端发送信息了。 //构建服务端信使对象 serverMessenger = new Messenger(service); mBound = true; //并将客户端的messenger发给服务端,让服务端也可以给客户端发送消息 Message msg = Message.obtain(null, MSG_FROM_CLIENT_MESSE); msg.replyTo = clientMessenger; try { serverMessenger.send(msg); } catch (RemoteException e) { e.printStackTrace(); } } public void onServiceDisconnected(ComponentName className) { // 当连接服务端异常时调用 serverMessenger = null; mBound = false; } }; private void sendInfoToServer() throws UnsupportedEncodingException { if (!mBound) return; Message msg = Message.obtain(null, MSG_FROM_CLIENT, 0, 0); String strMsg = "server received:" + Calendar.getInstance().getTime(); Bundle data = new Bundle(); data.putString("msgFromClient", strMsg); msg.setData(data); try { serverMessenger.send(msg); } catch (RemoteException e) { e.printStackTrace(); } } @Override protected void onStart() { super.onStart(); // 在界面可见时,可以选择去绑定服务 } @Override protected void onStop() { super.onStop(); // 在界面不可见时,可以选择去解绑服务 } private void bindService() { bindService(new Intent(this, Server_Service.class), mConnection, Context.BIND_AUTO_CREATE); } private void unBindService() { if (mBound) { unbindService(mConnection); mBound = false; } } } </span>
最后我们来看第三种方式使用AIDL:
这种方式支持多个请求同时进行,使用的时候要保证能够并发。基本流程:
与上面的使用信使一样,只不过IBinder的获取渠道不一样罢了,这里是使用创建.aidl文件来实现。
最重要的点:创建.aidl文件,里面定义一些接口,这些接口包括由服务端实现的,和客户端实现的。
服务端实现的接口,就是由.aidl文件生成的接口文件,我们在服务端继承该接口文件里定义的一个静态内部抽象类Stub,该类是Binder的子类,正好可以让我们在OnBind方法中返回给客户端。
如果你要服务端回调该客户端信息,你要再定义一个.aidl文件,里面包含回调方法。将该接口作为参数,在上面一个.aidl文件中定义注册和反注册方法;这样,当客户端连接成功服务端后,让客户端实现该接口对象,作为实参传递进来,最后就传给了服务端。服务端拿着对象往客户端发信息。
下面是一个例子:
例子结构图:
Book.java
package com.example.books.aidl; import android.os.Parcel; import android.os.Parcelable; //Book要实现跨进程,需要实现parcelable接口;还要定义该类的aidl文件 public class Book implements Parcelable { public int bk_id; public String name; public double price; public Book(int bk_id, String name, double price) { super(); this.bk_id = bk_id; this.name = name; this.price = price; } public Book() { super(); } @Override public String toString() { return "Book [bk_id=" + bk_id + ", name=" + name + ", price=" + price + "]"+"\n"; } @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(bk_id); dest.writeString(name); dest.writeDouble(price); } public static final Creator<Book> CREATOR = new Creator<Book>() { @Override public Book createFromParcel(Parcel source) { int bk_id = source.readInt(); String name = source.readString(); double price = source.readDouble(); return new Book(bk_id, name, price); } @Override public Book[] newArray(int size) { return new Book[size]; } }; }
Book.aidl
package com.example.books.aidl; parcelable Book;
ICallBack.aidl
package com.example.books.aidl; import com.example.books.aidl.Book; //用于服务端回调给客户端使用;在客户端中定义,由服务端调用 interface ICallBack { void success_GetBookList(in List<Book> allBook); void success_AddBook(in Book book); }
IBookManager.aidl
package com.example.books.aidl; import com.example.books.aidl.Book; import com.example.books.aidl.ICallBack; //服务端返回给客户端远程接口 interface IBookManager { //客户端调用 void requestGetBookList(); // 返回书籍列表 void requestAddBook(in Book book); // 添加书籍 //监听客户端行为,在连接服务成功后,注册客户端监听 void registerListener(ICallBack listener); // 注册接口 void unregisterListener(ICallBack listener); // 注册接口 }
BookManagerService.java
package com.example.books.service; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import android.app.Service; import android.content.Intent; import android.os.Binder; import android.os.IBinder; import android.os.RemoteCallbackList; import android.os.RemoteException; import android.support.annotation.Nullable; import android.util.Log; import com.example.books.aidl.Book; import com.example.books.aidl.IBookManager; import com.example.books.aidl.ICallBack; public class BookManagerService extends Service { protected static final String TAG = "book"; // 支持并发读写 private CopyOnWriteArrayList<Book> mBookList = new CopyOnWriteArrayList<>(); // 客户端数量 private RemoteCallbackList<ICallBack> mListenerList = new RemoteCallbackList<>(); private ExecutorService cacheExecutorService = Executors .newCachedThreadPool(); // 返回给客户端的接口对象;客户端调用 private Binder mBinder = new IBookManager.Stub() { @Override public void registerListener(ICallBack listener) throws RemoteException { mListenerList.register(listener); int num = mListenerList.beginBroadcast(); mListenerList.finishBroadcast(); Log.e(TAG, "添加完成, 注册接口数: " + num); } @Override public void unregisterListener(ICallBack listener) throws RemoteException { mListenerList.unregister(listener); int num = mListenerList.beginBroadcast(); mListenerList.finishBroadcast(); Log.e(TAG, "删除完成, 注册接口数: " + num); } //多线程处理,可以在同一时间同时进行多个请求。 @Override public void requestGetBookList() throws RemoteException { cacheExecutorService.submit(new Runnable() { @Override public void run() { try { Thread.sleep(4000); } catch (InterruptedException e) { e.printStackTrace(); } mListenerList.beginBroadcast(); ICallBack listener = mListenerList.getBroadcastItem(0); Log.e(TAG, "发送通知: " + listener.toString()); try { listener.success_GetBookList(mBookList); } catch (RemoteException e) { e.printStackTrace(); } mListenerList.finishBroadcast(); } }); } //多线程处理 @Override public void requestAddBook(final Book book) throws RemoteException { cacheExecutorService.submit(new Runnable() { @Override public void run() { try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } mBookList.add(book); mListenerList.beginBroadcast(); ICallBack listener = mListenerList.getBroadcastItem(0); Log.e(TAG, "发送通知: " + listener.toString()); try { listener.success_AddBook(book); } catch (RemoteException e) { e.printStackTrace(); } mListenerList.finishBroadcast(); } }); } }; @Nullable @Override public IBinder onBind(Intent intent) { return mBinder; } }
MainActivity.java
package com.example.books; import java.util.List; import android.app.Activity; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; import android.view.View; import android.view.View.OnClickListener; import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; import com.example.books.aidl.Book; import com.example.books.aidl.IBookManager; import com.example.books.aidl.ICallBack; import com.example.books.service.BookManagerService; public class MainActivity extends Activity implements OnClickListener { private TextView tv_list; private IBookManager mRemoteBookManager; // 服务端给客户端的回调 private ICallBack callBack = new ICallBack.Stub() { @Override public void success_GetBookList(final List<Book> allBook) throws RemoteException { runOnUiThread(new Runnable() { public void run() { tv_list.setText(allBook.toString()); } }); } @Override public void success_AddBook(final Book book) throws RemoteException { runOnUiThread(new Runnable() { public void run() { toast("成功添加书本:" + book); } }); } }; private ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { isConnected = true; mRemoteBookManager = IBookManager.Stub.asInterface(service); toast("connected success"); // 监听将数据回调给客户端 try { mRemoteBookManager.registerListener(callBack); } catch (RemoteException e) { e.printStackTrace(); } } @Override public void onServiceDisconnected(ComponentName name) { mRemoteBookManager = null; isConnected = false; } }; private EditText et_id; private EditText et_name; private EditText et_price; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); tv_list = (TextView) findViewById(R.id.tv_list); findViewById(R.id.bt_bind).setOnClickListener(this); findViewById(R.id.bt_getAll).setOnClickListener(this); findViewById(R.id.bt_add).setOnClickListener(this); et_id = (EditText) findViewById(R.id.et_id); et_name = (EditText) findViewById(R.id.et_name); et_price = (EditText) findViewById(R.id.et_price); } @Override protected void onDestroy() { if (isConnected == true) { isConnected = false; try { mRemoteBookManager.unregisterListener(callBack); unbindService(mConnection); } catch (Exception e) { e.printStackTrace(); } } super.onDestroy(); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.bt_bind: startBindService(); break; case R.id.bt_add: if (isConnected == false) { return; } String id = et_id.getText().toString(); String name = et_name.getText().toString(); String price = et_price.getText().toString(); Book book = new Book(Integer.valueOf(id), name, Double.valueOf(price)); try { mRemoteBookManager.requestAddBook(book); } catch (RemoteException e) { e.printStackTrace(); } break; case R.id.bt_getAll: if (isConnected == false) { return; } try { mRemoteBookManager.requestGetBookList(); } catch (RemoteException e) { e.printStackTrace(); } break; } } private boolean isConnected = false; private void startBindService() { if (isConnected == false) { Intent intent = new Intent(this, BookManagerService.class); bindService(intent, mConnection, Context.BIND_AUTO_CREATE); } else { toast("has Connected"); } } private void toast(String msg) { Toast.makeText(getApplicationContext(), msg, 0).show(); } }
activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <Button android:id="@+id/bt_bind" android:layout_width="match_parent" android:layout_height="wrap_content" android:onClick="bindService" android:text="绑定服务" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" > <EditText android:id="@+id/et_id" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_margin="5dp" android:layout_weight="1" android:text="1" /> <EditText android:id="@+id/et_name" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_margin="5dp" android:layout_weight="1" android:text="红马" /> <EditText android:id="@+id/et_price" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_margin="5dp" android:layout_weight="1" android:inputType="number" android:text="32" /> </LinearLayout> <Button android:id="@+id/bt_add" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="添加一本图书" /> <Button android:id="@+id/bt_getAll" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="获取所有图书" /> <TextView android:id="@+id/tv_list" android:layout_width="match_parent" android:layout_height="wrap_content" android:onClick="getBookList" android:text="显示图书列表" /> </LinearLayout>
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.books" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="22" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name=".MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <service android:name="com.example.books.service.BookManagerService" android:process=":remote_v1" > </service> </application> </manifest>
效果图:
相关文章推荐
- Android Studio 接入ZXing依赖库全流程
- Android新特性-ToolBar小结
- Android 关于使用LruCache缓存你想缓存的数据
- 安卓学习之—跳转到安卓系统的各个界面总结
- 安卓学习之-ListView相关的XML属性及方法
- 《Android源码设计模式》之单例模式
- Android注解框架Annotations从配置到应用
- 用Gradle 构建你的android程序
- 安卓学习笔记—ExpandableListView适配器参数解释(实现列表中有子列表)
- 安卓学习笔记-StickyListHeadersListView框架(自动分栏)
- 4 行代码实现 Android 快速文件下载
- Android 序列化 & 反序列化
- Android Anr监控
- Weex 版扫雷游戏开发
- Android 百分比布局库(percent-support-lib) 解析与扩展
- [实践] Android5.1.1源码 - 添加应用权限
- Xamarin如何生成Android项目的APK
- Android屏幕相关知识(一)
- Android中的自定义注解
- android Binder的使用方式 示例