与Service交互的三种方式

  • 1)start的方式与Service交互

    Activity是不能很直接的与Service进行交互,需要借助与其它组件来完成。常见的就是利用广播接收器。Service发送广播,Activity接受广播。
    
  • 2)bind的方式与Service交互

    需要在Service中准备一个IBinder接口的实现类。将该实现类的对象作为onBind方法的返回值
    

    在Activity中需要一个ServiceConnection对象,他会有两个回调方法,在其中一个方法中获得Service内onBind方法返回的IBinder对象。通过IB顶的人来实现与Service的交互。

  • 3)AIDL的方式与Service交互(不常用)

    Bind方式进行交互是有前提的,Activity和Service是出于同一个app中(同一个进程中)
    

通过AIDL可以实现跨进程的调用,一个APPA的Activity可以调用另一个APP的Service的方法
进行AIDL跨进程调用调用,必须使用Service的一个.aidl描述文件才可以进行


举例

  1. start的方式与Service交互
    XML代码:

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="xxxx" 
        android:textSize="30sp"
        android:background="#ffff0000"/>

    <Button
        android:id="@+id/button1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@+id/textView1"
        android:text="Start" 
        android:onClick="start"/>

    <Button
        android:id="@+id/button2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@+id/button1"
        android:layout_marginTop="17dp"
        android:text="Stop" 
 android:onClick="stop"/>`

Service代码:
初始化Handler handler = new Handler();//用于以秒为单位更新时间
在Service中重写onCreate和onDestroy方法
onCreate()中启动服务
onDestroy()中移除Handler;//Handler很强大,即使Service停止了,它任然在执行,所以要移除

package com.example.test01;

import java.text.SimpleDateFormat;

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

public class MyService extends Service {
    Handler handler = new Handler();
    public MyService() {
    }


    @Override
    public void onCreate() {
        Log.d("TAG", "服务创建");
        super.onCreate();
        handler.postDelayed(new Runnable() {
            /**
             * 当onCreate()执行,1秒后执行Runnable(),
             * intent发送getServiceTime()的返回值,发送广播
             */
            @Override
            public void run() {
                // TODO 发送广播,吧getServiveTime方法结果广播出去
                Intent intent = new Intent("service_start");//随便写只要不重名
                intent.putExtra("time", getServiceTime());
                sendBroadcast(intent);
                handler.postDelayed(this, 1000);//为了不让服务只更新一次而设置一个循环
            }
        }, 1000);//一秒更新一次
    }

    @Override
    public void onDestroy() {
        Log.d("TAG", "服务被销毁");
        handler.removeCallbacksAndMessages(null);//点击结束Servier,然而handler还在工作
        super.onDestroy();
    }

    public String getServiceTime(){
        SimpleDateFormat sdf = new SimpleDateFormat("mm:ss");//设置要得到系统的分秒
        return sdf.format(System.currentTimeMillis());
    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        throw new UnsupportedOperationException("Not yet implemented");
    }
}

Activity代码:
onResume()中使用过滤器得到Service发送的广播并注册广播接收器,
onPause()中注销广播接收器

package com.example.test01;

import android.os.Bundle;
import android.os.Handler;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.view.Menu;
import android.view.View;
import android.widget.TextView;

public class MainActivity extends Activity {
    TextView tvTime;
    MyReceiver receiver;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tvTime = (TextView) findViewById(R.id.textView1);
    }

    @Override
    protected void onResume() {
        super.onResume();
        receiver = new MyReceiver();
        IntentFilter filter = new IntentFilter();
        filter.addAction("service_start");//从系统底层获得这条广播
        registerReceiver(receiver, filter);//注册广播接收器
    }

    @Override
    protected void onPause() {
        super.onPause();
        unregisterReceiver(receiver);//退出时注销广播接收器
    }

    /**启动服务**/
    public void start(View v){//按钮的点击属性,启动服务
        Intent intent = new Intent(this,MyService.class);
        startService(intent);
    }
    /**关闭服务**/
    public void stop(View v){//按钮的点击属性,停止服务
        Intent intent = new Intent(this,MyService.class);
        stopService(intent);
    }


    /**广播接收类*/
    public class MyReceiver extends BroadcastReceiver{

        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();//得到Service发送的广播
            if("service_start".equals(action)){
                //从intent中,包“时间”取出来,放到tvTime中显示
                String time = intent.getStringExtra("time");
                tvTime.setText(time);
            }
        }

    }
}

效果图:
与Service交互的三种方式_第1张图片


2.bind的方式与Service交互
绑定方式的xml根启动模式的xml差别不大,把按钮从启动改为绑定(bind),停止改为解绑(unbind)

 Service代码:
package com.example.servicedemo;

import java.text.SimpleDateFormat;

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

public class MyService extends Service {
    Handler handler = new Handler();
    public MyService() {
    }

    @Override
    public void onCreate() {
        Log.d("TAG", "服务创建");
        super.onCreate();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d("TAG", "服务启动");
        return super.onStartCommand(intent, flags, startId);//返回的是Service的一种类型
    }

    @Override
    public void onDestroy() {
        Log.d("TAG", "服务被销毁");
        handler.removeCallbacksAndMessages(null);//点击结束Servier,然而handler还在工作
        super.onDestroy();
    }


    /**
     * 提供当前时间
     * @return
     */
    public String getServiceTime(){
        SimpleDateFormat sdf = new SimpleDateFormat("mm:ss");
        return sdf.format(System.currentTimeMillis());
    }

    @Override
    public IBinder onBind(Intent intent) {
        return new MyBinder();
    }

    public class MyBinder extends Binder{
        public String getTime(){
            return getServiceTime();
        }
    }
}

Activity代码:

package com.example.servicedemo;

import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.view.View;
import android.widget.TextView;

import com.example.servicedemo.MyService.MyBinder;

public class MainActivity extends Activity {
    TextView tvTime;

    /***Bind方式***/
    ServiceConnection conn;
    MyBinder binder;
    Handler handler;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tvTime = (TextView) findViewById(R.id.textView1);
        handler = new Handler();

        conn = new ServiceConnection() {

            @Override
            public void onServiceDisconnected(ComponentName name) {
                // TODO Auto-generated method stub

            }

            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                binder = (MyBinder) service;
                handler.postDelayed(new Runnable() {

                    @Override
                    public void run() {
                        tvTime.setText(binder.getTime());
                        handler.postDelayed(this, 1000);
                    }
                }, 1000);
            }
        };
    }

    public void bind(View v){
        Intent intent = new Intent(this,MyService.class);
        bindService(intent, conn, Context.BIND_AUTO_CREATE);
    }
    public void unbind(View v){
        unbindService(conn);
        handler.removeCallbacksAndMessages(null);
    }
}

3.AIDL的方式与Service交互
这是一种跨进程的交互方式一个APP的Activity可以调用另一个App中Service的方法
创建两个app,一个叫服务提供方,一个服务提供方

*两个app中都必须有一个相同名字的包,包里必须要有一个一样的aidl文件
*必须是服务提供方先启动,服务提供方才能使用提供方的服务

先创建服务提供方xml布局都一样,就不说了,提供方的
包名:com.example.serviceprovider(使用方也要创建一个这样的包名)
不要忘了包下的aidl文件,
与Service交互的三种方式_第2张图片

与Service交互的三种方式_第3张图片

提供方->MyBinder代码:
我怕写错,所以代码是我创建一个接口,然后删除“public”后,复制黏贴过来的,最后把接口删出就好

package com.example.serviceprovider;

interface MyBinder {
    String getTime();
}

提供方->Service代码:

package com.example.serviceprovider;

import java.text.SimpleDateFormat;
import java.util.Date;

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

public class MyService extends Service {
    public MyService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        return new MyBinderImpl();
    }

    public String getServiceTime(){
        SimpleDateFormat sdf = new SimpleDateFormat("mm:ss");
        return sdf.format(new Date());
    }

    public class MyBinderImpl extends MyBinder.Stub{

        @Override
        public String getTime() throws RemoteException {
            // TODO Auto-generated method stub
            return getServiceTime();
        }

    }
}

提供方->Activity代码:(这代码并没有什么卵用)

package com.example.serviceprovider;

import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;

public class MainActivity extends Activity {

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

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

}

使用方的aidl文件是复制过来的,新建一个包含它的包

使用方->Activity代码:

package com.exampleserviceuser;

import com.example.serviceprovider.MyBinder;

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.Handler;
import android.os.IBinder;
import android.os.RemoteException;
import android.view.View;
import android.widget.TextView;
/**
 * 复制aidl文件,包名一样
 * @author Android
 *
 */

public class MainActivity extends Activity {
    TextView tvTime;

    Handler handler;

    ServiceConnection conn;

    MyBinder binder;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tvTime = (TextView) findViewById(R.id.textView1);
        handler = new Handler();
        conn = new ServiceConnection() {

            @Override
            public void onServiceDisconnected(ComponentName name) {
                // TODO Auto-generated method stub

            }

            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
//不能强转,Stub是交给系统处理的
                binder = MyBinder.Stub.asInterface(service);
                handler.postDelayed(new Runnable() {

                    @Override
                    public void run() {
                        try {
                            tvTime.setText(binder.getTime());
                            handler.postDelayed(this, 1000);
                        } catch (RemoteException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                    }
                }, 1000);
            }
        };
    }

    public void bind(View v){
        //通过隐式意图启动远程Sercice
        Intent intent = new Intent("com.tarena.REMOTE_TIME_SERVICE");
        bindService(intent, conn, Context.BIND_AUTO_CREATE);
    }
    public void unbind(View v){
        unbindService(conn);
        handler.removeCallbacksAndMessages(null);
    }
}

源码下载:Service的三种简单交互方式

你可能感兴趣的:(学习笔记,Android)