分享

[z]android?service?使用以及aidl使用

 techres 2012-03-25

android service 使用以及aidl使用

(2011-05-08 10:50:53)
service

1:service的启动方式
service 是一个在后台运行的服务。你所启动的这个service所做得工作最好在另一个线程中做。因为这个service的线程的工作将阻塞调用它的线程。
创建和启动一个service有两种方式
Intent in = new Intent(***);
startService(in) 和 bindService(in)。
与上面相对应,停止一个service也有两种方式
stopService(in)  和 unbindService(in)。

如果是本地的service 则 Intent in = new Intent(this,LocalService.class)。同时那个service要在manifest文件中标明自己的name
<service android:name = ".serviceA"/>

如果是非本地的service 则在Intent中指明就可以了Intent in= new Intent("com.test.A") 与此同时那个非本地的service也要在manifest文件中申明自己的name和intent-filter
    <service android:name = ".serviceA">
            <intent-filter>
               <action android:name="com.test.A"/>
               <category android:name="android.intent.category.DEFAULT" />
           </intent-filter>
        </service>



2:使用startService 和 stopService
这种启动和停止方式是比较简单的。只需要在调用Activity中直接写上就可以了。

2.1service客户端代码
调用service的客户端的activity的代码:
package com.D_activity;

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 D_activity extends Activity {
    Button b;
    private boolean running =  false;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    //设置一个按钮来开启和关闭服务
        b=(Button)findViewById(R.id.button);
    }
    @Override
    protected void onResume() {
//指定一个Intent
       final Intent in = new Intent("com.test.A");
        super.onResume();
        b.setOnClickListener(new OnClickListener(){

            @Override
            public void onClick(View v) {
                if(running){
                    running = false;
        //关闭服务
                    stopService(in);
                    b.setText("start ");
                }
                else{
                    running = true;
        //开启服务
                   startService(in);
                    b.setText("stop");
                }
            }
            
        });
    }
}


2.2 被startService()调用的service 的代码:
通过startService启动的service在service的生命周期中将调用:onCreate()->onStartCommand()->onDestory()。
onCreate 仅仅在第一次创建这个service的时候调用。onStartCommand会在你使用startService()后调用。onDestory会在你使用stopSerivce的时候调用。

以下代码将实现一个每5秒打印系统时间的service,多半代码都是从文档中直接拿过来的。
package com.A_s;

import java.text.SimpleDateFormat;

import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
import android.os.Process;
import android.widget.Toast;

public class serviceA extends Service {

    private boolean flag =true;
    private Looper mServiceLooper;
    private ServiceHandler mServiceHandler;

    // Handler that receives messages from the thread
    private final class ServiceHandler extends Handler {
        public ServiceHandler(Looper looper) {
            super(looper);
        }
        @Override
        public void handleMessage(Message msg) {
            // Normally we would do some work here, like download a file.
            // For our sample, we just sleep for 5 seconds.
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            while(flag){
                synchronized (this) {
                      try {
                          Log.i("TEST","A  :"+sdf.format(System.currentTimeMillis()));
                          wait(5*1000);
                      } catch (InterruptedException e) {
                          e.printStackTrace();
                      }
                }
          }
            // Stop the service using the startId, so that we don't stop
            // the service in the middle of handling another job
            stopSelf(msg.arg1);
        }
    }

    @Override
    public void onCreate() {
      // Start up the thread running the service.  Note that we create a
      // separate thread because the service normally runs in the process's
      // main thread, which we don't want to block.  We also make it
      // background priority so CPU-intensive work will not disrupt our UI.
      HandlerThread thread = new HandlerThread("ServiceStartArguments",
              Process.THREAD_PRIORITY_BACKGROUND);
      thread.start();
      
      // Get the HandlerThread's Looper and use it for our Handler
      mServiceLooper = thread.getLooper();
      mServiceHandler = new ServiceHandler(mServiceLooper);
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();

        // For each start request, send a message to start a job and deliver the
        // start ID so we know which request we're stopping when we finish the job
        Message msg = mServiceHandler.obtainMessage();
        msg.arg1 = startId;
        mServiceHandler.sendMessage(msg);
        
        // If we get killed, after returning from here, restart
        return START_STICKY;
    }

    @Override
    public IBinder onBind(Intent intent) {
        // We don't provide binding, so return null
        return null;
    }
    
    @Override
    public void onDestroy() {
      Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show();
      flag =false;
    }
}


Manifest文件:
<service android:name = ".serviceA">
            <intent-filter>
               <action android:name="com.test.A"/>
               <category android:name="android.intent.category.DEFAULT" />
           </intent-filter>
        </service>



3:使用bindService和 unbindService
这种方式启动的service 生命周期中将调用:onCreate()->onBind()->onDestory()。
在service中与之前startService最不同的一点是,这次service不再使用onStartCommand而是使用onBind.所以这次service的代码与上面service的不同仅仅在于把onStartCommand的逻辑代码放到onBind中就可以了。
 @Override
    public IBinder onBind(Intent intent) {
        // We don't provide binding, so return null
        Toast.makeText(this, "service starting in onBind", Toast.LENGTH_SHORT).show();
        Message msg = mServiceHandler.obtainMessage();
        mServiceHandler.sendMessage(msg);

        return IBind;
    }




3.1使用bindService的客户端的代码如下

这次的Activity明显比之前使用startService的Activity多了一点东西,就是多了ServiceConnection类。当bindService完成时,系统会自动调用ServiceConnection中的onServiceConnected()
package com.C_activity;

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

public class C_activity extends Activity {
    Button b;
    private boolean running =  false;
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        b=(Button)findViewById(R.id.button);
       
    }
    @Override
    protected void onResume() {
       final Intent in = new Intent("com.test.E");
        super.onResume();
        b.setOnClickListener(new OnClickListener(){

            @Override
            public void onClick(View v) {
                if(running){
                    running = false;
                   unbindService(sc);
                    b.setText("start ");
                }
                else{
                    running = true;
//bindService方法的最后一个参数有其特定的意义,最好找文档确定自己需要哪种
                   bindService(in, sc, 1);
                    b.setText("stop");
                }
            }
            
        });
    }
    
    
    private ServiceConnection sc = new ServiceConnection(){

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
           
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {   
         
    };
    
}

4:利用aidl  远程调用service
当service 不是本地的服务,也就不能通过onServiceConnected中的IBinder来强制转换成相应服务类来使用service提供的一些方法。这时就需要使用aidl了。
直观的去看,远程服务如果能够被操作,也需要提供一个操作的接口,而这个接口不光在服务器端实现,同时在客户端也需要知道调用和使用的方式; 因此我们需要定义aidl文件来描述这么一个服务,也就是通过双方共享一个aidl文件的方式来共享一个接口。
在aidl里面定义了这个接口的内容之后, android的IDE帮助编译自动生成一个相应名字的java文件。这个java里面生成一个接口:test_aidl (extends android.os.IInterface) ,
 同时,最主要的,里面有个桩: public static abstract class Stub extends android.os.Binder implements test_aidl

比如我写了一个叫test_aidl.aidl的文件 内容如下:
package com.E_s;
 interface test_aidl{
    int getCount();
 }
那么在工程的gen目录下会自动生成一个test_aidl.java文件。然后在service中你就可以使用并实现这个接口中的方法。

 private final test_aidl.Stub IBind = new test_aidl.Stub()      
        @Override
        public int getCount() throws RemoteException {
            // TODO Auto-generated method stub
            return i;
        }
    };

4.1 使用aidl的service端的全部代码如下:
package com.E_s;

import java.text.SimpleDateFormat;

import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
import android.util.Log;
import android.os.Process;
import android.widget.Toast;

public class serviceA extends Service {
    
    private boolean flag =true;
    private Looper mServiceLooper;
    private ServiceHandler mServiceHandler;
    public static int i = 0;

    // Handler that receives messages from the thread
    private final class ServiceHandler extends Handler {
        public ServiceHandler(Looper looper) {
            super(looper);
        }
        @Override
        public void handleMessage(Message msg) {
            // Normally we would do some work here, like download a file.
            // For our sample, we just sleep for 5 seconds.
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            while(flag){
                synchronized (this) {
                      try {
                          i++;
                          Toast.makeText(serviceA.this, "E_s", Toast.LENGTH_SHORT).show();
                          Log.i("liyufei","E(A)  :"+sdf.format(System.currentTimeMillis()));
                          wait(5*1000);
                      } catch (InterruptedException e) {
                          // TODO Auto-generated catch block
                          e.printStackTrace();
                      }
                }
          }
            // Stop the service using the startId, so that we don't stop
            // the service in the middle of handling another job
//            stopSelf(msg.arg1);
        }
    }

    @Override
    public void onCreate() {
      // Start up the thread running the service.  Note that we create a
      // separate thread because the service normally runs in the process's
      // main thread, which we don't want to block.  We also make it
      // background priority so CPU-intensive work will not disrupt our UI.
      HandlerThread thread = new HandlerThread("ServiceStartArguments",
              Process.THREAD_PRIORITY_BACKGROUND);
      thread.start();
      
      // Get the HandlerThread's Looper and use it for our Handler
      mServiceLooper = thread.getLooper();
      mServiceHandler = new ServiceHandler(mServiceLooper);
    }

    @Override
    public IBinder onBind(Intent intent) {
        Toast.makeText(this, "service starting in onBind", Toast.LENGTH_SHORT).show();

        Message msg = mServiceHandler.obtainMessage();
        mServiceHandler.sendMessage(msg);

        return IBind;
    }
    
    private final test_aidl.Stub IBind = new test_aidl.Stub() {
        
        @Override
        public int getCount() throws RemoteException {
            return i;
        }
    };
    
    @Override
    public void onDestroy() {
      Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show();
      flag =false;
    }
}


在客户端,你首先要在客户端的工程中也创建相应的包名和aidl文件。比如将文中的test_aidl.aidl也放入客户端的com.E_s包中。然后客户端中也会自动生成一个test_aidl.java文件
然后就只需要将之前的使用bindService的客户端代码中的ServiceConnection方法中添加些东西就好了。
    test_aidl testAidl;

   private ServiceConnection sc = new ServiceConnection(){
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            testAidl = test_aidl.Stub.asInterface(service);
        }
        @Override
        public void onServiceDisconnected(Com

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多