黑马Android76期学习笔记01基础--day08--start/bind开启服务、电话录音,特别广播接收者,bindService/接口调用服务内方法,混合开启服务,进程间通讯,aidl应用场景
1.进程的基本概念
1、android下四大组件都是运行在主线程中,他没有界面,在后台运行
2、Foreground process前台进程,优先级最高,相当于activity执行了onresume方法,用户正在交互
3、visible process可视进程,一直影响用户看得见的体验,相当于activity执行了onpause方法
4、service process服务进程,通过startService开启一个服务
5、backgroud process后台进程 相当于activity执行了onStop方法,界面不可见,但是activity并没有被销毁
6、empty process 空进程 ,不会维持任何组件运行,但会占用内存
2.start方式开启服务
需要在清单文件中注册
1、定义四大组件的方式是一样的
2、定义一个类继承Service
3、服务一旦被开启,就会在后台长期运行,知道用户手工停止
1、DemoService
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
import androidx.annotation.Nullable;
public class DemoService extends Service {
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
Log.d("TAG", "onCreate: --------");
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d("TAG", "onStartCommand: --------");
return super.onStartCommand(intent, flags, startId);
}
}
2、MainActivity
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void btnStratClick(View view){
Intent intent=new Intent(this,DemoService.class);
startService(intent);
//stopService(intent);
}
}
打印
2020-08-22 10:46:19.280 4264-4264/com.fengray.ex066 D/TAG: onCreate: --------
2020-08-22 10:46:19.281 4264-4264/com.fengray.ex066 D/TAG: onStartCommand: --------
2.电话监听案例
开启电话状态监听许可
**1、清单文件**<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.fengray.ex067">
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".PhoneService">
</service>
</application>
</manifest>
2、PhoneService类
package com.fengray.ex067;
import android.annotation.SuppressLint;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.util.Log;
import androidx.annotation.Nullable;
public class PhoneService extends Service {
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
//获得telephonemanager的实例
@SuppressLint("ServiceCast")
TelephonyManager telephonyManager=(TelephonyManager)getSystemService(TELECOM_SERVICE);
//注册电话的监听
telephonyManager.listen(new MyPhoneStateListener(),PhoneStateListener.LISTEN_CALL_STATE);
super.onCreate();
}
@Override
public void onDestroy() {
super.onDestroy();
}
//定义类来监听电话的状态
private class MyPhoneStateListener extends PhoneStateListener{
//当电话设置状态发生改变时调用
@Override
public void onCallStateChanged(int state, String phoneNumber) {
//判断一下电话的状态
switch (state){
case TelephonyManager.CALL_STATE_IDLE://空闲
break;
case TelephonyManager.CALL_STATE_OFFHOOK://摘机
break;
case TelephonyManager.CALL_STATE_RINGING://响铃
Log.d("TAG", "onCallStateChanged: 准备录音");
break;
}
super.onCallStateChanged(state, phoneNumber);
}
}
}
3、MainActivity
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import android.os.SystemClock;
import android.util.Log;
import android.view.View;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void btnstart(View view){
Intent intent=new Intent(this,PhoneService.class);
startService(intent);
}
}
3.电话录音
1、清单文件设置服务和广播以及各种权限(andorid6以后有新的要求,需要先询问)
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.fengray.ex067">
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".PhoneService">
</service>
<receiver android:name=".BootReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
</receiver>
</application>
</manifest>
2、BootReceiver 类继承BroadcastReceiver
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
public class BootReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
//把服务开启
Intent intent1=new Intent(context,PhoneService.class);
context.startService(intent1);
}
}
**3、PhoneService 类继承Service **
public class PhoneService extends Service {
MediaRecorder recorder=null;
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
//获得telephonemanager的实例
@SuppressLint("ServiceCast")
TelephonyManager telephonyManager=(TelephonyManager)getSystemService(TELECOM_SERVICE);
//注册电话的监听
telephonyManager.listen(new MyPhoneStateListener(),PhoneStateListener.LISTEN_CALL_STATE);
super.onCreate();
}
@Override
public void onDestroy() {
super.onDestroy();
}
//定义类来监听电话的状态
private class MyPhoneStateListener extends PhoneStateListener{
//当电话设置状态发生改变时调用
@Override
public void onCallStateChanged(int state, String phoneNumber) {
//判断一下电话的状态
switch (state){
case TelephonyManager.CALL_STATE_IDLE://空闲
if (recorder!=null){
//停止录音
recorder.stop();
recorder.reset(); // You can reuse the object by going back to setAudioSource() step
recorder.release(); // Now the object cannot be reused
}
break;
case TelephonyManager.CALL_STATE_OFFHOOK://摘机
recorder.start(); // Recording is now started
break;
case TelephonyManager.CALL_STATE_RINGING://响铃
//拿到媒体录音对象
recorder=new MediaRecorder();//创建recorder实例
//设置音频的来源
recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
//设置输出格式
recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
//设置音频的编码方式
recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
//设置存放的路径
recorder.setOutputFile("/mnt/sdcard/luyin.3gp");
//准备录音
try {
recorder.prepare();
} catch (IOException e) {
e.printStackTrace();
}
break;
}
super.onCallStateChanged(state, phoneNumber);
}
}
}
**4、MainActivity类 **
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
4.注册特别的广播接受者(特别频繁的操作,如解锁屏)
1、写一个广播类,编写广播接收业务逻辑
2、写一个服务,用来注册广播接受者
3、在主类中的oncreate方法中开启服务
4、配置清单文件
1、ScreenReceiver 类
package com.fengray.ex068;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
public class ScreenReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
//获得当前事件类型
String action=intent.getAction();
if ("android.intent.action.SCREEN_OFF".equals(action)){
Log.d("TAG", "说明屏幕锁屏了");
}else if ("android.intent.action.SCREEN_ON".equals(action)){
Log.d("TAG", "说明屏幕解锁了 ");
}
}
}
2、ScreenService 类
package com.fengray.ex068;
import android.app.Service;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.IBinder;
import androidx.annotation.Nullable;
public class ScreenService extends Service {
ScreenReceiver screenReceiver;
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
//在这里通过代码的方式来注册广播(因为是特殊的广播接收者)
//创建screenReceiver实例
screenReceiver=new ScreenReceiver();
//创建IntentFilter实例,其目的是为了添加action
IntentFilter intentFilter=new IntentFilter();
//添加action
intentFilter.addAction("android.intent.action.SCREEN_OFF");
intentFilter.addAction("android.intent.action.SCREEN_ON");
//动态接收广播接受者
registerReceiver(screenReceiver,intentFilter);
super.onCreate();
}
@Override
public void onDestroy() {
unregisterReceiver(screenReceiver);
super.onDestroy();
}
}
3、MainActivity 主类
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//创建一个指向Service页面的intent,由于service*面,所以实际上就是做启动服务的准备
Intent intent=new Intent(this,ScreenService.class);
//开启服务
startService(intent);
}
}
4、清单文件
其实就是注册服务
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.fengray.ex068">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".ScreenService">
</service>
</application>
</manifest>
打印:
2020-08-22 21:08:32.064 8665-8665/com.fengray.ex068 D/TAG: 说明屏幕锁屏了
2020-08-22 21:08:33.623 8665-8714/com.fengray.ex068 D/EGL_emulation: eglMakeCurrent: 0x7aabda840540: ver 3 1 (tinfo 0x7aabda80dba0)
2020-08-22 21:08:33.656 8665-8665/com.fengray.ex068 D/TAG: 说明屏幕解锁了
2020-08-22 21:08:37.711 8665-8714/com.fengray.ex068 D/EGL_emulation: eglMakeCurrent: 0x7aabda840540: ver 3 1 (tinfo 0x7aabda80dba0)
2020-08-22 21:08:37.798 8665-8665/com.fengray.ex068 D/TAG: 说明屏幕锁屏了
2020-08-22 21:08:39.963 8665-8665/com.fengray.ex068 D/TAG: 说明屏幕解锁了 、
5.通过bind添加服务
1、服务不能多次解绑
2、onbind方法返回null是,onServiceconnected方法是不执行的
3、通过bind方式开启服务,服务不能再设置页面找到,相当于一个隐形的服务
1、DemoService
public class DemoService extends Service {
@Nullable
@Override
//当绑定服务的时候
public IBinder onBind(Intent intent) {
Log.d("TAG", "onBind: -------");
return null;//返回null则表示这个方法不执行
}
@Override
public void onCreate() {
Log.d("TAG", "onCreate: ----");
super.onCreate();
}
@Override
public void onDestroy() {
Log.d("TAG", "onDestroyAndUnbindService: ----");
super.onDestroy();
}
}
2、MainActivity
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.util.Log;
import android.view.View;
public class MainActivity extends AppCompatActivity {
private Myconn conn;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override
protected void onDestroy() {
unbindService(conn);
super.onDestroy();
}
//点击绑定服务按钮
public void btnBindClick(View view){
Intent intent=new Intent(this,DemoService.class);
conn=new Myconn();
//连接到DemoService这个服务
bindService(intent,conn,BIND_AUTO_CREATE);
}
//点击解绑服务按钮
public void btnUnbindClick(View view){
unbindService(conn);
}
//点击启动服务按钮
public void startClick(View view){
Intent intent=new Intent(this,DemoService.class);
startService(intent);
}
private class Myconn implements ServiceConnection{
//当服务连接成功调用
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.d("TAG", "onServiceConnected: -----");
}
//当服务失去连接
@Override
public void onServiceDisconnected(ComponentName name) {
Log.d("TAG", "onServiceDisconnected: ----");
}
}
}
3、清单文件中注册一下服务
<service android:name=".DemoService"></service>
6.通过bindservice方式调用服务内部方法
1、在服务的内部定义一个被调用的方法
2、在服务的内部定义一个中间人对象(IBinder)
3、把定义的中间人对象在onBind方法中返回。
4、在mainactivity的oncreate方法里调用bindservice,其目的是为了获取我们定义的中间人对象
5、获取中间人对象
6、拿到中间人对象,通过中间人对象调用服务内容的方法
7,当activity销毁的时候,要解绑服务
1、清单文件里注册服务
<service android:name=".BanzhengService"></service>
2、BanzhengService 服务类
public class BanzhengService extends Service {
@Nullable
@Override
//把自己定义的中间人对象返回
public IBinder onBind(Intent intent) {
return new MyBinder();
}
//办证方法
public void banzheng(int money){
if (money>1000){
Toast.makeText(getApplicationContext(), "我是领导,把证给办了", Toast.LENGTH_SHORT).show();
}else{
Toast.makeText(getApplicationContext(), "这点钱,还想办事情吗", Toast.LENGTH_SHORT).show();
}
}
//定义一个中间人对象(IBinder)
public class MyBinder extends Binder{
//调用服务里的方法
public void callBanzheng(int money){
banzheng(money);
}
}
}
3、MainActivity类
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;
public class MainActivity extends AppCompatActivity {
private Myconn conn;
BanzhengService.MyBinder myBinder;//自定义的中间人对象
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent=new Intent(this,BanzhengService.class);
conn=new Myconn();
//连接服务
bindService(intent,conn,BIND_AUTO_CREATE);
}
//点击按钮,调用服务里面的方法
public void btnbanzheng(View view){
myBinder.callBanzheng(500);
}
//监视服务的状态
private class Myconn implements ServiceConnection{
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//获取中间人对象
myBinder= (BanzhengService.MyBinder) service;
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
}
@Override
protected void onDestroy() {
unbindService(conn);
super.onDestroy();
}
}
7.通过接口调用服务内部方法
接口可以隐藏代码内部的细节,让程序员暴露自己只想暴露的方法
通过接口调用服务内部方法的步骤
1、定义一个接口,把想暴露的方法都定义在接口里面
2、定义一个中间人对象,实现我们自定义的接口
3、获取中间人对象的
4、调用服务内部方法
1、ImpService 接口
package com.fengray.ex070;
public interface ImpService {
//把想暴露的方法定义在接口里
public void callBanzheng(int money);
}
2、DemoService 类
package com.fengray.ex070;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;
import android.widget.Toast;
import androidx.annotation.Nullable;
public class DemoService extends Service {
@Nullable
@Override
//把自己定义的中间人对象返回
public IBinder onBind(Intent intent) {
return new MyBinder();
}
//办证方法
public void banzheng(int money){
if (money>1000){
Toast.makeText(getApplicationContext(), "我是领导,把证给办了", Toast.LENGTH_SHORT).show();
}else{
Toast.makeText(getApplicationContext(), "这点钱,还想办事情吗", Toast.LENGTH_SHORT).show();
}
}
//打麻将的方法
public void playMaJiang(){
Log.d("TAG", "playMaJiang: 陪领导打麻将");
}
//洗桑拿的方法
public void sangna(){
Log.d("TAG", "playMaJiang: 陪领导洗桑拿");
}
//定义一个中间人对象(IBinder)
private class MyBinder extends Binder implements ImpService{
//调用服务里的方法
public void callBanzheng(int money){
banzheng(money);
}
public void callplayMajiang(){
playMaJiang();
}
public void callsangna(){
sangna();
}
}
}
3、MainActivity 类
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;
public class MainActivity extends AppCompatActivity {
private Myconn conn;
private ImpService myBinder;//自定义的中间人对象
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent=new Intent(this, DemoService.class);
conn=new Myconn();
//连接服务
bindService(intent,conn,BIND_AUTO_CREATE);
}
//点击按钮,调用服务里面的方法
public void btnbanzheng(View view){
//调用服务里面的方法
myBinder.callBanzheng(500);
//myBinder.callplayMajiang();//接口没暴露这个方法因此无法调用
//myBinder.callsangna();//接口没暴露这个方法因此无法调用
}
//监视服务的状态
private class Myconn implements ServiceConnection{
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//获取中间人对象
myBinder= (ImpService) service;
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
}
@Override
protected void onDestroy() {
unbindService(conn);
super.onDestroy();
}
}
8.混合方式开启服务
所谓混合方式是指,既想让服务在后台长期运行,又想调用服务里面的方法
1、先调用startService开启服务,能够保证服务在后台长期运行
2、调用bindService方法,去获取中间人对象
3、调用unbindService解绑服务
4、调用stopService停止服务
9.音乐播放器
1、清单文件里注册服务
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.fengray.ex071music">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".MusicService"></service>
</application>
</manifest>
2、定义接口文件ImpService
package com.fengray.ex071music;
public interface ImpService {
// 暴露方法
public void callPlayMusic();
public void callPauseMusic();
public void callContinueMusic();
}
**3、定义服务文件MusicService **
package com.fengray.ex071music;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;
import androidx.annotation.Nullable;
public class MusicService extends Service {
@Nullable
@Override
//返回我们定义的中间人对象
public IBinder onBind(Intent intent) {
return new MyBinder();
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
public void onDestroy() {
super.onDestroy();
}
//播放音乐方法
public void playMusic(){
Log.d("TAG", "playMusic: 音乐播放了");
}
//暂停播放音乐方法
public void pauseMusic(){
Log.d("TAG", "playMusic: 音乐暂停了");
}
//继续播放音乐方法
public void continueMusic(){
Log.d("TAG", "playMusic: 音乐继续播放了");
}
//在服务的内部定义一个中间人对象(IBinder对象)
private class MyBinder extends Binder implements ImpService{
//调用播放音乐的方法
@Override
public void callPlayMusic() {
playMusic();
}
//调用暂停播放音乐的方法
@Override
public void callPauseMusic() {
pauseMusic();
}
//调用继续播放音乐的方法
@Override
public void callContinueMusic() {
continueMusic();
}
}
}
4、主MainActivity类
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;
public class MainActivity extends AppCompatActivity {
private ImpService impService=null;//定义的中间人对象
private MyConn conn=null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//混合方式开启服务
//先调用startService,保证服务能在后台长期运行
Intent intent=new Intent(this,MusicService.class);
startService(intent);
//调用bindService,目的是为了获取我们定义的中间人对象,这样就可以间接调用服务里面的方法
conn=new MyConn();//conn返回的是IBinder对象,尽管名字是Connection的
bindService(intent, conn,BIND_AUTO_CREATE);
}
public void btnPlay(View view){
impService.callPlayMusic();
}
public void btnPause(View view){
impService.callPauseMusic();
}
public void btnContinue(View view){
impService.callContinueMusic();
}
@Override
protected void onDestroy() {
unbindService(conn);
super.onDestroy();
}
//监听服务的状态
public class MyConn implements ServiceConnection {
@Override
//当服务连接的时候
public void onServiceConnected(ComponentName name, IBinder service) {
impService=(ImpService)service;
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
}
}
10.进程间通讯(aidl)
aidl介绍
本地服务:运行自己应用里面的服务
远程服务:运行在其他应用里面的服务
实现进程间通信(IPC)
aidl:安卓 接口 定义 语言
用来解决进程间通讯的
使用aidl的步骤
1、把Iservice.java文件变成一个aidl为后缀的文件
2、aidl这个语言不认识public,把public去掉
3、自动生成一个iservice.java文件,系统自动帮我们生成了一个类Stub
4、我们自己定义的中间人对象直接继承Stub即可
5、保证2个应用的aidl文件是同一个,保证aidl文件所在的包名相同
6、获取中间人对象的方式不一样
本文地址:https://blog.csdn.net/weixin_43745804/article/details/108163611