进程的概念
Android下四大组件都是运行在主线程中的
服务是在后台运行,没有界面
进程的优先级:
Foreground process(最高):前台进程,优先级最高,相当于activity执行了onResume方法,用户正在交互
visible process:可视进程,一直影响用户看得见,相当于activity执行了onpause方法
service process:服务进程,通过startservice方法开启了一个服务
background process:后台进程,相当于activity执行了onstop方法,界面不可见,但是activity并没有被销毁
empty process(最低):空进程,不会维持任何组件运行
start开启服务的特点
第一次点击按钮开启服务,服务执行oncreate方法和onstart方法
第二次点击按钮再次开启服务,服务执行onstart方法
服务一旦被开启,就会在后台长期运行,直到用户手动停止
bindservice开启服务的特点
第一次点击按钮,会执行服务的onCreate方法和onBind方法
当onBind方法返回为null时,onServiceConnected方法不执行
第二次点击按钮时,服务没有响应
和activity共生死,一旦activity被销毁,它也会被销毁
服务不可以多次解绑,多次解绑会报异常
通过bind方式开启服务,服务不能在设置页面找到,相当于一个隐形的服务
为什么要引入bindservice
目的是为了调用服务里的方法
实现过程:
在服务的内部定义一个方法,让activity去调用
在服务内定义一个中间人对象
把我定义的中间人对象在onbind方法里进行返回
在mainactivity的oncreate方法里调用bindservice的目的是为了获取我们定义的中间人对象
获取中间人对象
拿到中间人对象就可以间接调用服务里的方法
当activity销毁的时候解绑服务
通过接口的方式调用服务里的方法
接口可以隐藏代码内部的细节,让程序员暴露自己只想暴露的方法
过程:
定义一个接口,把想暴露的方法定义在接口里面
我们定义的中间人对象实现我们自己定义的接口
在获取中间人(ibind)对象的时候用接口类型
混合方式开启服务
需求:既想让服务在后台长期运行,也想调用服务里面的方法
步骤:
先调用startservice方法开启服务,能够保证服务在后台长期运行
调用bindservice方法获取中间人对象
调用unbindservice解绑服务
调用stopservice摧毁服务
具体代码:播放音乐
package com.dsl.a7_musicbaidu;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import android.Manifest;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.view.View;
import android.widget.SeekBar;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
IsService myBinder;
Myconn conn;
static SeekBar seekBar;
public static Handler handler = new Handler() {
@Override
public void handleMessage(@NonNull Message msg) {
Bundle data = msg.getData();
int duration = data.getInt("duration");
int currentPosition = data.getInt("currentPosition");
seekBar.setMax(duration);
seekBar.setProgress(currentPosition);
super.handleMessage(msg);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent(this, MusicService.class);
startService(intent);
conn = new Myconn();
bindService(intent, conn, BIND_AUTO_CREATE);
seekBar = findViewById(R.id.seekBar);
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar1) {
myBinder.callSeekTo(seekBar1.getProgress());
}
});
}
@Override
protected void onDestroy() {
unbindService(conn);
super.onDestroy();
}
public void start(View v) {
if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, 1);
} else {
play_music();
}
}
public void pause(View v) {
myBinder.callPause();
}
public void reset(View v) {
myBinder.callReplay();
}
public void play_music() {
myBinder.callPlay();
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
switch (requestCode) {
case 1:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
play_music();
} else {
Toast.makeText(this, "你拒绝了权限", Toast.LENGTH_SHORT).show();
}
break;
default:
break;
}
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
public class Myconn implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
myBinder = (IsService) service;
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
}
}
package com.dsl.a7_musicbaidu;
import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Message;
import java.io.IOException;
import java.util.Timer;
import java.util.TimerTask;
public class MusicService extends Service {
MediaPlayer mediaPlayer;
public MusicService() {
}
@Override
public IBinder onBind(Intent intent) {
return new MyBinder();
}
@Override
public void onCreate() {
mediaPlayer = new MediaPlayer();
super.onCreate();
}
public void playMusic() {
try {
mediaPlayer.reset();
mediaPlayer.setDataSource("mnt/sdcard/abc.mp3");
mediaPlayer.prepare();
mediaPlayer.start();
updateseekBar();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("音乐播放了");
}
private void updateseekBar() {
final int duration = mediaPlayer.getDuration();
final Timer timer = new Timer();
final TimerTask timerTask = new TimerTask() {
@Override
public void run() {
int currentPosition = mediaPlayer.getCurrentPosition();
Message message = Message.obtain();
Bundle bundle = new Bundle();
bundle.putInt("duration", duration);
bundle.putInt("currentPosition", currentPosition);
message.setData(bundle);
MainActivity.handler.sendMessage(message);
}
};
timer.schedule(timerTask, 100, 1000);
mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
System.out.println("歌曲播放完成了呢");
timer.cancel();
timerTask.cancel();
}
});
}
public void pauseMusic() {
mediaPlayer.pause();
System.out.println("音乐暂停了");
}
public void replayMusic() {
mediaPlayer.start();
System.out.println("音乐继续播放了");
}
public void seekTo(int position) {
mediaPlayer.seekTo(position);
}
private class MyBinder extends Binder implements IsService {
@Override
public void callPlay() {
playMusic();
}
@Override
public void callPause() {
pauseMusic();
}
@Override
public void callReplay() {
replayMusic();
}
@Override
public void callSeekTo(int position) {
seekTo(position);
}
}
}
package com.dsl.a7_musicbaidu;
public interface IsService {
void callPlay();
void callPause();
void callReplay();
void callSeekTo(int position);
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="start"
android:text="播放" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="pause"
android:text="暂停" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="reset"
android:text="继续播放" />
<SeekBar
android:id="@+id/seekBar"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
案例一:为什么要引入bindservice
- 在服务内定义一个类继承Binder
public class MyBinder extends Binder{
public void callMethod(int money){
method1(money);
}
}
- 将定义的MyBinder类在服务里的onBind方法内返回
public class TestService extends Service {
public TestService() {
}
@Override
public IBinder onBind(Intent intent) {
return new MyBinder();
}
public void method1(int money){
if (money>1000){
Toast.makeText(getApplicationContext(),"请帮我把证件办了",Toast.LENGTH_SHORT).show();
}else{
Toast.makeText(getApplicationContext(),"这点钱,你想办事?",Toast.LENGTH_SHORT).show();
}
}
}
- 在MainActivity 中定义类获取MyBinder对象
private class Myconn implements ServiceConnection{
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
myBinder = (TestService.MyBinder) service;
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
}
- 在MainActivity 的onCreate方法中开启服务
Intent intent = new Intent(this, TestService.class);
conn = new Myconn();
bindService(intent,conn,BIND_AUTO_CREATE);
- 利用中间人对象掉服务里的方法
public void click(View v){
myBinder.callMethod(200);
}
- onDestory方法关闭服务
@Override
protected void onDestroy() {
unbindService(conn);
super.onDestroy();
}
案例二:通过接口的方式调用服务里的方法
- 将服务想要暴露的方法,放在一个接口中
package com.dsl.interfaceservice;
public interface IsService {
void callMethod(int money) ;
}
- 让自己定义的Mybinder对象继承Binder 类,并实现这个接口
private class MyBinder extends Binder implements IsService{
public void callMethod(int money) {
method1(money);
}
public void callplay() {
play();
}
public void callwork() {
work();
}
}
- 其他的就和继承的方法一样了