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

推荐阅读更多精彩内容