美文网首页
Android Service

Android Service

作者: gaookey | 来源:发表于2022-02-18 23:22 被阅读0次
    image.png

    创建、配置 Service

    1. 定义一个继承 Service 的子类
    public class TestService extends Service {
        /*
           Service 被绑定时回调该方法
           必须实现的方法,返回一个 IBinder 对象,应用程序可通过该对象与 Service 组件通信
            */
        @Nullable
        @Override
        public IBinder onBind(Intent intent) {
    
    
            System.out.println("intent = " + intent);
    
            return null;
        }
    
        /*
        Service 被创建时回调该方法
         */
        @Override
        public void onCreate() {
            super.onCreate();
    
            System.out.println("onCreate");
        }
    
        /*
        Service 被启动时回调该方法
         */
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            return super.onStartCommand(intent, flags, startId);
        }
    
        /*
        Service 被关闭之前回调该方法
         */
        @Override
        public void onDestroy() {
            super.onDestroy();
        }
    
        /*
       当该 Service 上绑定的所有客户端都断开连接时将会回调该方法
         */
        @Override
        public boolean onUnbind(Intent intent) {
            return super.onUnbind(intent);
        }
    }
    
    1. AndroidManifest.xml 文件中配置该 Service
    <service
                android:name=".TestService"
                android:enabled="true"
                android:exported="true"></service>
    
    • name 指定该 Service 的实现类类名
    • exported 指定该 Service 是否能被其它 APP 启动。如果在配置该 Service 时指定了 <intent-filter.../> 子元素,则该属性默认为 true
    • permission 指定启动该 Service 所需的权限
    • process 指定该 Service 所处的线程,该 Service 组件默认处于该 APP 所在的进程中。Android 四大组件都可通过该属性指定进程

    没有配置 <intent-filter.../> 意味着该 Service 不能响应任何 Intent,只能通过指定 ComponentIntent 来启动

    运行 Service 的两种方式
    1. 通过 ContextstartService() 方法:通过该方法启动 Service,访问者与 Service 之间没有关联,即使访问者退出了,Service 也仍然运行。
    2. 通过 ContextbindService() 方法:使用该方法启动 Service,访问者与 Service 绑定在一起,访问者一旦退出,Service 也就终止了。

    启动和停止 Service

    // 创建启动Service的Intent
    Intent intent = new Intent(this, TestService.class);
    // 启动指定Service
    startBn.setOnClickListener(view -> this.startService(intent));
    // 停止指定Service
    stopBn.setOnClickListener(view -> stopService(intent));
    

    绑定本地 Service 并与之通信

    当程序通过 stariService()StopService() 启动、关闭 Service 时,Service 与访问者之间基本上不存在太多的关联,因此 Service 和访问者之间也无法进行通信、交换数据。
    如果 Service 和访问者之间需要进行方法调用或交换数据,则应该使用 bindService()unbindService() 方法启动、关闭 Service

    • service 该参数通过 Intent 指定要启动的 Service
    • conn 该参数是一个 ServiceConnection 对象,该对象用于监听访问者与 Service 之间的连接情况。当访问者与 Service 之间连接成功时将回调该 ServiceConnection 对象的 onServiceConnected(ComponentName name, IBinder service) 方法;当 Service 所在的宿主进程由于异常中止或其他原因终止,导致该 Service 与访问者之间断开连接时回调该 ServiceConnection 对象的 onServiceDisconnected(ComponentName name) 方法。当调用者主动通过 unbindService() 方法断开与 Service 的连接时,ServiceConnection 时象的 onServiceDisconnected(ComponentName name) 方法并不会被调用。
    • flags 指定绑定时是否自动创建 Service(如果 Service 还未创建)。该参数可指定为 0(不自动创建)或 BIND_AUTO_CREATE(自动创建)。

    BindService

    public class BindService extends Service {
        private int count;
        private boolean quit;
        // 定义onBinder方法所返回的对象
        private MyBinder binder = new MyBinder();
    
        // 通过继承Binder来实现IBinder类
        class MyBinder extends Binder  // ①
        {
            // 获取Service的运行状态:count
            public int getCount() {
                return BindService.this.count;
            }
        }
    
        // Service被绑定时回调该方法
        @Override
        public IBinder onBind(Intent intent) {
            System.out.println("Service is Binded");
            // 返回IBinder对象
            return binder;
        }
    
        // Service被创建时回调该方法
        @Override
        public void onCreate() {
            super.onCreate();
            System.out.println("Service is Created");
            // 启动一条线程,动态地修改count状态值
            new Thread(() ->
            {
                while (!quit) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    BindService.this.count++;
                }
            }).start();
        }
    
        // Service被断开连接时回调该方法
        @Override
        public boolean onUnbind(Intent intent) {
            System.out.println("Service is Unbinded");
            return true;
        }
    
        // Service被关闭之前回调该方法
        @Override
        public void onDestroy() {
            super.onDestroy();
            this.quit = true;
            System.out.println("Service is Destroyed");
        }
    }
    

    MainActivity

    public class MainActivity extends AppCompatActivity {
        // 保持所启动的Service的IBinder对象
        private BindService.MyBinder binder;
        // 定义一个ServiceConnection对象
        private ServiceConnection conn = new ServiceConnection() {
            // 当该Activity与Service连接成功时回调该方法
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                System.out.println("--Service Connected--");
                // 获取Service的onBind方法所返回的MyBinder对象
                binder = (BindService.MyBinder) service;   // ①
            }
    
            // 当该Activity与Service断开连接时回调该方法
            @Override
            public void onServiceDisconnected(ComponentName name) {
                System.out.println("--Service Disconnected--");
            }
        };
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            // 获取程序界面中的start、stop、getServiceStatus按钮
            Button bindBn = findViewById(R.id.bind);
            Button unbindBn = findViewById(R.id.unbind);
            Button getServiceStatusBn = findViewById(R.id.getServiceStatus);
            // 创建启动Service的Intent
            Intent intent = new Intent(this, BindService.class);
            bindBn.setOnClickListener(view ->
                    // 绑定指定Service
                    bindService(intent, conn, Service.BIND_AUTO_CREATE));
            unbindBn.setOnClickListener(view ->
                    // 解除绑定Service
                    unbindService(conn));
            getServiceStatusBn.setOnClickListener(view ->
                    // 获取并显示Service的count值
                    Toast.makeText(MainActivity.this, "Service的count值为:" +
                            binder.getCount(), Toast.LENGTH_SHORT).show()); // ②
        }
    }
    

    IntentService

    IntentService 是 Service 的子类

    Service存在的两个问题

    1. Service 不会专门启动一个单独的进程,Service 与它所在应用位于同一个进程中。
    2. Service 不是一条新的线程,因此不应该在 Service 中直接处理耗时的任务。

    IntentService 将会使用队列来管理请求 Intent,每当客户端代码通过 Intent 请求启动 IntentService 时,IntentService 会将该 Intent 加入队列中,然后开启一条新的 worker 线程来处理该 Intent。对于异步的 startService() 请求,IntentService 会按次序依次处理队列中的 Intent,该线程保证同一时刻只处理一个 Intent。由于 IntentService 使用新的 worker 线程处理 Intent 请求,因此 IntentService 不会阻塞主线程,所以 IntentService 自己就可以处理耗时任务。

    IntentService 具有如下特征

    • IntentService 会创建单独的 worker 线程来处理所有的 Intent 请求。
    • IntentService 会创建单独的 worker 线程来处理 onHandleIntent() 方法实现的代码,因此开发者无须处理多线程问题。
    • 当所有请求处理完成后,IntentService 会自动停止,因此开发者无须调用 stopSelf() 方法来停止该 Service
    • ServiceonBind() 方法提供了默认实现,默认实现的 onBind() 方法返回 null
    • ServiceonStartCommand() 方法提供了默认实现,该实现会将请求 Intent 添加到队列中。

    TestIntentService

    不会阻塞前台 UI 线程,可顺利完成任务

    public class TestIntentService extends IntentService {
     
        public TestIntentService() {
            super("MyIntentService");
        }
    
        @Override
        protected void onHandleIntent(@Nullable Intent intent) {
            // 该方法内可以执行任何耗时任务,比如下载文件等,此处只是让线程暂停20秒
            long endTime = System.currentTimeMillis() + 20 * 1000;
            System.out.println("onStartCommand");
            while (System.currentTimeMillis() < endTime) {
                synchronized (this) {
                    try {
                        wait(endTime - System.currentTimeMillis());
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
            System.out.println("---耗时任务执行完成---");
        }
    }
    

    TestService

    会导致程序 UI 线程被阻塞,阻塞时间过长会出现 ANR 异常

    public class TestService extends Service {
        @Override
        public IBinder onBind(Intent intent) {
            return null;
        }
    
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            // 该方法内执行耗时任务可能导致ANR(Application Not Responding)异常
            long endTime = System.currentTimeMillis() + 20 * 1000;
            System.out.println("onStart");
            while (System.currentTimeMillis() < endTime) {
                synchronized (this) {
                    try {
                        wait(endTime - System.currentTimeMillis());
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
            System.out.println("---耗时任务执行完成---");
            return START_STICKY;
        }
    }
    
        public void startService(View source) {
            // 创建需要启动的Service的Intent
            Intent intent = new Intent(this, TestService.class);
            // 启动Service
            startService(intent);
        }
    
        public void startIntentService(View source) {
            // 创建需要启动的IntentService的Intent
            Intent intent = new Intent(this, TestIntentService.class);
            // 启动IntentService
            startService(intent);
        }
    

    摘抄至《疯狂Android讲义(第4版)》

    相关文章

      网友评论

          本文标题:Android Service

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