美文网首页
Service基本使用

Service基本使用

作者: 者文_ | 来源:发表于2019-08-09 18:51 被阅读0次

    Service是android中实现程序后台运行的解决方案,适合去执行那些不需要和用户交互且长期运行的任务。服务的运行不依赖任何用户界面。

    Service并不是运行在一个独立的进程当中,依赖于创建服务时所在的应用程序进程。某个应用程序进程被杀掉时,所有依赖于该进程的服务也会停止

    1. Service使用

    image

    Android中使用Service的方式有两种

    • StartService()启动Service
    • BindService()启动Service
    • 额外其实还有一种,就是启动Service后,绑定Service

    1.1 关键方法

    • onCreate():当Service第一次被创建后立即回调该方法,该方法在整个生命周期 中只会调用一次
    • onDestory():当Service被关闭时会回调该方法,该方法只会回调一次
    • onStartCommand(intent,flag,startId):早期版本是onStart(intent,startId), 当客户端调用startService(Intent)方法时会回调,<font color = red>可多次调用StartService方法</font>, 但不会再创建新的Service对象,而是继续复用前面产生的Service对象,但会继续回调 onStartCommand()方法!
    • IBinder onBind(intent):该方法是Service都必须实现的方法,该方法会返回一个 IBinder对象,app通过该对象与Service组件进行通信!
    • onUnbind(intent):当该Service上绑定的所有客户端都断开时会回调该方法!

    1.2 startService()启动

    使用Service的一般流程:自定义service,重写相关方法,调用即可

    简单示例:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <Button
            android:id="@+id/start_service"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="start service" />
        <Button
           android:id="@+id/stop_service"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Stop Service"/>
    
    </LinearLayout>
    

    自定义Service

    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() {
            super.onCreate();
            Log.d("MyService", "onCreate executed");
        }
    
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            Log.d("MyService", "onStartCommand executed");
            return super.onStartCommand(intent, flags, startId);
        }
    
        @Override
        public void onDestroy() {
            super.onDestroy();
            Log.d("MyService", "onDestroy executed");
        }
    }
    

    调用服务

    public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            Button startService = (Button) findViewById(R.id.start_service);
            Button stopService = (Button) findViewById(R.id.stop_service);
            startService.setOnClickListener(this);
            stopService.setOnClickListener(this);
        }
    
        @Override
        public void onClick(View v) {
            switch (v.getId()) {
                case R.id.start_service:
                    Intent startIntent = new Intent(this, MyService.class);
                    startService(startIntent);
                    break;
                case R.id.stop_service:
                    Intent stopIntent = new Intent(this, MyService.class);
                    stopService(stopIntent);
                    break;
                default:
                    break;
    
            }
        }
    }
    

    注册服务(四大组件都要注册)

    <service
        android:name=".MyService"
        android:enabled="true"
        android:exported="true"></service>
    

    备注

    • exported属性表示是否允许除了当前程序之外的其他程序访问这个服务
    • enabled属性表示是否启用这个服务
    • startService()stopService()方法都是定义在Context类中,可以直接调用这两个方法来启动和停止服务。
    • 如要服务自行停止,在MyService的任何一个位置调用stopSelf()方法就可以停止服务

    1.3 bindService()启动

    前述的方式启动服务之后,活动与服务基本就没有关系了。而用Binder方法可以让活动和服务的关系更加紧密,实现二者的通信。

    1.3.1 知识介绍

    • ServiceConnection对象

      监听访问者与Service间的连接情况,如果成功连接,回调 onServiceConnected(),如果异常终止或者其他原因终止导致Service与访问者断开 连接则回调onServiceDisconnected()方法,调用unBindService()不会调用该方法!

    • onServiceConnected()

      该方法中有一个IBind对象,该对象可以实现与被绑定Service之间通信。开发的Service类里 IBinder onBind()方法会会返回一个IBinder对象,会传到ServiceConnection对象中的onServiceConnect(),通过此对象完成通信。

    1.3.2 步骤与实例

    一般步骤如下

    • 在自定义的Service中继承Binder,实现自己的IBinder对象
    • 通过onBind()方法返回自己的IBinder对象
    • 绑定该Service的类中定义的一个ServiceConnection对象,重写其中两个方法,直接读取IBinder传递过来的参数即可。

    实例

    public class MyService extends Service {
    
        private DownloadBinder mBinder = new DownloadBinder();
    
        class DownloadBinder extends Binder {
    
            public void startDownload() {
                Log.d("MyService", "startDownload");
            }
    
            public int getProgress() {
                Log.d("MyService", "getProgress executed");
                return 0;
            }
        }
    
        public MyService() {
        }
    
        @Override
        public IBinder onBind(Intent intent) {
            // TODO: Return the communication channel to the service.
            return mBinder;
        }
        ...
     }
    
    public class MainActivity extends AppCompatActivity implements View.OnClickListener {
        //绑定该Service的类中定义一个ServiceConnection对象
        private MyService.DownloadBinder downloadBinder;
        private ServiceConnection connection = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                downloadBinder = (MyService.DownloadBinder) service;
                downloadBinder.startDownload();
                downloadBinder.getProgress();
            }
    
            @Override
            public void onServiceDisconnected(ComponentName name) {
            }
        };
        
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            Button startService = (Button) findViewById(R.id.start_service);
            Button stopService = (Button) findViewById(R.id.stop_service);
            startService.setOnClickListener(this);
            stopService.setOnClickListener(this);
            Button bindService = (Button) findViewById(R.id.bind_service);
            Button unbindService = (Button) findViewById(R.id.unbind_service);
            bindService.setOnClickListener(this);
            unbindService.setOnClickListener(this);
        }
    
        @Override
        public void onClick(View v) {
            switch (v.getId()) {
                case R.id.start_service:
                    Intent startIntent = new Intent(this, MyService.class);
                    startService(startIntent);
                    break;
                case R.id.stop_service:
                    Intent stopIntent = new Intent(this, MyService.class);
                    stopService(stopIntent);
                    break;
                case R.id.bind_service:
                    Intent bindIntent = new Intent(this, MyService.class);
                    bindService(bindIntent, connection, BIND_AUTO_CREATE);
                    break;
                case R.id.unbind_service:
                    unbindService(connection);
                    break;
                default:
                    break;
    
            }
        }
    }
    
    

    备注

    • bindService()接收3个参数:
      • 第一个是Intent对象
      • 第二个是创建的ServiceConnection实例
      • 第三个是一个标志位
        • BIND_AUTO_CREATE:活动和服务进行绑定后自动创建服务。这使得Service中的onCreate()得以执行
    • 绑定多客户端情况需要解除所有绑定才会调用onDestory()进行销毁

    2. IntentService使用

    如果直接把耗时线程放到Service中的onStart()方法中,容易引起ANR(Application Not Responding)异常.Service不是一个单独的进程,与应用程序同在一个进程中;Service不是一个线程,避免在Service中进行耗时操作

    我们可以用多线程技术,在服务的每个具体方法里开启一个子线程,在这里去处理耗时的逻辑,则一个标准的逻辑可以写成:

    public class MyService extends Service {
        ...
        @override
            public int onStartCommand(Intent intent, int flags, int startId) {
            new Thread(new Runnable() {
                @override
                public void run() {
                    //处理具体逻辑
                    stopself();//执行完毕自动停止服务
                }
            }).start();
            return super.onStartCommand(intent, flags, startId);
        }
    }
    

    前述方法容易忘记开启线程,或者忘记调用stopSelf()方法。

    IntentService继承于Service并处理异步请求的一个类,在IntentService中有一个工作线程来处理耗时操作,请求的Intent记录会加入队列。

    2.1 工作流程

    客户端通过startService(Intent)来启动IntentService,当任务执行完后,IntentService会自动停止;可以启动IntentService多次,每个耗时操作会以工作队列的方式在IntentService的 onHandleIntent回调方法中执行,并且每次只会执行一个工作线程,执行完一,再到二这样!

    实例:

    public class MyIntentService extends IntentService {
    
        public MyIntentService() {
            super("MyIntentService");
        }
    
        @Override
        protected void onHandleIntent(Intent intent) {
            Log.d("MyIntentService", "Thread id is" + Thread.currentThread().getId());
        }
    
        @Override
        public void onDestroy() {
            super.onDestroy();
            Log.d("MyIntentService", "onDestory ececuted");
        }
    }
    

    备注

    • 自定义的IntentService类需要先提供一个无参构造器,并且必须在其内部调用父类的有参构造函数。
    • 要在子类中实现onHandleIntent()这个抽象方法,在这个方法中处理一些具体的逻辑
    • 这个服务运行结束后自动停止,重写了onDestroy()方法。

    3. 前台服务(待补充)

    Service一般都是运行在后台的,但是Service的系统优先级 还是比较低的,当系统内存不足的时候,就有可能回收正在后台运行的Service, 对于这种情况我们可以使用前台服务,从而让Service稍微没那么容易被系统杀死。

    前台服务与普通服务之间最大的区别在于:它会有一个正在运行的图标在系统的状态栏显示,下拉状态栏可以看到更加详细的信息。

    相关文章

      网友评论

          本文标题:Service基本使用

          本文链接:https://www.haomeiwen.com/subject/xeckjctx.html