头像更新前后端交互逻辑可参考头像更新前后端整体时序图 ;这里主要描述客户端实现头像更新的流程
一.头像监听更新整体流程
1.同一个群/用户不同地方展示的不同AvatarComponent只会生成一个头像更新的监听者。避免监听者大量生成造成内存浪费,同时也能保证每个群/用户的单次头像数据更新逻辑只会执行一次缓存清理,数据更新逻辑。
2.头像更新监听器只负责更新用户/群头像的数据信息(比如用户信息表用户头像字段的网络地址或者群信息表的群头像字段的网络地址);清理旧的头像图片二级缓存。不负责新的头像图片的加载/缓存处理,新的头像图片的加载/缓存仍然走的AvatarComponent自己原有的加载缓存逻辑。
3.AvatarComponent添加头像更新的监听示例代码如下:
initUpdateListener(){
if (this.avatarInterface == null) {
return
}
const listener = AvatarUpdateListenerManager.getInstance().getUpdateListenerFor(this.avatarInterface)
listener?.appendUpdateCallBack((avatarInterface:AvatarBaseInterface)=>{
this.composeAvatarSrc()
})
}
4.监听者映射表生成示例代码如下:
public getUpdateListenerFor(avatarInterface: AvatarBaseInterface): AvatarUpdateListener | undefined {
if (avatarInterface instanceof UserAvatarInterface) {
const key = /////
let listener: AvatarUpdateListener | undefined = this.listenerMap.get(key)
if (listener == undefined) {
listener = new UserAvatarListener(avatarInterface)
this.listenerMap.set(key, listener)
}
return listener
} else if (avatarInterface instanceof GroupAvatarInterface) {
let key = ////
let listener: AvatarUpdateListener | undefined = this.listenerMap.get(key)
if (listener == undefined) {
listener = new GroupAvatarListener(avatarInterface)
this.listenerMap.set(key, listener)
}
return listener
}
return undefined
}
二.用户头像更新实现
每个用户头像更新的逻辑都有一个自己的UserAvatarListener。UserAvatarListener负责三种情景的用户头像更新:
1.用户主动变更自己的头像后,主动刷新客户端自己已展示AvatarComponent
2.监听其他用户变更了头像的push通知,主动刷新该用户已展示的AvatarComponent
3.进入其他用户主页,强刷用户信息后,比对用户信息的头像字段有更新时,主动刷新该用户已展示的AvatarComponent
下面的时序图描述了以上三种请求的用户头像更新逻辑:
三.群头像更新实现
每一个群Id对应的所有群头像AvatarComponent更新逻辑由专门的GroupAvatarListener负责控制。GroupAvatarListener的职责比较简单只需要注册一个observer到IMManager.getGroupManager中心,监听群成员/群信息变更。然后通知对应的群头像组件(AvatarComoponent)。重新获取最新的群信息里面的群头像photo字段后。扔给ImageKnife去加载展示即可。
四.面向切片编程实现用户头像数据更新与用户头像UI更新彻底解耦合
实现代码如下:
interface UserInfo{
uid:string,
name:string
photo:string,
}
interface UserCacheUpdateInterceptor {
willCacheUserInfo(user:UserInfo):void
didCacheUserInfo(user:UserInfo):void
}
class UserCacheManager {
private interceptors:UserCacheUpdateInterceptor[] = []
addInterceptor(interceptor:UserCacheUpdateInterceptor) {
this.interceptors.push(interceptor)
}
updateUserInfo(user:UserInfo) {
this.interceptors.forEach(value=>{
value.willCacheUserInfo(user)
})
//TODO:1.更新用户信息的内存缓存;2.更新用户信息的本地数据库缓存
this.interceptors.forEach(value=>{
value.didCacheUserInfo(user)
})
}
getUserInfo(uid:string):UserInfo|undefined {
return undefined
}
}
const DefaultUserCache = new UserCacheManager()
export class UserAvatarListener implements UserCacheUpdateInterceptor {
private uid:string = ''
private userInfo?:UserInfo
constructor() {
this.userInfo = DefaultUserCache.getUserInfo(this.uid)
DefaultUserCache.addInterceptor(this)
}
didCacheUserInfo(user:UserInfo):void{
if (this.userInfo?.photo != user.photo) {
//头像变更了通知头像组件刷新
}
}
willCacheUserInfo(user: UserInfo): void {
}
}