Android中Service与多个Activity通信的三种方式

由于项目需要,我们有时候需要在service中处理耗时操作,然后将结果发送给activity以更新状态。通常情况下,我们只需要在一个service与一个activity之间通信,通常这种情况下,我们使用最多的是通过回调接口。具体做法是在service中定义一个接口,在activity中实现该接口,并通过bindservice来传入。实现方式很简单,在此不再赘述。
当需要将service中的结果一次发送给多个activity时,我们又该如何实现呢?经过多个项目的积累,总结了三种实现的方式。分别是回调接口、广播接收者和观察者模式。

1. 回调接口的方式

与单个service与单个activity通信类似,只是将service中的接口变为接口的集合,每个需要通信的activity都实现接口,然后在获取结果后,循环调用集合中的实现类,来与多个activity进行通信,代码如下:

1.1 Service类:

package com.example.servicecallback;

import java.util.ArrayList;
import java.util.List;

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

public class ContentService extends Service {

    //回调接口的集合
    private List<Callback> list;

    @Override
    public IBinder onBind(Intent arg0) {
        // TODO Auto-generated method stub
        return new LocalBinder();
    }

    @Override
    public void onCreate() {
        // TODO Auto-generated method stub
        super.onCreate();
        list = new ArrayList<Callback>();
    }

    public final class LocalBinder extends Binder {
        public ContentService getService() {
            return ContentService.this;
        }
    }

    /**
     * 回调接口
     * @author Ivan Xu
     *
     */
    public interface Callback {
        public void getPerson(Person person);
    }

    /**
     * 往回调接口集合中添加一个实现类
     * @param callback
     */
    public void addCallback(Callback callback) {
        list.add(callback);
    }

    public void asyncSendPerson(final String name) {
        // 休息5秒,模拟异步任务
        new Thread(new Runnable() {
            @Override
            public void run() {
                // TODO Auto-generated method stub
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                handler.sendMessage(handler.obtainMessage(0, name));
            }
        }).start();
    }

    private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            // TODO Auto-generated method stub
            String name = (String) msg.obj;
            Log.i("ContentService", "---name-->" + name);
            Person person = new Person();
            person.setName(name);
            Log.i("ContentService", "---list.size()-->" + list.size());
            Log.i("ContentService", "---person-->" + person.toString());
            //遍历集合,通知所有的实现类,即activity
            for (int i = 0; i < list.size(); i++) {
                list.get(i).getPerson(person);
            }
        }
    };
}

1.2 第一个activity:

package com.example.servicecallback;

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.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.TextView;
import com.example.servicecallback.ContentService.Callback;
import com.example.servicecallback.ContentService.LocalBinder;

public class MainActivity extends Activity implements Callback {

    private MyServiceConn conn;
    private ContentService service;
    private TextView mContent;

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

        conn=new MyServiceConn();
        bindService(new Intent(this, ContentService.class), conn,
                BIND_AUTO_CREATE);

        mContent = (TextView) findViewById(R.id.content);

        this.findViewById(R.id.button1).setOnClickListener(
                new OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        // TODO Auto-generated method stub
                        startActivity(new Intent(MainActivity.this,
                                OtherActivity.class));
                    }
                });
    }

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

    public class MyServiceConn implements ServiceConnection {

        @Override
        public void onServiceConnected(ComponentName name, IBinder binder) {
            service = ((LocalBinder) binder).getService();
            //将当前activity添加到接口集合中
            service.addCallback(MainActivity.this);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            // TODO Auto-generated method stub
            service = null;
        }
    }

    @Override
    protected void onDestroy() {
        // TODO Auto-generated method stub
        super.onDestroy();
        unbindService(conn);
    }

    /**
     * 获取回调的内容,更新UI
     */
    @Override
    public void getPerson(Person person) {
        // TODO Auto-generated method stub
        mContent.setText(person.toString());
    }
}

1.3 第二个activity:

package com.example.servicecallback;

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;
import android.widget.EditText;
import android.widget.TextView;
import com.example.servicecallback.ContentService.Callback;
import com.example.servicecallback.ContentService.LocalBinder;
import com.example.servicecallback.MainActivity.MyServiceConn;

public class OtherActivity extends Activity implements Callback {

    private ContentService service;
    private TextView mContent;
    private Button mSubmit;
    private EditText mEditText;
    private ServiceConnection conn;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);

        setContentView(R.layout.other);

        mEditText = (EditText) findViewById(R.id.edittext);
        mSubmit = (Button) findViewById(R.id.button1);
        mContent = (TextView) findViewById(R.id.content);

        mSubmit.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                String name = mEditText.getText().toString();
                service.asyncSendPerson(name);
            }
        });

        
        conn=new MyServiceConn();
        bindService(new Intent(OtherActivity.this, ContentService.class), conn,
                BIND_AUTO_CREATE);

    }

    public final class MyServiceConn implements ServiceConnection {
        @Override
        public void onServiceConnected(ComponentName name, IBinder binder) {
            // TODO Auto-generated method stub
            service = ((LocalBinder) binder).getService();
            //将当前activity添加到接口集合中
            service.addCallback(OtherActivity.this);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            // TODO Auto-generated method stub
            service = null;
        }
    }

    @Override
    protected void onDestroy() {
        // TODO Auto-generated method stub
        super.onDestroy();
        unbindService(conn);
    }

    /**
     * 获取回调的内容,更新UI
     */
    @Override
    public void getPerson(Person person) {
        // TODO Auto-generated method stub
        mContent.setText(person.toString());
    }
}

2 通过广播(==推荐==)

在service中执行完耗时操作后,将结果以广播的形式发送,在所有的activity中注册广播,接收到结果后更新UI,这种方式比较简单,也是笔者比较推荐的方式。因为耗时的操作结果不需要以handler的方式发送到主线程,可以直接在子线程中发送广播,接收者始终运行在主线程中。代码如下:

2.1 Service类:

package com.example.servicecallback;

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

public class ContentService extends Service {


    @Override
    public IBinder onBind(Intent arg0) {
        // TODO Auto-generated method stub
        return new LocalBinder();
    }

    @Override
    public void onCreate() {
        // TODO Auto-generated method stub
        super.onCreate();
    }

    public final class LocalBinder extends Binder {
        public ContentService getService() {
            return ContentService.this;
        }
    }

    public void asyncSendPerson(final String name) {
        // 休息5秒,模拟异步任务
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //可以在子线程中直接发送广播
                sendContentBroadcast(name);
            }
        }).start();
    }

    /**
     * 发送广播
     * @param name
     */
    protected void sendContentBroadcast(String name) {
        // TODO Auto-generated method stub
        Intent intent=new Intent();
        intent.setAction("com.example.servicecallback.content");
        intent.putExtra("name", name);
        sendBroadcast(intent);
    }
}

2.2 第一个activity:

package com.example.servicecallback;

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.IBinder;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.TextView;

public class MainActivity extends Activity {

    private MyServiceConn conn;
    private TextView mContent;
    private ContentReceiver mReceiver;

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

        conn = new MyServiceConn();
        bindService(new Intent(this, ContentService.class), conn,
                BIND_AUTO_CREATE);

        mContent = (TextView) findViewById(R.id.content);

        this.findViewById(R.id.button1).setOnClickListener(
                new OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        // TODO Auto-generated method stub
                        startActivity(new Intent(MainActivity.this,
                                OtherActivity.class));
                    }
                });

        
        doRegisterReceiver();
    }

    /**
     * 注册广播接收者
     */
    private void doRegisterReceiver() {
        mReceiver=new ContentReceiver();
        IntentFilter filter = new IntentFilter(
                "com.example.servicecallback.content");
        registerReceiver(mReceiver, filter);
    }

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

    public class MyServiceConn implements ServiceConnection {

        @Override
        public void onServiceConnected(ComponentName name, IBinder binder) {
            // service = ((LocalBinder) binder).getService();
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            // TODO Auto-generated method stub
            // service = null;
        }
    }

    @Override
    protected void onDestroy() {
        // TODO Auto-generated method stub
        super.onDestroy();
        unbindService(conn);
        if (mReceiver!=null) {
            unregisterReceiver(mReceiver);
        }
    }

    public class ContentReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            String name = intent.getStringExtra("name");
            Person person = new Person();
            person.setName(name);
            mContent.setText(person.toString());
        }
    }
}

2.3 第二个activity:

package com.example.servicecallback;

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.IBinder;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

import com.example.servicecallback.ContentService.LocalBinder;

public class OtherActivity extends Activity {

    private ContentService service;
    private TextView mContent;
    private Button mSubmit;
    private EditText mEditText;
    private ServiceConnection conn;
    private ContentReceiver mReceiver;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.other);

        mEditText = (EditText) findViewById(R.id.edittext);
        mSubmit = (Button) findViewById(R.id.button1);
        mContent = (TextView) findViewById(R.id.content);

        mSubmit.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                String name = mEditText.getText().toString();
                service.asyncSendPerson(name);
            }
        });

        
        conn=new MyServiceConn();
        bindService(new Intent(OtherActivity.this, ContentService.class), conn,
                BIND_AUTO_CREATE);

        doRegisterReceiver();
    }

    private void doRegisterReceiver() {
        mReceiver=new ContentReceiver();
        IntentFilter filter = new IntentFilter(
                "com.example.servicecallback.content");
        registerReceiver(mReceiver, filter);
    }
    
    public final class MyServiceConn implements ServiceConnection {
        @Override
        public void onServiceConnected(ComponentName name, IBinder binder) {
            service = ((LocalBinder) binder).getService();
        }

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

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unbindService(conn);
        if (mReceiver!=null) {
            unregisterReceiver(mReceiver);
        }
    }

    public class ContentReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            String name = intent.getStringExtra("name");
            Person person = new Person();
            person.setName(name);
            mContent.setText(person.toString());
        }
    }
}

3 使用观察者模式

service为被观察者,所有的activity为观察者,当service中的内容发生改变时,通知所有的activity来更新,代码如下:

3.1 Service类:

package com.example.servicecallback;

import java.util.Observable;
import java.util.Observer;

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

public class ContentService extends Service {

    //被观察者
    private MyObservable mObservable;

    @Override
    public IBinder onBind(Intent arg0) {
        return new LocalBinder();
    }

    @Override
    public void onCreate() {
        super.onCreate();
        mObservable = new MyObservable();
    }

    public final class LocalBinder extends Binder {
        public ContentService getService() {
            return ContentService.this;
        }
    }

    public void asyncSendPerson(final String name) {
        // 休息5秒,模拟异步任务
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                handler.sendMessage(handler.obtainMessage(0, name));
            }
        }).start();
    }

    /**
     * 添加观察者
     * @param observer
     */
    public void addObserver(Observer observer) {
        mObservable.addObserver(observer);
    }

    private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            String name = (String) msg.obj;
            Person person = new Person();
            person.setName(name);
            //通知更新
            mObservable.notifyChanged(person);
        }
    };

    public class MyObservable extends Observable {
        
        public void notifyChanged(Object object) {
            this.setChanged();
            this.notifyObservers(object);
        }
    }
}

3.2 第一个activity:

package com.example.servicecallback;

import java.util.Observable;
import java.util.Observer;
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.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.TextView;

import com.example.servicecallback.ContentService.LocalBinder;

public class MainActivity extends Activity implements Observer {

    private MyServiceConn conn;
    private TextView mContent;
    private ContentService mService;

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

        conn = new MyServiceConn();
        bindService(new Intent(this, ContentService.class), conn,
                BIND_AUTO_CREATE);

        mContent = (TextView) findViewById(R.id.content);

        this.findViewById(R.id.button1).setOnClickListener(
                new OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        startActivity(new Intent(MainActivity.this,
                                OtherActivity.class));
                    }
                });
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    public class MyServiceConn implements ServiceConnection {

        @Override
        public void onServiceConnected(ComponentName name, IBinder binder) {
            mService = ((LocalBinder) binder).getService();
            //将当前activity添加为观察者
            mService.addObserver(MainActivity.this);
        }

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

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

    //更新UI
    @Override
    public void update(Observable observable, Object data) {
        Person person = (Person) data;
        mContent.setText(person.toString());
    }

}

3.2 第二个activity:

package com.example.servicecallback;

import java.util.Observable;
import java.util.Observer;

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

import com.example.servicecallback.ContentService.LocalBinder;

public class OtherActivity extends Activity implements Observer {

    private ContentService service;
    private TextView mContent;
    private Button mSubmit;
    private EditText mEditText;
    private ServiceConnection conn;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.other);

        mEditText = (EditText) findViewById(R.id.edittext);
        mSubmit = (Button) findViewById(R.id.button1);
        mContent = (TextView) findViewById(R.id.content);

        mSubmit.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                String name = mEditText.getText().toString();
                service.asyncSendPerson(name);
            }
        });

        conn = new MyServiceConn();
        bindService(new Intent(OtherActivity.this, ContentService.class), conn,
                BIND_AUTO_CREATE);

    }

    public final class MyServiceConn implements ServiceConnection {
        @Override
        public void onServiceConnected(ComponentName name, IBinder binder) {
            service = ((LocalBinder) binder).getService();
            //将当前activity添加为观察者
            service.addObserver(OtherActivity.this);
        }

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

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

    //更新UI
    @Override
    public void update(Observable observable, Object data) {
        // TODO Auto-generated method stub
        Person person=(Person) data;
        
        mContent.setText(person.toString());
    }
}

附上其他相关代码,三种方式都一样:

Person类:

package com.example.servicecallback;

public class Person {

    private String name;

    public String getName() {
        return name;
    }

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

    @Override
    public String toString() {
        return "Person [name=" + name + "]";
    }

}

MainActiivty的布局文件:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >

    <Button
        android:id="@+id/button1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="next" />

    <TextView
        android:id="@+id/content"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/hello_world" />

</LinearLayout>

OtherActivity的布局文件:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <EditText
        android:id="@+id/edittext"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <Button
        android:id="@+id/button1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="submit" />

    <TextView
        android:id="@+id/content"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="content" />

</LinearLayout>
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,378评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,356评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,702评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,259评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,263评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,036评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,349评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,979评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,469评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,938评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,059评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,703评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,257评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,262评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,485评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,501评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,792评论 2 345

推荐阅读更多精彩内容