天天看點

service 的四種使用場景與方法

今天晚上把service的用法整理一下,service在Android中的地位僅次于activity,其重要性可見一斑。下面主要從四個部分分别講解:

分别是startService,bindservice(兩個基礎用法。通過log檢視生命周期)messenger和aidl(Android IPC機制主要也是通過service與binder來實作的)

編寫activityInfo類來管理這四個測試的activity類,友善activity之間的跳轉,簡化代碼

package com.example.servicetest;

public class ActivityInfo
{
    private String name;
    private Class clazz;

    public ActivityInfo(String name, Class clazz)
    {
        super();
        this.name = name;
        this.clazz = clazz;
    }

    public String getName()
    {
        return name;
    }

    public Class getClazz()
    {
        return clazz;
    }

    public void setName(String name)
    {
        this.name = name;
    }

    public void setClazz(Class clazz)
    {
        this.clazz = clazz;
    }

}
           

測試主類 MainActivity代碼:

package com.example.servicetest;

import java.util.Arrays;
import java.util.List;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;

public class MainActivity extends Activity
{
    private ListView mListView;

    private final List<ActivityInfo> mData = Arrays.asList(new ActivityInfo(
            "StartService", ActivityStartService.class), new ActivityInfo(
            "bindService", ActivityBindService.class), new ActivityInfo(
            "Menssenger", ActivityMessenger.class), new ActivityInfo("aidl",
            ActivityAidl.class));

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //初始化view,個人的風格而已
        initView();
    }

    private void initView()
    {
        mListView = (ListView) findViewById(R.id.lv_activity_main);
        //為listview設定adapter
        mListView.setAdapter(new MyAdapter(this, mData));
        mListView.setOnItemClickListener(new OnItemClickListener()
        {

            @Override
            public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
                    long arg3)
            {
                Intent intent = new Intent();
                //通過前面設計的activityInfo得到要跳轉的activity的class
                intent.setClass(MainActivity.this, mData.get(arg2).getClazz());
                startActivity(intent);
            }
        });
    }
}
           

listView的adapter實作很簡單,繼承自baseAdapter,使用viewholder去優化listview,想必大家都了解。

(1)通過startService(Intent intent)的方式開啟服務

package com.example.servicetest;

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 ActivityStartService extends Activity implements OnClickListener
{

    private Button mButtonStart, mButtonStop;

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.service_layout);
        initView();
    }

    private void initView()
    {
        mButtonStart = (Button) findViewById(R.id.btn_start_service);
        mButtonStop = (Button) findViewById(R.id.btn_stop_service);
        mButtonStart.setOnClickListener(this);
        mButtonStop.setOnClickListener(this);
    }

    @Override
    public void onClick(View arg0)
    {
        switch (arg0.getId())
        {
        case R.id.btn_start_service:
        //開啟service
            startService(new Intent(ActivityStartService.this,
                    StartService.class));
            break;
            //停止service
        case R.id.btn_stop_service:
            stopService(new Intent(ActivityStartService.this,
                    StartService.class));
            break;
        default:
            break;
        }
    }
}
           

service的實作:

package com.example.servicetest;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;

public class StartService extends Service
{
    private final String TAG = "StartService";

    @Override
    public void onCreate()
    {
        Log.e(TAG, "-----oncreate----");
        super.onCreate();
    }

    @Override
    public void onDestroy()
    {
        Log.e(TAG, "-----onDestroy----");
        super.onDestroy();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId)
    {
        Log.e(TAG, "----onStartCommand----");
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public IBinder onBind(Intent arg0)
    {
        Log.e(TAG, "----onBind----");
        return null;
    }

    @Override
    public void onRebind(Intent intent)
    {
        Log.e(TAG, "----onReBind----");
        super.onRebind(intent);
    }

    @Override
    public boolean onUnbind(Intent intent)
    {
        Log.e(TAG, "----onUnbind----");
        return super.onUnbind(intent);
    }

}
           
service 的四種使用場景與方法

(2)bindService的啟動過程,需要注意的是通過bindService啟動service時,當service正常結束的時候,是不會調用onServiceDisconnected方法的,即使手動調用了unBindService()方法。

package com.example.servicetest;

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.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class ActivityBindService extends Activity implements OnClickListener
{
    private Button mButtonBind, mButtonUnBind;
    private final String TAG = "ActivityBindService";

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.service_layout);
        initView();
    }

    private void initView()
    {
        mButtonBind = (Button) findViewById(R.id.btn_start_service);
        mButtonUnBind = (Button) findViewById(R.id.btn_stop_service);
        mButtonBind.setOnClickListener(this);
        mButtonUnBind.setOnClickListener(this);
    }

    @Override
    public void onClick(View arg0)
    {
        switch (arg0.getId())
        {
        case R.id.btn_start_service:
            bindService(
                    new Intent(ActivityBindService.this, StartService.class),
                    mConnection, BIND_AUTO_CREATE);

            break;
        case R.id.btn_stop_service:
            unbindService(mConnection);
            break;

        default:
            break;
        }
    }

    private final ServiceConnection mConnection = new ServiceConnection()
    {

        @Override
        public void onServiceDisconnected(ComponentName arg0)
        {
            Log.e(TAG, "----onServiceDisconnected----");
        }

        @Override
        public void onServiceConnected(ComponentName arg0, IBinder arg1)
        {
            Log.e(TAG, "----onServiceConnected----");
        }
    };
}
           
service 的四種使用場景與方法

(3)messenger使用service進行IPC通信:

messenger主要是使用了Ibinder機制,其本質也是使用了aidl,但是他的好處是不用手工編寫aidl檔案,也不用理會aidl的生成過程。使用麼三messege 和 Handler進行消息進行傳遞通信。因為handler是線程安全而且是一對一的通信,是以當Android IPC是一對一的時候,可以考慮使用messenger代替aidl去實作程序間通信

package com.example.servicetest;

import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.Handler;
import android.os.Handler.Callback;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class ActivityMessenger extends Activity implements OnClickListener
{
    private final String TAG = "ActivityMessenger";
    private Button mButton, mButton2;
    private Messenger iMessenger;
    private final Handler mHandler = new Handler(new Callback()
    {

        @Override
        public boolean handleMessage(Message arg0)
        {
            switch (arg0.what)
            {
            case RemoteService.MSG_FROM_CLIENT:
                String msg = arg0.getData().getString("rsp");
                Log.e(TAG, msg);
                break;

            default:
                break;
            }
            return false;
        }
    });

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.service_layout);
        initView();
    }

    private void initView()
    {
        mButton = (Button) findViewById(R.id.btn_start_service);
        mButton.setOnClickListener(this);
        mButton2 = (Button) findViewById(R.id.btn_stop_service);
        mButton2.setOnClickListener(this);
    }

    @Override
    public void onClick(View arg0)
    {
        switch (arg0.getId())
        {
        case R.id.btn_start_service:
            bindService(
                    new Intent(ActivityMessenger.this, RemoteService.class),
                    mConnection, BIND_AUTO_CREATE);
            break;
        case R.id.btn_stop_service:
            unbindService(mConnection);
            break;
        default:
            break;
        }
    }

    private final ServiceConnection mConnection = new ServiceConnection()
    {

        @Override
        public void onServiceDisconnected(ComponentName arg0)
        {
            Log.e(TAG, "----onServiceDisconnected----");
        }

        @Override
        public void onServiceConnected(ComponentName arg0, IBinder arg1)
        {
            Log.e(TAG, "----onServiceConnected----");
            //初始化messenger
            iMessenger = new Messenger(arg1);
            //設定message的類型
            Message message = Message.obtain(null,
                    RemoteService.MSG_FROM_CLIENT);
            Bundle bundle = new Bundle();
            bundle.putString("msg", "msg from client");
            message.setData(bundle);
            //這一句很重要,表明該消息的回複消息處理的handler為上面定義的mHandler。
            message.replyTo = new Messenger(mHandler);
            try
            {
                iMessenger.send(message);
            } catch (RemoteException e)
            {
                e.printStackTrace();
            }
        }
    };
}
           

下面看看RemoteService類:

package com.example.servicetest;

import android.app.Service;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Handler.Callback;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.util.Log;

public class RemoteService extends Service
{

    public static final int MSG_FROM_CLIENT = ;
    private final String TAG = "RemoteService";
    private Messenger iMessenger;
    private final Handler mHandler = new Handler(new Callback()
    {

        @Override
        public boolean handleMessage(Message arg0)
        {
            switch (arg0.what)
            {
            case RemoteService.MSG_FROM_CLIENT:
            //獲得服務程序傳遞過來的msg
                String msg = arg0.getData().getString("msg");
                Log.e(TAG, msg);
                /**
                *注意前面設定過msg的replyTo為用戶端定義的mHandler
                */
                iMessenger = arg0.replyTo;
                Bundle bundle = new Bundle();
                bundle.putString("rsp", "rsp from server");
                Message message = Message.obtain(null,
                        RemoteService.MSG_FROM_CLIENT);
                message.setData(bundle);
                try
                {
                    iMessenger.send(message);
                } catch (RemoteException e)
                {
                    e.printStackTrace();
                }
                break;
            default:
                break;
            }
            return false;
        }
    });

    @Override
    public IBinder onBind(Intent arg0)
    {
        return new Messenger(mHandler).getBinder();
    }

}
           
service 的四種使用場景與方法

(4)最後就是aidl方式,aidl是處理Android程序間通信的,可以實作一對多的通信,下面通過一個相加求和的例子來講解

下面是aidl檔案,在兩個app項目中,需要設定包名一模一樣,會在gen包下生成對應的Java檔案

package com.example.servicetest;
/**
*注意書寫規範
*interface 沒有 public private 的修飾
*方法也沒有public private的修飾
*/
interface AIDLSum{
    double sum(double d1, double d2);
}
           
package com.example.servicetest;

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.RemoteException;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class ActivityAidl extends Activity implements OnClickListener
{

    private Button mButton;
    private final String TAG = "ActivityAidl";
    private AIDLSum mAidlService;

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.service_layout);
        initView();
    }

    private void initView()
    {
        mButton = (Button) findViewById(R.id.btn_start_service);
        mButton.setOnClickListener(this);
    }

    @Override
    public void onClick(View arg0)
    {
        switch (arg0.getId())
        {
        case R.id.btn_start_service:
            bindService(new Intent(ActivityAidl.this, AIDLService.class),
                    mConnection, BIND_AUTO_CREATE);
            break;

        default:
            break;
        }
    }

    private final ServiceConnection mConnection = new ServiceConnection()
    {

        @Override
        public void onServiceDisconnected(ComponentName arg0)
        {

        }

        @Override
        public void onServiceConnected(ComponentName arg0, IBinder arg1)
        {
            Log.e(TAG, "----onServiceConnected----");
            //asInterface函數可以在gen的aidl對應的java檔案中檢視
            mAidlService = AIDLSum.Stub.asInterface(arg1);
            double sum;
            try
            {
                sum = mAidlService.sum(, );
                Log.e(TAG, sum + "");
            } catch (RemoteException e)
            {
                e.printStackTrace();
            }
        }
    };

    @Override
    protected void onDestroy()
    {
        super.onDestroy();
        unbindService(mConnection);
    };
}
           

最後看看AIDLService.java檔案:

package com.example.servicetest;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;

public class AIDLService extends Service
{
    private final String TAG = "AIDLService";

    @Override
    public IBinder onBind(Intent arg0)
    {
        Log.e(TAG, "----onBind----");
        return stub;
    }

//這裡是處理邏輯的核心部分,就是實作了aidl中的interface中的接口函數
    private final AIDLSum.Stub stub = new AIDLSum.Stub()
    {

        @Override
        public double sum(double d1, double d2) throws RemoteException
        {
            return d1 + d2;
        }
    };

}
           
service 的四種使用場景與方法

以上就是service的四種使用場景。希望有所幫助

————————————–向死而生———————————

梅花香自苦寒來