Android 开启Service两种方式及Activity与Service间进行消息传递

Service

Android开发者文档里这样定义:
A service is a component that runs in the background to perform long-running operations or to perform work for remote processes. A service does not provide a user interface. For example, a service might play music in the background while the user is in a different app, or it might fetch data over the network without blocking user interaction with an activity.Another component, such as an activity, can start the service and let it run or bind to it in order to interact with it.

Service是Android提供的四大组件之一,我们可以认为它是一个没有用户界面、开发者创建的组件,它可以用来执行长久的操作,可以超出单个Activity的范围。Service可以作为客户端/服务器开发模式的服务器,通过进程间通信(IPC)提供远程调用服务。
如果一个任务需要使用worker线程,可能会影响应用的响应速度和性能,而这个任务对处理时间并不敏感,那就考虑使用Service,在主要应用程序和任何单独的Activity生命周期外处理任务。

常见应用

  • 天气、电子邮件或者社交网络的App,可以定期检查网络上更新的服务。
  • 一个游戏,可以在用户需要的时候创建一个Service下载并处理相关内容。
  • 一个照片或者多媒体应用保持数据的在线同步。
  • 一个视频编辑软件,可以将繁重的处理工作放置在服务队列,降低系统能耗。
  • 一个新闻应用,可以实现预加载内容的服务,当用户启动时,提前下载相应新闻,提高性能和相应能力。

开启Service的两种方式:

  1. startService(Intent serviceIntent) 一个组件可以通过startService的方式来开启Service服务。这种方式开启的Service可以调用stopSelf()来停止服务,也可以通过在其他组件中调用stopService()方法来停止。
Intent serviceIntent = new Intent(this, FirstStartedService.class);
  startService(serviceIntent);

FirstStartedService就是开启的继承自Service的服务。

public class FirstStartedService extends Service {
    private CustomHanlder ch;
    public FirstStartedService() {

    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.w("service created:","flag");
        HandlerThread ht=new HandlerThread("handler.thread.name");
        ht.start();
        ch=new CustomHanlder(ht.getLooper());
    }

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

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.w("service started:","flag");
        Log.w("main thread id:",""+Thread.currentThread().getName()+Thread.currentThread().getId());
        //do service task;
        //stopSelf();
        ch.sendEmptyMessage(0);
        return Service.START_STICKY;
    }

    private class CustomHanlder extends Handler{
        public CustomHanlder(Looper looper) {
            super(looper);
        }
        @Override
        public void handleMessage(Message msg) {
            Log.w("handler thread id:",""+Thread.currentThread().getName()+Thread.currentThread().getId());
        }
    }
}

2.bindService(Intent service ,ServiceConnection conn ,Int flags) 参数service是指要绑定的Service,conn是ServiceConnection对象,这个对象不能为null,flags为binding的类型,可以为0。 这种方式开启的Service会一直运行,直到没有组件绑定这个Service的时候系统才会停止Service。一般情况下,一个组件在不需要Service服务后要调用unBindService(ServiceConnection conn)来解绑Service。
一个简单示例:Activity作为客户端使用bindService的方式开启一个Service服务,并向服务端发送一个字符串,服务端接收字符串后向客户端返回一个字符串。这也是一个简单的进程间通信(IPC)的例子

客户端代码:

public class ServiceTestScreen extends AppCompatActivity {

    private TextView tv;

    public ServiceTestScreen() {
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_service_test_screen);
        tv = (TextView) findViewById(R.id.reply_text);
    }

    public void onClickButton(View v) {
        int id = v.getId();
        switch (id) {
            case R.id.start_service: {
                Intent serviceIntent = new Intent(this, FirstStartedService.class);
                startService(serviceIntent);
                break;
            }
            case R.id.bind_service: {
                Intent serviceIntent = new Intent(this, FirstBinderService.class);
                bindService(serviceIntent, serviceConnection, Context.BIND_AUTO_CREATE);
                break;
            }
            case R.id.start_intent_service: {
                Intent serviceIntent = new Intent(this, FirstIntentService.class);
                startService(serviceIntent);
                break;
            }
            case R.id.send_msg: {
                if (serviceBound) {
                    if (serverMsger != null) {
                        Message msg = new Message();
                        Bundle data = new Bundle();
                        data.putString("send", "client msg");
                        msg.setData(data);
                        msg.replyTo = clientMsger;
                        try {
                            serverMsger.send(msg);
                        } catch (RemoteException e) {
                            e.printStackTrace();
                        }
                    }
                }
                break;
            }
        }
    }

    private boolean serviceBound = false;
    private Messenger serverMsger;
    private ServiceConnection serviceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder binder) {
            Log.w("component name:", name.getClassName());
            serverMsger = new Messenger(binder);
            serviceBound = true;
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            serverMsger = null;
            serviceBound = false;
        }
    };
    private Handler h = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            tv.setText(msg.getData().getString("reply"));
        }
    };

    private Messenger clientMsger = new Messenger(h);

    @Override
    protected void onStop() {
        super.onStop();
        if (serviceBound) {
            unbindService(serviceConnection);
            serviceBound = false;
            serverMsger = null;
        }
    }
}

服务端代码:

public class FirstBinderService extends Service {

    private final Messenger serverMsger = new Messenger(new MessageHandler());

    public FirstBinderService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        return serverMsger.getBinder();
    }

    private class MessageHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            Message replyMsg = new Message();
            Bundle data = new Bundle();
            data.putString("reply", msg.getData().getString("send") + "--server msg");
            replyMsg.setData(data);
            try {
                msg.replyTo.send(replyMsg);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
    }

}

示例效果图:


Activity获取Service的返回字符串
Activity获取Service的返回字符串

总结

本文主要总结了Android中启动Service的两种方式,并用了具体示例来进行演示,完成了使用bindService的方式进行进程间通信。如果总结的有错误或不足的地方,欢迎大家批评指正。
示例代码
个人主页
GitHub

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

推荐阅读更多精彩内容