Android 四大组件之Service

Android四大组件之Service

1、前言

    Service我们可以把它叫做后台服务。因为它是一个运行在后台,我们看不见的地方,执行一些不希望用户看到的服务程序。它和Activity一样继承自Context类,不过没有UI界面,即使这样,它也运行在UI线程中,因此不要在Service里面执行耗时操作,耗时操作请开启一个子线程。
    Service按运行地点可以分为两种。一种是localService,一种是remoteService,本地服务依附在主进程上,并不一个独立进程,在一定程度上节约了资源的使用。并且不要进行IPC和AIDL通信,而bindService就显得很方便了,bindService其实也是通过binder通信,不过使用起来更加方便。remoteService即远程服务(android:process:":remote"在manifest文件里这样使用),不要被远程这个词搞糊涂了,它和本地服务的区别就是remoteService是一个独立的进程,当启动它的主线程挂了,它还能运行。虽然看起来很强大,但是用起来就比本地服务要复杂一些,需要是要IPC进程间通信,而且还会占用一些资源。Service按启动方式可以分为三种。分别是startService、bindService、startService与bindService结合使用,下面我们就主要讲这三种启动方式。

2、startService

    通过startService启动后台服务。会调用Service的onCreate方法、onStartCommand方法,不调用onBind方法,但是这个方式是必须要实现的,可以返回一个null。之后每次执行startService就会调用startCommand。当在activity中调用stopService或者Service自己调用stopSelf时,会回调Service里面的onDestory方法。这里要注意的是后台销毁了,但是它开启的线程并不会被取消,因为子线程还在主进程中运行,为了节省资源应该在onDestroy方法中断正在执行的线程。下面有个例子:

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "test";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    public void onLaunchService(View view){
        Intent intent = new Intent(this, TestOfStartService.class);
        intent.putExtra("activityName", this.getClass().getName());
        Log.d(TAG, "onLaunchService: ");
        startService(intent);
    }
    public void onStopService(View view){
        Intent intent = new Intent(this, TestOfStartService.class);
        stopService(intent);
    }
}

xml文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">


    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="启动服务"
        android:onClick="onLaunchService"/>

    <Button
        android:layout_height="wrap_content"
        android:layout_width="match_parent"
        android:text="停止服务"
        android:onClick="onStopService"/>
</LinearLayout>

后台服务类

public class TestOfStartService extends Service {

    private Thread mThread;
    private static final String TAG = "test";

    Handler handler = new Handler(){
        @Override
        public void handleMessage(@NonNull Message msg) {
            super.handleMessage(msg);
            Toast.makeText(getApplication(), "后台提醒", Toast.LENGTH_SHORT).show();
        }
    };

    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG, "TestOfStartService + onCreate: " + TestOfStartService.class.getSimpleName() + ":服务被创建!");
    }

    //此方法必须实现
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {

        Log.d(TAG, "TestOfStartService + onStartCommand: " + intent.getStringExtra("activityName"));
        if(mThread != null) {
            mThread.interrupt();
        }
        mThread = new Thread() {
            @Override
            public void run() {
                try {
                    while (true) {
                        //等待停止线程
                        if (this.isInterrupted()) {
                            throw new InterruptedException();
                        }
                        Thread.sleep(2000);
                        //耗时操作。
//                        System.out.println("执行耗时操作");
                        handler.sendEmptyMessage(1);
                        Log.d(TAG, "TestOfStartService + onStartCommand + run: 执行耗时操作");
                    }
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
        };
        mThread.start();
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "TestOfStartService + onDestroy: 服务被摧毁");
        mThread.interrupt();
    }
}

别忘了在manifest文件里面添加

        <service android:name="com.example.startservice.TestOfStartService"
            android:enabled= "true" />

    这里可以看出,虽然startService可以常驻后台,即使activity被kill了还有运行,但是startService启动Service不方便activity与Serivice进行交互,Service只能在onStartCommand这个方法里面接受来自client的消息,而client无法从Serivce上获取消息。

2、bindService

    可以通过bindService启动服务,依次调用Service的onCreate、onBind方法,onStartCommand不会回调。之后多次调用bindService都不会触发任何回调。停止服务情况也有几种,可以通过unBindService或者启动Service的Context消失了都会停止这个服务。调用unBindService会触发onUnBind、onDestroy回调,如果重复调用unBindService会出错的哦。下面来看看例子:
MainActivity:

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "test";
    TestOfBindService.MyBinder myBinder;

    private ServiceConnection con = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            //这个iBinder就是service中iBinder对象的引用,可以通过这个引用实现通信。
            myBinder = (TestOfBindService.MyBinder) iBinder;
            myBinder.showTip();
            //可以显示,说明不需要。
            Log.d(TAG, "onServiceConnected: " + myBinder.test.test);
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            Log.d(TAG, "onServiceDisconnected: " + componentName.toString());
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

    }
    public void onLaunch(View view){
        Intent intent = new Intent(this, TestOfBindService.class);
        intent.putExtra("activityName", MainActivity.class.getSimpleName());
        bindService(intent, con, BIND_AUTO_CREATE);
    }

    public void onUnBindtest(View view){
        unbindService(con);
    }
    //通过改变myBinder对象的变量实现通信
    public void onUserBinder(View view){
        myBinder.changeable = !myBinder.changeable;
        Log.d(TAG, "onUserBinder: " + myBinder.changeable);
    }
}

Service实现:

public class TestOfBindService extends Service {
    private static final String TAG = "test";
    private MyBinder myBinder = new MyBinder();
    private Handler handler = new Handler(){
        @Override
        public void handleMessage(@NonNull Message msg) {
            super.handleMessage(msg);
            Toast.makeText(getApplication(),"myBinder数据改变了", Toast.LENGTH_SHORT).show();
        }
    };
    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG, "TestOfBindService + onCreate: ");
        new Thread(new Runnable() {
            @Override
            public void run() {
                while(true){
                    //根据myBinder对象变量来改变状态。
                    if(myBinder.changeable){
                        try {
                            Thread.sleep(1000);
//                            handler.sendEmptyMessage(1);
                            Log.d(TAG, "run: " + myBinder.hashCode());

                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }).start();
    }

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

    @Override
    public boolean onUnbind(Intent intent) {
        Log.d(TAG, "TestOfBindService + onUnbind: " + intent.getStringExtra("activityName") + "解除绑定");
        return super.onUnbind(intent);
    }

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

    //需要返回给前台的Binder类
    class MyBinder extends Binder {
        protected boolean changeable = false;
        public testClass test = new testClass();
        public void showTip(){
//            System.out.println("我是来此服务的提示");
            Log.d(TAG, "showTip: " + "我是来自此服务的提示");
        }
    }
    class testClass{
        public String test = "binder的成员对象是否需要实现parcel接口?";
    }
}

XML文件:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="启动服务"
        android:onClick="onLaunch"/>

    <Button
        android:layout_height="wrap_content"
        android:layout_width="match_parent"
        android:text="解绑后台"
        android:onClick="onUnBindtest"/>

    <Button
        android:layout_height="wrap_content"
        android:layout_width="match_parent"
        android:text="使用service中的binder"
        android:onClick="onUserBinder"/>

</LinearLayout>

最后不要忘了在Manifest文件里面添加service标签。

3、startService and bindService

    如果想要服务常驻后台,又要与服务进行通信,那么就可以使用这种方法。Service的生命是onCreate->onStartCommand->onBind->onUnBind->onDestroy.需要注意的是调用unBindService是不能停止服务的,需要调用stopService或者服务自己调用stopSelf。

总结

    前所讲的都是Service的一些基本操作,比较难使用是clien和Service跨进程间通信,这里需要使用Android平台的IPC知识(带你了解android的IPC机制)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值