Android四大组件之Service

/ 0评 / 0

Service

Service正如其名,是一种服务性质的组件,不能被用户所见,只能在后台运行,但是可以和其他组件进行交互,Service可以看做不可见的Activity,可以在后台有规律的执行某些操作,Service组件与其他的应用程序对象一样,是运行在启动它的主线程中,所以不可以在Service中进行耗时的操作,会阻塞主线程,但是可以在Service中启动新线程来进行操作,Service作为没有界面的长生命周期组件,可以用于媒体播放,记录用户地理位置信息等后台操作。

Service的启动模式

Service可以通过startService启动一个无绑定的Service,当启动这个Service的Activity被destroy的时候,Service继续运行在后台,不过这种方式启动的Service与Activity无交互,还有一种方式是通过bindService方法启动一个绑定的service,这种方式启动的Service可以与绑定的程序发生交互,但是在绑定的程序退出的时候,需要unbindService来解绑定,不然会有异常发生,还可以连续调用上面的两个函数,让Service同时具有上面两个的优点,当程序退出时,Service不销毁,而且可以与应用程序发生交互。

Service的生命周期

对于startService方式启动的服务来说,只有第一次启动的时候会调用onCreate() 方法,以后多次调用startService均只调用onStartCommand()方法(onStart()方法被弃用了),不论前面调用多少次startService,只需调用一次stopService即可停止服务,stopService多次调用没事,不会产生异常

对于bindService方式启动的服务来说,可以多次调用bindService,不过只有第一次有效,但是unbindService只能在服务正在运行的时候调用有效,当绑定服务没有运行的时候,调用此方法会产生异常

Service

Service的使用

定义一个Service,首先得继承android.app.Service,根据需要,覆写上面生命周期图中的回调函数

public class Service1 extends Service {
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onCreate() {
        Log.v("x", "onCreate");
        super.onCreate();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.v("x", "onStartCommand");
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        Log.v("x", "onDestroy");
        super.onDestroy();
    }
}

可以看到,上面有一个特殊的onBind方法是必须覆写的,这个方法的默认返回null,如果通过startService方式启动Service,那么不用管这个回调函数,如果使用bindService启动服务,那么当绑定的时候,会回调这个函数,通过这个函数的返回值,启动服务的组件就可以与服务进行交互。

与其他组件一样,当定义好一个Service以后,需要在配置文件中注册这个Service

<service android:name=".Service1" />

startService启动:类似于其他组件,需要使用Intend对象

Intent intent = new Intent();
intent.setClass(this, Service1.class);
startService(intent);

停止startService启动的服务

Intent intent = new Intent();
intent.setClass(this, Service1.class);
stopService(intent);

bindService启动服务:

public boolean bindService (Intent service, ServiceConnection conn, int flags)

Intent service:一个Intent对象,用于指定启动的Service

ServiceConnection conn:一个ServiceConnection 对象,用于绑定时回调给绑定者

int flags:启动的标志,Service.BIND_AUTO_CREATE代表自动创建服务

Intent intent = new Intent(this, Service2.class);
startService(intent);
bindService(intent, conn, Service.BIND_AUTO_CREATE);

定义ServiceConnection 对象,ServiceConnection 是一个接口,我们需要new一个匿名内部类出来

ServiceConnection conn = new ServiceConnection() {
    @Override
    //当bind成功,onBind方法被调用以后调用此回调函数
    public void onServiceConnected(ComponentName name, IBinder service) {
        Log.v("x", "Connected");
    }
    //当绑定意外断开的时候调用此方法
    @Override
    public void onServiceDisconnected(ComponentName name) {
        Log.v("x", "onServiceDisconnected");
    }
};

ServiceConnection 的onServiceConnected()方法中,我们可以看到第二个参数为IBinder类型,这个参数就是Service中必须覆写的onBind方法的返回值,通过这个返回值,我们就可以获取服务的实例,从而调用服务中的方法。

完整的demo:

Service代码

public class Service2 extends Service {

    //自定义一个类继承自Binder
    class MyBinder extends Binder {
        //自定义方法,返回此Service的实例
        public Service2 getService() {
            return Service2.this;
        }
    }

    @Override
    public IBinder onBind(Intent intent) {
        //此函数的返回值就是ServiceConnection的第二个参数
        return new MyBinder();
    }
    //Service自定义的四个方法
    public void pro() {
        Log.v("x", "pro");
    }

    public void stop() {
        Log.v("x", "stop");
    }

    public void next() {
        Log.v("x", "next");
    }

    public void play() {
        Log.v("x", "play");
    }
}

启动服务端的代码

public class MainActivity extends Activity {
    private Service2 service2;
    ServiceConnection conn = new ServiceConnection() {
        @Override
        //当bind成功,onBind方法被调用以后调用此回调函数
        public void onServiceConnected(ComponentName name, IBinder service) {
            //获取服务实例
            service2 = ((Service2.MyBinder) service).getService();
        }
        //当绑定意外断开的时候调用此方法
        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.v("x", "onServiceDisconnected");
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.bindService: {
                Intent intent = new Intent(this, Service2.class);
                startService(intent);
                bindService(intent, conn, Service.BIND_AUTO_CREATE);
            }
            break;
            case R.id.unbindService: {
                unbindService(conn);
            }
            break;
            case R.id.play:
                service2.play();
                break;
            case R.id.next:
                service2.next();
                break;
            case R.id.stop:
                service2.stop();
                break;
            case R.id.pro:
                service2.pro();
                break;
        }
    }
}

将Service设置为前台可见

有时候,我们想让Service与用户产生交互,或者给用户提示,我们可以调用public final void startForeground (int id, Notification notification)方法,第一个参数为Notifycation的id,第二个参数为Notifycation对象,在onCreate中调用这个方法,那么Service将会用传入的Notifycation对象,产生一个通知栏提示。可以给与用户提示,onDestroy里面调用stopForeground可以解除前台运行但是不会停止服务,如果在服务被停止的时候,是前台运行状态,通知栏也会一起被清除,不管是否调用了stopForeground。

 

 

发表评论

您的电子邮箱地址不会被公开。