Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> android中Service使用詳解

android中Service使用詳解

編輯:關於Android編程

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綁定或者
服務位於前台。但是如果服務最後還是被停止了,我們要重新啟用服務。


service的創建和使用,

也可以使用IntentService,它是service子類,在處理後台任務時,不需要你自己開線程,可以直接在 onHandleIntent()中進行任務。

 

1.
  ...
  
      
      ...
  


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();
      }
  }
}

 

使用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啟用服務來後台播放音樂。


服務端:

 

 

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);
    }
}

客戶端:

 

 

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;
        }
    };
}

 

 

接下來我們看第二種方式;使用Messenger,

如果您只需要在 Activity 可見時與服務交互,則應在 onStart() 期間綁定,在 onStop() 期間取消綁定。

如果您希望 Activity 在後台停止運行狀態下仍可接收響應,則可在 onCreate() 期間綁定,在 onDestroy() 期間取消綁定。請注意,這意味著您的 Activity 在其整個運行過程中(甚至包括後台運行期間)都需要使用服務,因此如果服務位於其他進程內,那麼當您提高該進程的權重時,系統終止該進程的可能性會增加

下面是個完整的例子;客戶端和服務端使用Messenger來通訊。

服務端:Server_Service

 

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();
    }
}
在manifest下配置:

 

 


客戶端:Client
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;
        }
    }

}

 

 

最後我們來看第三種方式使用AIDL:


 

 


 

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved