Android Service

2022-02-18  本文已影响0人  gaookey
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>

没有配置 <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

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 具有如下特征

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版)》

上一篇下一篇

猜你喜欢

热点阅读