Android 音乐APP(六)Activity和Notification通讯(1)

liveDataMap.put(key,new BusMutableLiveData());

}

return (BusMutableLiveData) liveDataMap.get(key);

}

public static class BusMutableLiveData extends MutableLiveData {

//是否需要粘性事件

private boolean isHad = false;

//重写observe的方法

public void observe(@NonNull LifecycleOwner owner, boolean isHad,@NonNull Observer<? super T> observer) {

if(isHad){

this.isHad = true;

}else{

this.isHad = false;

}

this.observe(owner,observer);

}

//重写observe的方法

@Override

public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {

super.observe(owner, observer);

//改变observer.mLastVersion >= mVersion这个判断 然后拦截onChanged

try {

if(this.isHad){

hook((Observer) observer);

}

} catch (Exception e) {

e.printStackTrace();

}

}

/**

  • hook方法 hook系统源码 改变系统的一些参数

  • @param observer

*/

private void hook(Observer observer) throws Exception {

//获取到LiveData的类对象

Class liveDataClass = LiveData.class;

//获取到mObservers的反射对象

Field mObserversField = liveDataClass.getDeclaredField(“mObservers”);

//让mObserversField可以被访问

mObserversField.setAccessible(true);

//获取到这个mObserversField的值

Object mObservers = mObserversField.get(this);

//获取到mObservers的get方法的反射对象

Method get = mObservers.getClass().getDeclaredMethod(“get”, Object.class);

//设置这个反射对象可以被访问

get.setAccessible(true);

//执行这个方法 得到Entry

Object invokeEntry = get.invoke(mObservers, observer);

//定义一个空的对象 LifecycleBoundObserver

Object observerWrapper = null;

if(invokeEntry!=null && invokeEntry instanceof Map.Entry){

observerWrapper = ((Map.Entry)invokeEntry).getValue();

}

if(observerWrapper == null){

throw new NullPointerException(“ObserverWrapper不能为空”);

}

//获取到ObserverWrapper的类对象

Class<?> superclass = observerWrapper.getClass().getSuperclass();

//获取搭配这个类中的mLastVersion成员变量

Field mLastVersionField = superclass.getDeclaredField(“mLastVersion”);

mLastVersionField.setAccessible(true);

//获取到mVersion的反射对象

Field mVersionField = liveDataClass.getDeclaredField(“mVersion”);

//打开权限

mVersionField.setAccessible(true);

//得到的就是mVersion在当前类中的值

Object o = mVersionField.get(this);

//把它的值给mLastVersion

mLastVersionField.set(observerWrapper,o);

}

}

}

这里面的代码是我在第一次听课的过程中一步一步写的,整体的思路并不是我想的,也可以说是学习了。上面的代码也都有注释,就不过多解释了,下面看怎么去用,首先通过通知栏控制Activity,也就是页面,下面我就都用页面二字代替Activity了。说白了其中的思路就是当我点击了通知栏上的某一个按钮的时候,服务会知道这个事情,因为之前注册了广播,但是页面怎么知道这个事情呢,所以其实就是要让服务去告诉页面,我当前点击了通知栏上某一个按钮。然后页面就去做出相应的操作,在这里服务是被观察者,而页面是观察者,所以我们可以在服务中安插一个卧底,让它告诉我们通知栏干了啥事。这么一想思路就很清晰了,下面来看具体的实现。

进入MusicService中,

/**

  • 通知栏控制Activity页面UI

*/

private LiveDataBus.BusMutableLiveData activityLiveData;

创建对象,传入String就代表接收的也是String,这里你可以传递任何类型的数据。

然后要在onCreate进行实例化。

activityLiveData = LiveDataBus.getInstance().with(“activity_control”, String.class);

这样,卧底就安插好了,下面就是要告诉卧底什么时候要给页面传递消息了。

在这里插入图片描述

首先当然是播放了,注意上图中红色方框中的代码,postValue就是发送消息,PLAY是在Constant中定义的全局变量。就是告诉页面,我当前的音乐开始播放了。

在这里插入图片描述

当我点击通知的播放按钮时回调用这个方法,那么在这个方法里面首先控制了通知栏本身的按钮UI,于是我再加上对页面的控制,就是一举两得。

在这里插入图片描述

关闭通知栏的时候也要告诉页面,这个时候页面上的UI也要做出改变,

在这里插入图片描述

在这里插入图片描述

下一首和上一首都要通知页面,到这里该告诉页面的信息都说了,再说的话卧底可能就要暴露了,不太好吧。既然卧底的消息都发出去了,那么页面怎么做出相应的改变呢?进入MainActivity。

/**

  • 当Service中通知栏有变化时接收到消息

*/

private LiveDataBus.BusMutableLiveData activityLiveData;

创建对象,然后在initData中调用notificationObserver方法对服务发送过来的消息进行处理。

在这里插入图片描述

notificationObserver的代码如下:

/**

  • 通知栏动作观察者

*/

private void notificationObserver() {

activityLiveData = LiveDataBus.getInstance().with(“activity_control”, String.class);

activityLiveData.observe(MainActivity.this, true, new Observer() {

@Override

public void onChanged(String state) {

switch (state) {

case PLAY:

btnPlay.setIcon(getDrawable(R.mipmap.icon_pause));

btnPlay.setIconTint(getColorStateList(R.color.gold_color));

changeUI(musicService.getPlayPosition());

break;

case PAUSE:

case CLOSE:

btnPlay.setIcon(getDrawable(R.mipmap.icon_play));

btnPlay.setIconTint(getColorStateList(R.color.white));

changeUI(musicService.getPlayPosition());

break;

case PREV:

BLog.d(TAG, “上一曲”);

changeUI(musicService.getPlayPosition());

break;

case NEXT:

BLog.d(TAG, “下一曲”);

changeUI(musicService.getPlayPosition());

break;

default:

break;

}

}

});

}

② Activity控制通知栏


在上面我通过在服务中安插卧底得知通知栏的一些机密信息,那么通知栏也不是省油的灯,也可以安插卧底在Activity中,得知页面的信息,然后更好的伪装自己。再次之前,首先要添加一个依赖。打开app下的build.gradle,在dependencies闭包中添加如下依赖库,然后Sync

//Service中使用lifecycle

implementation “androidx.lifecycle:lifecycle-service:2.2.0”

到这一步就先不管这个了。还是在MainActivity中,

/**

  • 当在Activity中做出播放状态的改变时,通知做出相应改变

*/

private LiveDataBus.BusMutableLiveData notificationLiveData;

然后在initData中,增加一个notification_control的标识key

在这里插入图片描述

目前我只是通过MainActivity的底部播放按钮开始播放音乐,这个时候时候通知栏有变化,但是如果这时再点击一次按钮,就是暂停了,而不是重新播放,暂停后再点就是继续播放。所以要在底部按钮的点击事件中,发送一个消息过去。

在这里插入图片描述

下面进入到MusicService。

/**

  • Activity控制通知栏UI

*/

private LiveDataBus.BusMutableLiveData notificationLiveData;

然后在MusicServiceonCreate方法中调用activityObserver方法

在这里插入图片描述

再写这个方法之前,先修改一些MusicService继承的Service,改成LifecycleService,如果你没有这个类就说明你的依赖库没有加进来。

在这里插入图片描述

然后

在这里插入图片描述

下面写这个activityObserver方法,代码如下:

/**

  • Activity的观察者

*/

private void activityObserver() {

notificationLiveData = LiveDataBus.getInstance().with(“notification_control”, String.class);

notificationLiveData.observe(MusicService.this, new Observer() {

@Override

public void onChanged(String state) {

//UI控制

UIControl(state, TAG);

}

});

}

也是比较的简单因为它和通知栏相应时传递的值是一样的,所以可以复用UIControl方法,这样环节就走通过了。

在这里插入图片描述

很明显,无论是通过页面操作通知栏还是通知栏操作页面,都搞定了。

③ Activity获取后台音乐播放进度


这个播放进度相信不会陌生,因为之前在LocalMusicActivity中时就已经实现了这个通过,不过当时是只在当前的的Activity中实现的,现在是要获取到后台播放音乐的MediaPlayer的当前播放音乐的进度,所以有些不同,还记得当时安插的卧底吗,可以再给它一个任务,让它在进度变化时发送一个消息给页面,这样就可以了。那么怎么来做呢?可以把之前在LocalMusicActivity中的两个方法复制到MusicService中,然后再稍加改动即可。

private Handler mHandler = new Handler(new Handler.Callback() {

@Override

public boolean handleMessage(Message message) {

//进度发生改变时,

activityLiveData.postValue(PROGRESS);

//更新进度

updateProgress();

return true;

}

});

/**

  • 更新进度

*/
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

img

img

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

最后

想要了解更多关于大厂面试的同学可以点赞支持一下,除此之外,我也分享一些优质资源,包括:Android学习PDF+架构视频+源码笔记高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料 这几块的内容。非常适合近期有面试和想在技术道路上继续精进的朋友。

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

551)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

[外链图片转存中…(img-Oij4tdeO-1713771972552)]

最后

想要了解更多关于大厂面试的同学可以点赞支持一下,除此之外,我也分享一些优质资源,包括:Android学习PDF+架构视频+源码笔记高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料 这几块的内容。非常适合近期有面试和想在技术道路上继续精进的朋友。

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值