Android_08_服务的使用总结

来源:互联网 发布:nmath 非线性优化 编辑:程序博客网 时间:2024/06/05 03:53

前言:

服务是应用程序的一个组件,一般用在不与用户交互情况下去执行一个较长时间运行的操作或者是提供功能为其他应用所使用;

每一个Service类必须在AndroidManifest.xml下进行<service>的声明;服务可以通过Context.startService()或者Context.bindService()

来启动;

需要知道一点的就是:服务,像其他应用程序对象一样,在宿主进程的主线程中运行。这意味着如果你的服务将要去做一些CPU密集型

或者阻塞的操作,那么应该放在它自己创建的线程中去做这些事;


服务实际上是很简单的,它给出了两个主要的特性:

1>

一种是为了告诉系统,有些东西,甚至有时根本不与用户交互的一些东西,它希望能够运行于后台;相应地,它会去调用Context.startService();

它会要求系统去调度和运行这个服务,直至这个服务自己停止或者用户将其停止为止;

2>

另一种是为了给其他应用提供一些功能;相应地,会去调用Context.bindService(),为了能够和服务进行一个交互,这个方法会与服务建立一个

长期的连接;


服务的生命周期:

一个服务可以由系统运行有两个方面;如果某人调用了Context.startService(),然后系统就会得到这个Service(通过onCreate()方法),

然后调用onStartCommand(Intent, int, int)方法,这个时候,服务依旧会继续运行,直到调用了Context.stopService()或者stopSelf()方法;

需要知道一点的就是:多次调用Context.startService(),不会导致这个服务的多次开启(尽管这会多次地去响应onStartCommand()),无论

开启服务多少次,一旦调用Context.stopService() or stopSelf(),这个服务就会被停止掉;然而,服务可以使用stopSelf(int)方法去确保服务

不会被停止,直到开启的intent已经被处理了为止;


对于已经开启的服务,这有两种操作模式可供它们去选择运行,主要依赖于通过onStartCommand()返回的这个值;

START_STICKY用来显示启动和停止服务,然后START_NOT_STICKY或者START_REDELIVER_INTENT被用来

在处理命令的时候,它们依旧能够保持运行状态;


客户端也可以使用Context.bindService()去获得与服务的一个长久的连接;这同样也导致一个服务的创建,如果之前这个

服务创建的话,但是它不会再去调用onStartCommand()方法;客户端将会收到一个IBinder对象,服务也将会从IBinder

对象的onBind(Intent)方法中去返回回去,然后允许客户端去回调这个服务;只要连接依旧处于建立的状态,那么这个

服务就依旧会处于运行之中(无论客户端是否保留了这个服务的IBinder的引用);通常IBinder返回的是一个复杂的接口,

这个接口已经被写进aidl之中了;


一个服务在被开启的同时,且允许有连接与这个服务绑定;在这种情况下,只要满足这个服务被开启的条件或者满足

有一个或多个连接还与这个服务绑定在一起,那么系统依旧会让服务处于运行的状态,如果这两个条件都不满足,那么,

就会调用服务的onDestroy()方法来终止这个服务的运行;所有的清理工作都应该在onDestroy()里边进行;



方式一:Context.startService()

代码示例如下:

MainActivity:

package com.example.administrator.teststartservice;import android.content.Intent;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.util.Log;import android.view.View;public class MainActivity extends AppCompatActivity {    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);    }    /**     * 开启服务     * **/    public void startService(View view){        Log.e("MainActivity","startService");        Intent intent = new Intent(this,MyService.class);        startService(intent);    }    /**     * 关闭服务     * **/    public void stopService(View view){        Log.e("MainActivity","stopService");        Intent intent = new Intent(this,MyService.class);        stopService(intent);    }}

MyService.java

package com.example.administrator.teststartservice;import android.app.Service;import android.content.Intent;import android.os.IBinder;import android.util.Log;public class MyService extends Service {    public MyService() {    }    @Override    public IBinder onBind(Intent intent) {        // TODO: Return the communication channel to the service.        throw new UnsupportedOperationException("Not yet implemented");    }    @Override    public void onCreate() {        Log.e("MyService","onCreate");    }    @Override    public int onStartCommand(Intent intent, int flags, int startId) {        Log.e("MyService","onStartCommand");        return super.onStartCommand(intent, flags, startId);    }    @Override    public void onDestroy() {        Log.e("MyService","onDestroy");    }}


activity_main.xml:

<?xml version="1.0" encoding="utf-8"?><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: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="com.example.administrator.teststartservice.MainActivity">    <Button        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="开启服务"        android:onClick="startService"        />    <Button        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="关闭服务"        android:onClick="stopService"        /></LinearLayout>

运行结果如下:

一次开启,一次关闭:

多次开启,一次关闭:

从上面对的运行结果可以看出:

onCreate()  ----->   onStartCommand()  ----->  onDestroy()

当服务开启后,不会再开启服务,同一个服务只会开启一次,

此时,onCreate() 不会再次调用,但是 onStartCommand()可以被多次调用

在关闭服务时,就会调用onDestroy()方法;

注:

当系统的内存不足时,系统会按照进程的优先级,将服务关闭,直至内存够用,

所以说服务在一般情况下是很难被系统杀死的,若是被系统杀死了,当内存充足时,

其会自动开启;若是用户手动关闭服务,那么在内存充足时,也不会被系统开启,

除非用户自己手动去开启服务;


方式二:Context.bindService()

代码示例如下:

MainActivity.java

package com.example.administrator.testbindservice;import android.content.ComponentName;import android.content.Intent;import android.content.ServiceConnection;import android.os.IBinder;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.util.Log;import android.view.View;/** * 本示例的作用是实现在Activity里边去调用服务里边的方法, * 这样做的原因是因为Service我们是直接拿不到的,这个是系统 * 帮我们创建的,所以我们也就没办法直接访问Service里边的方法, * 此时我们可以通过bindService()来实现去调用服务里边的方法; * **/public class MainActivity extends AppCompatActivity {    private LeaderService.Medium medium;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        /**         * 确定连接哪个服务         * **/        Intent intent = new Intent(this,LeaderService.class);        /**         * 绑定服务         * 主要是为了获取服务里边的某项功能,供我们所用         * **/        bindService(intent,new MyServiceConnection(),BIND_AUTO_CREATE);        Log.e("onCreate","bindService");    }    private class MyServiceConnection implements ServiceConnection{        /***         * 当与这个服务建立连接时,这个方法会调用,         * 其中,其参数 IBinder service 是在         * ServiceonBind()方法调用的时候返回回来的;         * **/        @Override        public void onServiceConnected(ComponentName name, IBinder service) {            medium = (LeaderService.Medium) service;            Log.e("MyServiceConnection","onServiceConnected");        }        /**         * 当与这个服务失去连接时,这个方法会调用;         * **/        @Override        public void onServiceDisconnected(ComponentName name) {            Log.e("MyServiceConnection","onServiceDisconnected");        }    }    public void callService(View view){        Log.e("callService","callService");        medium.mediumDoSomething();    }}


LeaderService.java

package com.example.administrator.testbindservice;import android.app.Service;import android.content.Intent;import android.os.Binder;import android.os.IBinder;import android.util.Log;public class LeaderService extends Service {    /***     * 在调用bindService()的时候,这个方法就会被调用,     * 当绑定成功,就会将onBindIBinder传递给     * ServiceConnection的参数IBinder service中,     * 这样我们在MainActivity直接操作ServiceConnection     * 的参数IBinder service即可到达我们的目的;     * **/    @Override    public IBinder onBind(Intent intent) {        Log.e("LeaderService","onBind");        return new Medium();    }    /***     * 这是LeaderService里边的方法(功能)     * MainActivity里边是没办法直接调用的     * **/    public void doSomething(){        Log.e("LeaderService","doSomething");    }    /**     * 1>     * 因为BinderIBinder的实现,     * 若我们直接实现IBinder,则需要重写的方法太多,不便于代码的阅读,     * 所以在这里通过继承其子类来达到我们的目的;     * 2>     * Medium在这里充当中间人的作用,由于MainActivity是没有办法直接     * 调用LeaderService里边的方法的,所以我们就通过在Medium里边的方法去     * 调用LeaderService中的方法,然后将Medium返回,这样,当MainActivity     * 得到Medium之后,然后调用Medium里边的方法的时候,就间接达到调用LeaderService里边的方法了;     * **/    class Medium extends Binder{        /***         * 这样,当我们调用mediumDoSomething()方法时,         * 其间接也就实现了调用LeaderService里边的doSomething()方法了;         * **/        public void mediumDoSomething(){            doSomething();        }    }    @Override    public void onCreate() {        Log.e("LeaderService","onCreate");    }    @Override    public int onStartCommand(Intent intent, int flags, int startId) {        Log.e("LeaderService","onStartCommand");        return super.onStartCommand(intent, flags, startId);    }    @Override    public void onDestroy() {        Log.e("LeaderService","onDestroy");    }    @Override    public boolean onUnbind(Intent intent) {        Log.e("LeaderService","onUnbind");        return super.onUnbind(intent);    }}


activity_main.xml

<?xml version="1.0" encoding="utf-8"?><RelativeLayout 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: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="com.example.administrator.testbindservice.MainActivity">    <Button        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="调用LeaderService里边的方法"        android:onClick="callService"        /></RelativeLayout>

运行结果如下:

1>当MainActivity开启时:



2>当点击按钮调用服务时:


3>当销毁MainActivity时:



注:

用Context.bindService()方法启动服务,在服务未被创建时,系统会先调用服务的onCreate()方法,接着调用onBind()方法。这个时候调用者和服务绑定在一起,调用者退出了,系统就会先调用服务的onUnbind()方法,接着调用onDestroy()方法。如果调用bindService()方法前服务已经被绑定,多次调用bindService()方法并不会导致多次创建服务及绑定(也就是说onCreate()和onBind()方法并不会被多次调用)。如果调用者希望与正在绑定的服务解除绑定,可以调用unbindService()方法,调用该方法也会导致系统调用服务的onUnbind()-->onDestroy()方法。



总结:startService 和 bindService的区别

服务不能自己运行,需要通过调用Context.startService()或Context.bindService()方法启动服务。这两个方法都可以启动Service,但是它们的使用场合有所不同。
 
使用startService()方法启用服务,调用者与服务之间没有关连,即使调用者退出了,服务仍然运行。使用bindService()方法启用服务,调用者与服务绑定在了一起,调用者一旦退出,服务也就终止,大有“不求同时生,必须同时死”的特点。
 
如果打算采用Context.startService()方法启动服务,在服务未被创建时,系统会先调用服务的onCreate()方法,接着调用onStart()方法。如果调用startService()方法前服务已经被创建,多次调用startService()方法并不会导致多次创建服务,但会导致多次调用onStart()方法。采用startService()方法启动的服务,只能调用Context.stopService()方法结束服务,服务结束时会调用onDestroy()方法。
 

如果打算采用Context.bindService()方法启动服务,在服务未被创建时,系统会先调用服务的onCreate()方法,接着调用onBind()方法。这个时候调用者和服务绑定在一起,调用者退出了,系统就会先调用服务的onUnbind()方法,接着调用onDestroy()方法。如果调用bindService()方法前服务已经被绑定,多次调用bindService()方法并不会导致多次创建服务及绑定(也就是说onCreate()和onBind()方法并不会被多次调用)。如果调用者希望与正在绑定的服务解除绑定,可以调用unbindService()方法,调用该方法也会导致系统调用服务的onUnbind()-->onDestroy()方法。


源码:

1>

方式一:Context.startService()源码

2>

方式二:Context.bindService()源码


参考:http://blog.csdn.net/sweetsnow24/article/details/7434149


注:服务记得在Manifest.xml中进行注册,否则开启服务时,不会有效果;

1 0