0
点赞
收藏
分享

微信扫一扫

【达内课程】Service(上)

天际孤狼 2022-06-06 阅读 75


文章目录

  • ​​进程优先级​​
  • ​​Service使用​​
  • ​​Service生命周期​​
  • ​​Activity和Service传递数据​​
  • ​​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(上)_android
当启动一个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_02

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 条评论