天天看点

安卓基础学习之服务组件及应用服务组件及应用

目录

  • 服务组件及应用
    • 1. 服务概念
    • 2. 服务类型
      • 2.1 本地服务
      • 2.2 远程服务
    • 3. service启动方式与生命周期
    • 4. 两种方法的简单实例
      • 4.1 非绑定式的服务
        • 4.1.1 效果
        • 4.1.2 代码
      • 4.2 绑定式的服务
        • 4.2.1 效果
        • 4.2.2 代码

服务组件及应用

1. 服务概念

Service也是Android系统四大组件1之一,它是一种长生命周期、没有可视化界面、运行于后台的一种服务程序。

比如:播放音乐的时候,你有可能想边听音乐边干些其他事情,当退出播放音乐的应用,如果不用Service,就听不到歌了——这就是Service的用武之地了。

Android后台运行的很多Service是在系统启动时被开启的,以支持系统的正常工作。

比如:MountService监听是否有SD卡安装及移除,PackageManagerService提供软件包的安装、移除及查看等。

激活和停止Service通常是由其他组件完成的。例如,组件Activity的超类Context提供了激活和停止Service的方法。

安卓基础学习之服务组件及应用服务组件及应用

如同Activity组件一样,Service组件必须在清单文件里使用相应的标签。使用菜单File→New→Service创建的服务组件,将自动在清单文件里注册。

2. 服务类型

服务类型可划分为本地服务和远程服务,也可划分为绑定式服务与非绑定服务。

2.1 本地服务

本地服务用于应用程序内部(同一个apk内被调用),使用startService()启动服务,使用stopService()停止服务。

在服务内部可以调用Service.stopSelf() 或 Service.stopSelfResult()来自己停止。无论调用了多少次startService(),都只需调用一次stopService()来停止。

2.2 远程服务

远程服务用于应用程序之间(被另一个apk调用)。

可以定义接口并把接口暴露出来,以便其他应用进行操作,比如一个天气预报服务。客户端建立到服务对象的连接,并通过那个连接来调用服务。

通过调用bindService()方法建立连接并启动服务,调用 unbindService()关闭连接。多个客户端可以绑定至同一个服务。如果服务此时还没有加载,bindService()会先加载它。

远程服务提供给可被其他应用复用。

3. service启动方式与生命周期

安卓基础学习之服务组件及应用服务组件及应用
  • 非绑定式服务:

    使用

    startService()

    启动service,调用

    onCreate()

    onStartCommand()

    2两个方法。该service只能创建一次,也就是说

    onCreate()

    只会执行一次。(但每次调用

    startService()

    时,

    onStartCommand()

    方法都会被调用。)

    使用

    stopService()

    来结束服务,调用

    onDestroy()

    方法即可终止服务。
  • 绑定式服务:

    第一次执行

    bindService()

    时,会调用

    onCreate()

    onBind()

    方法创建服务并将service与activity绑定。(但是多次执行

    bindService()

    时,并不会多次创建服务和绑定服务,也就不会再次调用这两个方法。)

    当调用

    unbindService()

    方法或者调用者Context不存在时,比如绑定的activity调用

    finish()

    方法,就会调用

    onUnbind()

    onDestroy()

    来结束服务。
非绑定式服务和绑定式服务的区别
1、startService启动的服务默认无限期执行,bindService启动的服务的生命周期与其绑定者相关。
2、若使用startService启动服务,则创建后将无法再与其传递消息;若使用bindService启动服务,则可以通过IBinder接口实现灵活的交互。

4. 两种方法的简单实例

4.1 非绑定式的服务

4.1.1 效果

界面如下图所示:

安卓基础学习之服务组件及应用服务组件及应用

logcat中输出:

2020-04-17 16:10:52.756 24674-24674/com.example.myapplication_service V/MyService_unbind: service is created!
2020-04-17 16:10:52.756 24674-24674/com.example.myapplication_service V/MyService_unbind: service is started!
2020-04-17 16:11:01.823 24674-24674/com.example.myapplication_service V/MyService_unbind: service is destroyed!
           

4.1.2 代码

首先在项目中new一个Service(注意,Service中又两个选项,new的是Service而不是Service(IntentService))

创建初始会自带

onBind()

方法,由于此处写的是非绑定式的方法,直接在里面

return null;

即可。

MyService_unbind.java

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;

public class MyService_unbind extends Service {
    public MyService_unbind() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        return null;
    }

	//创建服务
    @Override
    public void onCreate() {
        super.onCreate();
        Log.v("MyService_unbind","service is created!");
    }

	//开始服务
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.v("MyService_unbind","service is started!");
        return START_STICKY;
    }

	//结束服务
    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.v("MyService_unbind","service is destroyed!");
    }
}
           

由于服务是不与用户交互的,此处为了使代码更简单且演示效果更明显,就在每个方法中用logcat打印出一句话表明服务的生命周期,并在布局文件中写两个用于启动服务和终止服务的button。

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.403" />

    <Button
        android:id="@+id/btn_ubs"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="启动非绑定式服务"
        app:layout_constraintBottom_toTopOf="@+id/btn_ubd"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.498"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/textView"
        app:layout_constraintVertical_bias="0.676" />

    <Button
        android:id="@+id/btn_ubd"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="204dp"
        android:text="关闭非绑定式服务"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.498"
        app:layout_constraintStart_toStartOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>
           

在MainActivity中写两个button的触发事件,在启动服务按钮中使用

startService()

启动service,在终止按钮中使用

stopService()

来结束服务。

MainActivity.java

import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class MainActivity extends AppCompatActivity {

    Button btn_ubs;
    Button btn_ubd;

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

        //获取程序界面的两个按钮
        btn_ubs = (Button)findViewById(R.id.btn_ubs);
        btn_ubd = (Button)findViewById(R.id.btn_ubd);

        btn_ubs.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(MainActivity.this,MyService_unbind.class);
                startService(intent);
            }
        });

        btn_ubd.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(MainActivity.this,MyService_unbind.class);
                stopService(intent);
            }
        });

    }
}
           

需要注意的问题:

1、若没有直接new一个service,则要手动在

AndroidManifest.xml

文件里面注册自己写的service。若是new的service,则会在清单文件中自动注册,如下所示。

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

2、布局文件中的button的text最好写在strings.xml中,可以根据布局文件中的警告进一步修改。

4.2 绑定式的服务

4.2.1 效果

界面如下图所示:

每点一次按钮,textview就会刷新成自第一次点击按钮后到这次点击按钮所经历的秒数。

安卓基础学习之服务组件及应用服务组件及应用

4.2.2 代码

new一个service,命名为BinderService来写绑定式服务。

绑定式服务需要重写

onBind()

方法,返回一个IBinder的对象。IBinder是一个接口,一般我们会继承实现了IBinder类的Binder类,在其中实现自己的方法。

BinderService.java

import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;

public class BinderService extends Service {
    public BinderService() {
    }

    private int count = 0;

    class Mybinder extends Binder{
        public int getcount(){return count;}
    }

    Mybinder binder = new Mybinder();

    @Override
    public void onCreate() {
        super.onCreate();
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (true){
                    try{
                        //线程启动后每过1s,count+1
                        Thread.sleep(1000);
                        count++;
                    }catch (Exception e){e.printStackTrace();}
                }
            }
        }).start();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
    }

    @Override
    public boolean onUnbind(Intent intent) {
        return super.onUnbind(intent);
    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        return binder;
    }
}
           

在布局文件中定义一个button来启动绑定式服务,textview显示当前秒数。

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
    tools:context=".MainActivity">
    
    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.179" />

    <Button
        android:id="@+id/btn_bs"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/btn_bs_text"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/textView" />

</androidx.constraintlayout.widget.ConstraintLayout>
           

在MainActivity中写button的触发事件,在启动服务按钮中用

bindService()

来绑定服务。

MainActivity.java

import androidx.appcompat.app.AppCompatActivity;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    Button btn_bs;
//    创建绑定服务下的binder的实例
    BinderService.Mybinder mybinder;

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

        btn_bs = (Button)findViewById(R.id.btn_bs);

        final TextView textView = (TextView)findViewById(R.id.textView);

//        给出activity要调的服务BinderService,是bindService的第一个参数
        Intent binderintent = new Intent(MainActivity.this,BinderService.class);

//        bindService的第二个参数
        ServiceConnection connection = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
//                这里的service就是onBind()方法返回的binder对象
                mybinder = (BinderService.Mybinder)service;
            }

            @Override
            public void onServiceDisconnected(ComponentName name) {
//                服务连接结束时,设置其为null
                mybinder = null;
            }
        };

//        绑定服务,有三个参数:intent、ServiceConnection和int
//        其中的第三个参数是指明绑定效果
        bindService(binderintent,connection, Context.BIND_AUTO_CREATE);

        btn_bs.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                textView.setText(mybinder.getcount()+"");
            }
        });
    }
}
           
  1. Android四大组件分别为:Activity/Service/BroadCast Recevicer/Content provider ↩︎
  2. Service的onStart方法在API 5时被废弃,替代它的是onStartCommand方法。 ↩︎