Service知识点全解析(一)

本文详细介绍了Android中的Service组件,包括其特点、分类、生命周期以及启动和绑定两种使用方式。并通过示例代码展示了如何创建和使用Service,同时介绍了Service与Activity之间的通信方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

什么是Service?

Service即服务,是Android四大组件之一,主要用于在后台处理一些计算型的任务。如后台播放音乐等。但是service是在主线程中的,所以耗时任务处理需要在service中开启子线程的。

Service的特点:
1. 它无法与用户直接进行交互、它必须由用户或者其他程序显式的启动;
2. 它的优先级比较高,它比处于前台的应用优先级低,但是比后台的其他应用优先级高;

Service的分类:
本地服务:这种服务主要依附于主进程上,因此不需要IPC,也不需要AIDL。在主进程被杀后服务会终止。如音乐软件的播放等。
远程服务:这种服务是在独立的进程上,对应进程名格式为所在包名加上你指定的android:process字符串。如一些提供系统服务的Service,这种Service是常驻的。

Service 与 Thread 的区别: 请记住这句话:半毛钱关系都没有。一般用service并在其中处理耗时任务,是因为便于控制。

service的生命周期:

startService方式启动的服务:onCreate(),onStartCommand,onDestroy()。
bindService方式绑定的服务:onCreate(),onBind(),onUnbind(),onDeatroy()。

使用service的方式有启动和绑定两种方式。一个service可以既被启动也可以被绑定。若是关闭这种服务,需要调用stopService和unbindService方法解绑并关闭service,与调用的顺序无关。

注意:
1. 一个已经启动的服务,再次启动只会重复执行onStartCommand方法。
2. 一个已经绑定的服务,再次绑定,生命周期内方法均不会被执行。
3. 停止服务的时候,只需要一次stopService或unbindService即可(若既启动有绑定,需要两个方法都要调用)。

如何使用service

清单文件注册(四大组件中除了广播,都需要在AndroidMainfest.xml中注册)

<application>
...
<service android:name=".FirstService"/>
...
</application>

startService方式启动的service类

public class SecondService extends Service {
    private static String TAG = "SecondService";

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.d(TAG, "onBind");
        return null;
    }

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

bindService方式绑定的service类

public class FirstService extends Service {
    private static String TAG = "FirstService";
    private MyBinder myBinder = new MyBinder();

    @Override
    public IBinder onBind(Intent intent) {
        Log.d(TAG, "onBind");
        return myBinder;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG, "onCreate");
    }

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

    class MyBinder extends Binder {
        public void downloadTask() {
            //这里仍是在主线程内,所以若是做耗时操作,需要开启子线程去完成
            Log.d(TAG, "downloadTask");
        }
    }

    @Override
    public void onDestroy() {
        Log.d(TAG, "onDestroy");
        super.onDestroy();
    }
}

activity内调用如下

public class SecondActivity extends Activity {
    private static String TAG = "SecondActivity";
    @BindView(R.id.startService)
    Button startService;
    @BindView(R.id.stopService)
    Button stopService;
    @BindView(R.id.bindService)
    Button bindService;
    @BindView(R.id.unbindService)
    Button unbindService;

    private FirstService.MyBinder myBinder;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);
        Log.d(TAG, "onCreate");
    }


    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        Log.d(TAG, "onSaveInstanceState");
    }

    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        Log.d(TAG, "onRestoreInstanceState");
    }

    @OnClick({R.id.startService, R.id.stopService, R.id.bindService, R.id.unbindService})
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.startService:
                startService(new Intent(this, FirstService.class));
                break;
            case R.id.stopService:
                stopService(new Intent(this, FirstService.class));
                break;
            case R.id.bindService:
                bindService(new Intent(this, FirstService.class), serviceConnection, BIND_AUTO_CREATE);
                break;
            case R.id.unbindService:
                unbindService(serviceConnection);
                break;
        }
    }

    ServiceConnection serviceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            myBinder = (FirstService.MyBinder) service;
            myBinder.downloadTask();
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };

    @Override
    protected void onDestroy() {
        super.onDestroy();
        stopService(new Intent(this, FirstService.class));
        Log.d(TAG, "onDestroy");
    }
}

上面已经列出了不同启动的方式和使用方法。如activity内:
一般startService方式启动的service是放任服务执行任务的,交互较少。而bindService方式绑定的service,交互较多。

bindService方式绑定一个service如下:

bindService(new Intent(this, FirstService.class), serviceConnection, BIND_AUTO_CREATE);

这里BIND_AUTO_CREATE表示绑定后自动创建服务。还有很多标志位,查阅源码即知~

serviceConnection是一个内部类,其中:
onServiceConnected方法表示绑定后的回调,onServiceDisconnected是解绑后的回调。

我们通过onServiceConnected内的向下转型获得binder实例,然后可以调用service内MyBinder的方法downloadTask()。

 myBinder = (FirstService.MyBinder) service;
 myBinder.downloadTask();

MyBinder内还有其他的方法通过此实例被activity调用,这也是activity与service通信的一种方式。

activity与service的通信

上面的是一种通信方式,是一种被动式通信。若实现service主动向activity通信,还有以下方式~
1. 接口回调
2. 广播
注意:从不用EventBus,因可读性差,不便维护~

案例:每秒从service发送进度给activity,并更新在activity的textview上。

接口回调方式建立通信:

public interface OnProgressListener {
    void onProgress(int progress);
}

在service内,接口定义写在MyBinder内了,保持低耦合(一个binder类可以复用在不同的service中哦),其他的是无关代码,省略~

 ...
 public class MyBinder extends Binder {
        private OnProgressListener onProgressListener;

        public void setOnProgressListener(OnProgressListener onProgressListener) {
            this.onProgressListener = onProgressListener;
        }

        public void downloadTask() {
            //这里仍是在主线程内,所以若是做耗时操作,需要开启子线程去完成
            Log.d(TAG, "downloadTask");
            new Thread(new Runnable() {
                @Override
                public void run() {
                    while (flag && count < 20) {
                        try {
                            Thread.sleep(1000);
                            count++;
                            onProgressListener.onProgress(count);
                            Log.d(TAG, "onStartCommand=" + count);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }).start();
        }
    }
...

activity内接受数据更新在Textview上:

 ServiceConnection serviceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            myBinder = (FirstService.MyBinder) service;
            myBinder.downloadTask();
            myBinder.setOnProgressListener(new OnProgressListener() {
                @Override
                public void onProgress(final int progress) {
                    Log.d(TAG,"onProgress="+progress);
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            showProgress.setText("onProgress="+progress);
                        }
                    });
                }
            });
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };

runOnUiThread底层也是通过handler异步通信机制的,此类知识点可看

http://blog.youkuaiyun.com/abcjinzi/article/details/53433320

广播方式建立通信: 很简单的,会用广播就会了,省略了吧~

个人分述:一般情况下,在同一时刻,服务是一对一与activity交互的,使用接口回调方式通信更方便,广播适合同时刻一对多的情况,而其他情况下都有种“大材小用”的感觉~

接下来还有对service的进一步研究,敬请期待~

源码下载

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值