1、前臺服務java
service基本都是在後臺進行運行的,一直都是在默默地工做,不愛表現本身(沒有界面),但是這樣一個基層的工做人員(service)在Android系統的待遇(優先級)仍是比較差的,在系統內存不足的狀況下,就有可能回收掉正在後臺運行的service,所以service就會中止運行。若是但願service一直保持運行,不因系統內存不足而回收,該怎麼作呢?能夠先考慮使用前臺service,前臺service和普通service的區別在於,前臺service一直有一個正在運行的圖標在系統的狀態欄中顯示。但有一點要注意的是使用前臺service不表明service不能被殺死,在應用程序管理那裏能夠中止前臺service,狀態欄通知被刪除了也能解除service!
那前臺service有什麼能夠用來幹什麼呢?一般來講,一個音樂的播放器能夠設置前臺service,在狀態欄中能夠顯示播放的歌曲相關的信息並能夠做爲啓動按鈕,打開音樂播放器,並且用戶也是明確知道音樂播放器在運行的。還有天氣相關的app也能夠用前臺service,在狀態欄中實時同步更新的天氣信息。android
那麼咱們先來看看前臺service的效果吧:app
效果圖能夠看到前臺service的界面,基本和一個通知信息界面差很少,而後點擊中止前臺service,狀態欄的圖標就消失了!此時前臺service也就關閉了!固然用戶想要中止前臺service,也跟普通service同樣,能夠在程序管理器那裏進行中止,具體看下面的效果圖!ide
看完效果圖,咱們來看下代碼的實現,其實基本跟普通的service差很少,就是多了須要調用startForeground()方法,這個方法須要兩個參數:一個惟一標識通知的整數和給狀態欄的通知!若是須要刪除前臺service須要調用stopForeground()方法!函數
主界面的代碼:工具
[java] view plain copyui
- package com.liangdianshui.service2;
-
- import com.example.service2.R;
-
- import android.app.Activity;
- import android.content.Intent;
- import android.os.Bundle;
- import android.view.View;
- import android.view.View.OnClickListener;
- import android.widget.Button;
-
- public class MainActivity extends Activity implements OnClickListener {
-
- private Button mBtStartFrontService;
- private Button mBtStopFrontService;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
-
- initView();
- }
-
- private void initView() {
- mBtStartFrontService = (Button) findViewById(R.id.bt_start_front_server);
- mBtStopFrontService = (Button) findViewById(R.id.bt_stop_front_server);
- mBtStartFrontService.setOnClickListener(this);
- mBtStopFrontService.setOnClickListener(this);
- }
-
- @Override
- public void onClick(View v) {
- // TODO Auto-generated method stub
- Intent intent2 = new Intent(MainActivity.this, MyService2.class);
- switch (v.getId()) {
- case R.id.bt_start_front_server:
- startService(intent2);
- break;
- case R.id.bt_stop_front_server:
- stopService(intent2);
- break;
- }
- }
-
- }
Service類的代碼:this
[java] view plain copy加密
- package com.liangdianshui.service2;
-
- import com.example.service2.R;
-
- import android.app.Notification;
- import android.app.PendingIntent;
- import android.app.Service;
- import android.content.Intent;
- import android.os.Binder;
- import android.os.IBinder;
- import android.util.Log;
-
- public class MyService2 extends Service {
-
- private static final String TAG = MyService2.class.getSimpleName();
-
- private MyBinder mBinder = new MyBinder();
-
- @Override
- public IBinder onBind(Intent intent) {
- // TODO Auto-generated method stub
- return mBinder;
- }
-
- @Override
- public void onCreate() {
- // TODO Auto-generated method stub
- super.onCreate();
- Log.i(TAG, "onCreate");
- frontService();
- }
-
- @Override
- public void onDestroy() {
- // TODO Auto-generated method stub
- super.onDestroy();
- Log.i(TAG, "onDestroy");
- }
-
- @Override
- public int onStartCommand(Intent intent, int flags, int startId) {
- // TODO Auto-generated method stub
- Log.i(TAG, "onStartCommand");
- return super.onStartCommand(intent, flags, startId);
- }
-
- class MyBinder extends Binder {
-
- public void toDo() {
- Log.i(TAG, "toDo");
- }
- }
-
- /**
- * 前臺服務
- */
- private void frontService() {
- Notification notification = new Notification(R.drawable.ic_launcher,
- "Notification", System.currentTimeMillis());
- Intent notificationIntent = new Intent(this, MainActivity.class);
- PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
- notificationIntent, 0);
- notification
- .setLatestEventInfo(this, "Title", "Content", pendingIntent);
- startForeground(1, notification);
- Log.d(TAG, "onCreate() executed");
- }
- }
最後記得跟普通service同樣,在配置文件中聲明!操作系統
Demo的下載地址:http://download.csdn.net/detail/two_water/9591717
由於電腦有加密系統,因此只要把上面的類複製到對應的Java文件就能夠運行了。
2、遠程服務
說到遠程服務(remote service),咱們怎麼建立遠程servie呢?
其實在普通的service基礎上,咱們只要在配置文件中註冊Service的時候將它的android:process屬性指定成:remote就能夠了!
注意:remote前面是有個冒號的!以下圖:
以後咱們瞭解下Activity怎麼和遠程service進行通訊?爲何要了解這個呢?難道遠程服務不能像普通服務那樣和Activity那樣進行通訊嗎?
其實遠程服務跟啓動遠程服務的程序不是同一個進程的,並且他們的包名也是不同的!(後面運行Demo的時候,看效果圖,打印的log信息能夠看到他們進程ID號不一樣,包名不一樣,具體在後面驗證)
在Android中, 每一個應用程序都有本身的進程,當須要在不一樣的進程之間傳遞對象時,該如何實現呢? 顯然, Java中是不支持跨進程內存共享的。所以要傳遞對象, 須要把對象解析成操做系統可以理解的數據格式, 以達到跨界對象訪問的目的。在JavaEE中,採用RMI經過序列化傳遞對象。在Android中, 則採用AIDL(Android Interface Definition Language:接口描述語言)方式實現。
那麼什麼是AIDL呢?
AIDL是一種接口定義語言,用於約束兩個進程間的通信規則,供編譯器生成代碼,實現Android設備上的兩個進程間通訊(IPC)。AIDL的IPC 機制和EJB所採用的CORBA很相似,進程之間的通訊信息,首先會被轉換成AIDL協議消息,而後發送給對方,對方收到AIDL協議消息後再轉換成相應 的對象。因爲進程之間的通訊信息須要雙向轉換,因此android採用代理類在背後實現了信息的雙向轉換,代理類由android編譯器生成,對開發人員 來講是透明的。
那麼具體咱們是怎麼操做的呢?
(1)在工程的src下,新創建一個文本文件,將要實現的函數放在這個文件中,後綴爲.aidl。(主要是一個接口,定義方法)
(2)刷新工程後,就會發如今gen包下,有一個同名的java文件,這是aidl工具自動生成的,裏面,就有咱們要實現的函數。
(3)Aidl定義好後,咱們就要實現咱們的remote service了。它也是繼承自service的。
(4)Service實現後,要將它在mainfest.xml設置爲remote.注意,客戶端服務端在同個App中,android:process=":remote",表明在應用程序裏,當須要該service時,會自動建立新的進程。而若是是android:process="remote",沒有「:」分號的,則建立全局進程,不一樣的應用程序共享該進程。
(5)最後,來實現咱們的客戶端,也就是Activity,來調用service。
最後,咱們來看下代碼:
首先須要新建一個AIDL文件,在這個文件中定義好Activity須要與Service進行通訊的方法。新建MyAIDL.aidl文件,代碼以下所示:
[java] view plain copy
- package com.liangdianshui.service3;
-
- interface MyAIDL {
- String combineString(String str1,String str2);
- int countChar(String str);
- }
在服務類中,經過MyAIDL.Stub來實現MyAIDL.aidl中的兩個方法,而後在onBind()方法中將MyAIDLService.Stub的實現返回,其餘的跟普通service差很少!由於Stub其實就是Binder的子類,因此在onBind()方法中能夠直接返回Stub的實現。
[java] view plain copy
- package com.liangdianshui.service3;
-
- import com.liangdianshui.service3.MyAIDL.Stub;
-
- import android.app.Service;
- import android.content.Intent;
- import android.os.Binder;
- import android.os.IBinder;
- import android.os.Process;
- import android.os.RemoteException;
- import android.util.Log;
-
- public class MyService3 extends Service {
-
- private static final String TAG = MyService3.class.getSimpleName();
-
- MyAIDL.Stub mBinder = new Stub() {
-
- @Override
- public String combineString(String str1, String str2)
- throws RemoteException {
- // TODO Auto-generated method stub
- return str1 + str2;
- }
-
- @Override
- public int countChar(String str) throws RemoteException {
- // TODO Auto-generated method stub
- return str.length();
- }
-
- };
-
- @Override
- public IBinder onBind(Intent intent) {
- // TODO Auto-generated method stub
- return mBinder;
- }
-
- @Override
- public void onCreate() {
- // TODO Auto-generated method stub
- super.onCreate();
- Log.i(TAG, "onCreate");
- Log.i(TAG, "MyService3 process ID:" + Process.myPid());
- }
-
- @Override
- public void onDestroy() {
- // TODO Auto-generated method stub
- super.onDestroy();
- Log.i(TAG, "onDestroy");
- }
-
- @Override
- public int onStartCommand(Intent intent, int flags, int startId) {
- // TODO Auto-generated method stub
- Log.i(TAG, "onStartCommand");
- return super.onStartCommand(intent, flags, startId);
- }
-
- }
在MainActivity中,ServiceConnection中的代碼。能夠看到,這裏首先使用了MyAIDLService.Stub.asInterface()方法將傳入的IBinder對象傳換成了MyAIDLService對象,接下來就能夠調用在MyAIDLService.aidl文件中定義的全部接口!
[java] view plain copy
- package com.liangdianshui.service3;
-
- import android.app.Activity;
- import android.content.ComponentName;
- import android.content.Intent;
- import android.content.ServiceConnection;
- import android.os.Bundle;
- import android.os.IBinder;
- import android.os.Process;
- import android.util.Log;
- import android.view.View;
- import android.view.View.OnClickListener;
- import android.widget.Button;
-
- public class MainActivity extends Activity implements OnClickListener {
-
- private final static String TAG = MainActivity.class.getSimpleName();
-
- private Button mBtStartRemoteService;
- private Button mBtStopRemoteService;
- private Button mBtBindRemoteService;
- private Button mBtUnbindRemoteService;
-
- private MyAIDL mAIDL;
-
- private ServiceConnection mConnection = new ServiceConnection() {
-
- @Override
- public void onServiceConnected(ComponentName name, IBinder service) {
- // TODO Auto-generated method stub
- mAIDL = MyAIDL.Stub.asInterface(service);
- try {
- int result = mAIDL.countChar("liangdianshui");
- String str = mAIDL.combineString("liangdianshui", "hello");
- Log.d(TAG, "countChar: " + result);
- Log.d(TAG, "combineString : " + str);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
- @Override
- public void onServiceDisconnected(ComponentName name) {
- // TODO Auto-generated method stub
-
- }
-
- };
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
-
- initView();
-
- Log.i(TAG, "MainActivity process ID:" + Process.myPid());
- }
-
- private void initView() {
- // TODO Auto-generated method stub
- mBtStartRemoteService = (Button) findViewById(R.id.bt_start_remote_server);
- mBtStopRemoteService = (Button) findViewById(R.id.bt_stop_remote_server);
- mBtBindRemoteService = (Button) findViewById(R.id.bt_bind_remote_server);
- mBtUnbindRemoteService = (Button) findViewById(R.id.bt_unbind_remote_server);
- mBtStartRemoteService.setOnClickListener(this);
- mBtStopRemoteService.setOnClickListener(this);
- mBtBindRemoteService.setOnClickListener(this);
- mBtUnbindRemoteService.setOnClickListener(this);
- }
-
- @Override
- public void onClick(View v) {
- // TODO Auto-generated method stub
- Intent intent3 = new Intent(MainActivity.this, MyService3.class);
- switch (v.getId()) {
- case R.id.bt_start_remote_server:
- startService(intent3);
- break;
- case R.id.bt_stop_remote_server:
- //點擊後會發現不能中止遠程service,由於遠程service和本程序不在同一個進程
- stopService(intent3);
- break;
- case R.id.bt_bind_remote_server:
- bindService(intent3, mConnection, BIND_AUTO_CREATE);
- break;
- case R.id.bt_unbind_remote_server:
- unbindService(mConnection);
- break;
- }
- }
-
- }
運行咱們的程序,並點擊「開啓遠程Server」,看下打印出來的Log:
不難發現,它們的進程ID不一樣了,並且包名也是不同的,包名後面還跟上了:remote標識。
其實遠程service跟普通service開啓和關閉基本是同樣的,就是綁定服務那裏不一樣,由於是創建在不一樣進程間的通訊!那咱們來看下綁定遠程服務和解綁的效果圖吧:
能夠看出,打印出來的log信息,把遠程服務的方法的結果打印出來了!
Demo的下載地址:http://download.csdn.net/detail/two_water/9592054
由於電腦有加密系統,因此只要把上面的類複製到對應的java文件就能夠運行了。