【达内课程】Service(上)

进程优先级

讲解 Service 之前,先了解一下进程优先级

在 Android 系统中,当系统资源(内存资源)不足时,系统会自动清理一部分应用程序占用的内存,以释放出更多的可用内存空间,运行当前需要执行的应用程序

当系统自动清理应用程序占用的内存时,会按照进程的优先级,从低到高进行清理,即优先级较低的进程则最优先被清理,而优先级较高的则越不容易被清理

进程的优先级,从高到低依次是:
1、前台进程,表现为进程中存在可见并可控的 Activity
2、可见进程,表现为进程中存在局部可见却不可控的 Activity
3、服务进程,表现为存在正在运行的 Service
4、后台进程,表现为该进程中的所有 Activity 均已被置于后台,即不可见也不可控
5、空进程,表现为已经退出的进程

如果我正在使用 QQ,那么 QQ 属于前台进程,如果回到桌面,就是后台进程,如果直接按返回键退出,那么 QQ 就是空进程

Service使用

Service 是 Android 系统的核心组件之一

Service 是没有界面的,后台工作(看不见)的类

Service 是运行在主线程的,所以,虽然 Service 适合做长期的任务,但是,也必须开始子线程来完成相关任务。Service 可以用于在后台执行的操作,例如检查版本更新,长时间的任务。

Service 是单例的(实例唯一:在同一时间内只存在一个对象)

启动Service
调用startService(Intent)方法即可启动 Service

停止Service
1、在 Service 类以外,调用stopService(intent)方法即可停止 Service
2、在 Service 类内部,调用stopSelf()方法,即可停止当前 Service

Service生命周期

onCreate():当第一次创建 Service 对象时被调用
onStartCommand():每次激活 Service 组件时被调用
onDestroy():销毁服务

栗子1:观察service生命周期

新增 WorkService

public class WorkService extends Service {
    public WorkService() {
        super.onCreate();
        Log.d("Service", "WorkService@" + hashCode() + ".onCreate()");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d("Service", "WorkService@" + hashCode() + ".onStartCommand()");
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        Log.d("Service", "WorkService@" + hashCode() + ".onDestroy()");
        super.onDestroy();
    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        throw new UnsupportedOperationException("Not yet implemented");
    }
}

通过 Android Studio 的右键 new 一个 Service 会自动在 AndroidManifest中注册

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

activity_main布局文件中增加两个 Button 分别用来激活和停止 Service

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <Button
        android:id="@+id/btn_start_service"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="激活Service" />

    <Button
        android:id="@+id/btn_stop_service"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="停止Service" />

</LinearLayout>

MainActivity.java

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    private Button btnStart;
    private Button btnStop;

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

        btnStart = findViewById(R.id.btn_start_service);
        btnStart.setOnClickListener(this);
        btnStop = findViewById(R.id.btn_stop_service);
        btnStop.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        Intent intent = new Intent(this, WorkService.class);
        switch (v.getId()) {
            case R.id.btn_start_service:
                startService(intent);
                break;
            case R.id.btn_stop_service:
                stopService(intent);
                break;
        }
    }
}

运行程序:
在这里插入图片描述
当启动一个Service的时候,会调用该 Service中 的onCreate()onStartCommand()

onCreate()方法只会在 Service 第一次被创建的时候调用

如果当前Service已经被创建过了,不管怎样调用startService()方法,onCreate()方法都不会再执行

Activity和Service传递数据

开始这里的内容之前,你需要知道 Activity 和 Activity 之间是如何传递数据的,如果不清楚可以查看:Intent在Android系统的作用

栗子2:Activity和Service传递数据

期待实现的功能:我们修改 activity_main.xml 的布局,在页面增加一些信息输入的控件,然后点击 Button 把页面输入信息通过 Activity 传个 Service。

activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="15dp">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="请输入用户名" />

    <EditText
        android:id="@+id/et_username"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="请选择性别" />

    <RadioGroup
        android:id="@+id/rg_male"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <RadioButton
            android:id="@+id/rb_male"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="" />

        <RadioButton
            android:id="@+id/rb_female"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="" />

    </RadioGroup>

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="请输入年龄" />

    <EditText
        android:id="@+id/et_age"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:inputType="number" />

    <Button
        android:id="@+id/btn_submit"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="提交" />

</LinearLayout>

MainActivity.java

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    private EditText etUserName;
    private RadioButton rbGenderMale;
    private EditText etAge;
    private Button btnSubmit;

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

        etUserName = findViewById(R.id.et_username);
        rbGenderMale = findViewById(R.id.rb_male);
        etAge = findViewById(R.id.et_age);
        btnSubmit = findViewById(R.id.btn_submit);
        btnSubmit.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        Toast.makeText(this, "clicked", Toast.LENGTH_SHORT).show();
        String username = etUserName.getText().toString().trim();
        String gender = rbGenderMale.isChecked() ? "男" : "女";
        int age = Integer.parseInt(etAge.getText().toString());

        Intent intent = new Intent(this, WorkService.class);
        intent.putExtra("_username", username);
        intent.putExtra("_gender", gender);
        intent.putExtra("_age", age);
        startService(intent);
    }
}

修改刚才的 WorkService,仅修改 onStartCommand() 方法即可。其中 WorkService 的onStartCommand()方法的第一个参数就是Intent直接取值即可。

WorkService

@Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d("Service", "WorkService@" + hashCode() + ".onStartCommand()");
        String u = intent.getStringExtra("_username");
        String g = intent.getStringExtra("_gender");
        int a = intent.getIntExtra("_age", 0);

        Log.d("Service", "姓名:" + u + " 性别:" + g + " 年龄:" + a);

        return super.onStartCommand(intent, flags, startId);
    }

运行程序:
在这里插入图片描述

Service粘性

Service 的粘性表现为当 Service 意外终止后,在一定时间后会自动重新启动

Service是否粘性,由 onStartCommand() 方法的返回值决定,取值可以是

  • Service.START_STICKY–>粘性
  • Service.START_NOT_STICKY–>非粘性
  • Service.START_STICKY_COMPATIBILITY–>兼容模式粘性
  • Service.START_REDELIVER_INTENT–>粘性的,且重启时还拥有此前的 Intent 数据(重新传递 Intent )

【小结】
如果希望 Service 是非粘性的,取值为 Service.START_NOT_STICKY
如果希望 Service 是粘性的,则使用父类方法返回值

如果 Service 是粘性的,默认情况下,每次自动重启时,并不会携带 Intent 对象,即自动重启时,第一个参数 Intent,为null。

如果希望 Service 是粘性的,且自动重启时还拥有此前的 Intent 数据,则取值为Service.START_REDELIVER_INTENT

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值