一、Service简单概述
Service(服务)是一个一种可以在后台执行长时间运行操作而没有用户界面的应用组件。服务可由其他应用组件启动(如Activity),服务一旦被启动将在后台一直运行,即使启动服务的组件(Activity)已销毁也不受影响。 此外,组件可以绑定到服务,以与之进行交互,甚至是执行进程间通信 (IPC)。 例如,服务可以处理网络事务、播放音乐,执行文件 I/O 或与内容提供程序交互,而所有这一切均可在后台进行,Service基本上分为两种形式:
(比如说播放音乐,你退出APP界面它音乐还是继续在播放)
启动状态 Started Service
当应用组件(如 Activity)通过调用 startService() 启动服务时,服务即处于“启动”状态。一旦启动,服务即可在后台无限期运行,即使启动服务的组件已被销毁也不受影响,除非手动调用才能停止服务, 已启动的服务通常是执行单一操作,而且不会将结果返回给调用方。
比如说音乐播放。
绑定状态 Bound Service
当应用组件通过调用 bindService() 绑定到服务时,服务即处于“绑定”状态。绑定服务提供了一个客户端-服务器接口,允许组件与服务进行交互、发送请求、获取结果,甚至是利用进程间通信 (IPC) 跨进程执行这些操作。 仅当与另一个应用组件绑定时,绑定服务才会运行。 多个组件可以同时绑定到该服务,但全部取消绑定后,该服务即会被销毁。
组件被停止后,绑定的Service也会被停止。
- 有时我们可能需要从Activity组建中去调用Service中的方法,此时Activity以绑定的方式挂靠到Service后,我们就可以轻松地方法到Service中的指定方法),组件(如Activity)可以向Service(也就是服务端)发送请求,或者调用Service(服务端)的方法,此时被绑定的Service(服务端)会接收信息并响应,甚至可以通过绑定服务进行执行进程间通信
- 与启动服务不同的是绑定服务的生命周期通常只在为其他应用组件(如Activity)服务时处于活动状态,不会无限期在后台运行,也就是说宿主(如Activity)解除绑定后,绑定服务就会被销毁。
二、Started Service 项目 MediaPlayer播放音乐
点击开始播放,即可播放音乐,点击停止即可停止播放音乐,点击图标也可以播放音乐
1.创建Service
2.复写方法
onCreate:首次创建服务时,系统将调用此方法来执行一次性设置程序(在调用 onStartCommand() 或 onBind() 之前)。如果服务已在运行,则不会调用此方法。该方法只被调用一次
onStartCommand:每次通过startService()方法启动Service时都会被回调。
onDestroy:服务销毁时的回调
在onCreate中创建MediaPlayer对象,并加载需要播放的音频文件
在onStartCommand中进行player.isPlaying
MusicService完整代码
package com.edu.nchu.lab4exer01;
import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.IBinder;
public class MusicService extends Service {
static boolean isplay;//记录当前播放状态
MediaPlayer player;//MediaPlayer对象
public MusicService() {
}
/**
* 绑定服务时才会调用
* 必须要实现的方法
*/
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
// 重写生命周期中的三个方法
/**
* 首次创建服务时,系统将调用此方法来执行一次性设置程序(在调用 onStartCommand() 或 onBind() 之前)。
* 如果服务已在运行,则不会调用此方法。该方法只被调用一次
*/
@Override
public void onCreate() {
//创建MediaPlayer对象,并加载播放的音频文件
player = MediaPlayer.create(this,R.raw.hellow);
System.out.println("生成对象");
super.onCreate();
}
/**
* 每次通过startService()方法启动Service时都会被回调。
*/
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if(!player.isPlaying()){
// player.isPlaying();
player.start();
// 这里的start是开始播放
// isPlaying是返回播放状态
isplay = player.isPlaying();//设置当前状态为正在播放音乐
System.out.println("开始播放" + isplay);
}
return super.onStartCommand(intent, flags, startId);
}
/**
* 服务销毁时的回调
*/
@Override
public void onDestroy() {
player.stop(); //停止
isplay = player.isPlaying();//设置当前状态为正在播放音乐
System.out.println("开始播放" + isplay);
player.release();//释放资源
super.onDestroy();
}
}
activity_main中的布局代码:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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">
<ImageButton
android:layout_width="100dp"
android:layout_height="100dp"
android:id="@+id/btn_play"
android:src="@drawable/begin"
android:scaleType="centerInside"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true"
/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/begin"
android:text="开始播放我和我的祖国"
android:layout_below="@+id/btn_play"
android:layout_centerHorizontal="true"
/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/end"
android:text="停止播放我和我的祖国"
android:layout_below="@+id/begin"
android:layout_centerHorizontal="true"
/>
</RelativeLayout>
重点是MainActivity中的调用
package com.edu.nchu.lab4exer01;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ImageButton;
public class MainActivity extends AppCompatActivity {
Button button1;
Button button2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//也是通过Intent来进行activi与Service进行绑定
final Intent intent = new Intent(MainActivity.this,MusicService.class);
ImageButton btn_play = findViewById(R.id.btn_play);
button1 = findViewById(R.id.begin);
button2 =findViewById(R.id.end);
btn_play.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if(MusicService.isplay == false){
startService(intent);//开启后台服务
((ImageButton)view).setImageDrawable(getResources().getDrawable(R.drawable.end));
}else {
stopService(intent);
((ImageButton)view).setImageDrawable(getResources().getDrawable(R.drawable.begin));
}
}
});
button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
startService(intent);//播放音乐
// ((ImageButton)view).setImageDrawable(getResources().getDrawable(R.drawable.end));
}
});
button2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
stopService(intent);
// ((ImageButton)view).setImageDrawable(getResources().getDrawable(R.drawable.begin));
}
});
}
}
二、Bound Service 项目 生成随机数
在Service中最重要是是要写一个获取service的方法,MyBinder继承于Binder,重写onBind方法
重写onDestroy方法
BinderService代码
package com.edu.nchu.service_2_boundservice;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class BinderService extends Service {
public BinderService() {
}
public class MyBinder extends Binder {
public BinderService getService(){//创建获取service的方法
return BinderService.this;//返回当前的service类
}
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
// throw new UnsupportedOperationException("Not yet implemented");
return new MyBinder();//返回MyBinder Service对象
}
@Override
public void onDestroy() {
super.onDestroy();
}
// 自定义方法 ,生成随机数
public List getRandomNumber(){
List resArr = new ArrayList();
String strNumber = "";
for(int i = 0; i < 7; i ++){
int number = new Random().nextInt(33)+1;
if(number < 10){
strNumber = "0" + String.valueOf(number);
}else{
strNumber = String.valueOf(number);
}
resArr.add(strNumber);
}
return resArr;
}
}
MainActivity
要定义一个ServiceConnection
具体的绑定操作,也可以不写onstart里,可以通过一个按钮或者啥点击绑定都可以,这里绑定上后就可以使用service中的方法了。
完整代码:
package com.edu.nchu.service_2_boundservice;
import androidx.appcompat.app.AppCompatActivity;
import android.content.ComponentName;
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 {
BinderService binderService;//绑定的service
Button button;
TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button = findViewById(R.id.begin);
textView = findViewById(R.id.tv);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
String a = (String) binderService.getRandomNumber().get(0);
textView.setText("随机数:" + a);
}
});
}
// 这里是service绑定成功后调用的方法
private ServiceConnection coon = new ServiceConnection() {
//这里括号里是就代表要从后台绑定的service
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
binderService = ((BinderService.MyBinder)iBinder).getService();
}
// 这里是service解开绑定后调用的方法
@Override
public void onServiceDisconnected(ComponentName componentName) {
}
};
@Override
protected void onStart() {
super.onStart();
// 在Activity生成的时候进行service的自动绑定
// 也可以不写这里
Intent intent = new Intent(this,BinderService.class);
bindService(intent,coon,BIND_AUTO_CREATE);
}
@Override
protected void onStop() {
// 在Activity销毁的时候进行service的自动绑定
super.onStop();
unbindService(coon);
}
}
布局代码:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/tv"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true"
android:textSize="50dp"
/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/begin"
android:text="生成随机数"
android:layout_below="@+id/tv"
android:layout_centerHorizontal="true"
/>
</RelativeLayout>