Android切面实践
2020-03-12 本文已影响0人
sgfb
开篇
首先这不是一篇教程,更像是开发过程中的随笔所以建议抱着讨论与批评的态度观看
切面编程的基础概念我这里不做介绍,请自行搜索学习。
在Android中比较少使用到切面编程相关,在自行摸索了一段时间之后整理了点概念和一些实用性的功能,
目前的感觉是在Android中切面编程主要职责并不是单纯为简化代码(当然部分功能可以简化代码),简化代码应该是方法封装去做的。而切面是简化逻辑,把技术相关的逻辑都封装了再配合方法简化缩短实际代码,这样剩下的都是真实的业务层逻辑和代码。
在这里抛出一个使用切面优化案例:拍照上传用户新头像且立即保存
这个需求至少看起来很简单,但是几个技术细节会增加实际代码的复杂度。
首先拍照就需要运行时权限,
然后调起照相机拍照,
再然后调用上传文件接口(返回得到图片地址),
最后调用修改用户头像接口。
以上是整条逻辑都是成功的情况,如果考虑到失败的情况可以有8种走向,而且这4个步骤都需要回调所以逻辑和代码必然有冗余。
一个简化版实现(使用第三方辅助,未处理错误等逻辑)
使用了3个第三方
1.权限请求(com.yanzhenjie:permission)
2.网络请求及异步辅助(retrofit+rx+okhttp)
3.照片请求(com.github.LuckSiege.PictureSelector:picture_library)
/**
* 请求权限
*/
private void requestPermission(){
Options permissionHelp=AndPermission.with(TakePictureDemoActivity.this);
permissionHelp.runtime()
.permission(Manifest.permission.CAMERA)
.onGranted(data -> {
getImageFromCamera();
})
.onDenied(data -> {
//提示请求权限
})
.start();
}
/**
* 调用照相机取得照片
*/
private void getImageFromCamera(){
PictureSelector.create(TakePictureDemoActivity.this)
.openCamera(PictureMimeType.ofImage())
.forResult(new OnResultCallbackListener() {
@Override
public void onResult(List<LocalMedia> result) {
uploadAvatarAndChangeAvatar(result.get(0).getPath());
}
@Override
public void onCancel() {
}
});
}
/**
* 上传头像并且得到返回的头像url后调用接口修改头像地址
*/
private void uploadAvatarAndChangeAvatar(String avatarPath){
RequestBody file=RequestBody.create(MediaType.parse("image/jpg"),new File(avatarPath));
MultipartBody.Part part=MultipartBody.Part.createFormData("file","image.jpg",file);
mInterface.uploadFile(part)
.flatMap((Func1<Response<String>, Observable<Response<Boolean>>>) stringResponse -> mInterface.updateUserAvatar(stringResponse.data))
.subscribe(new Action1<Response<Boolean>>() {
@Override
public void call(Response<Boolean> booleanResponse) {
if(booleanResponse.data)
System.out.println("头像修改成功");
}
});
}
首先是一屏高的长度显的略长,其次使用了3个方法意味着以后维护时需要跳转3次去读这些代码,并且每个方法中都使用了回调增加了阅读理解成本
使用切面后实现同样功能
private void changeAvatar(){
//使用照相机拍照获取返回的照片
String imagePath=mController.getImageFromCamera();
//上传照片并得到返回的url
String imageUrl=mController.uploadFile(new File(imagePath));
//调用接口修改头像地址
mController.changeAvatar(imageUrl);
}
//////////Controller切面实现
@GetImageFromCamera
public String getImageFromCamera(){
return "";
}
public String uploadFile(File file){
return mInterface.uploadFile(file);
}
public boolean changeAvatar(String avatarUrl){
return mInterface.changeAvatar(avatarUrl);
}
首先代码量减少,且重点逻辑变成顺序执行而不是原先的套娃形式。抽出了高级抽象作为主执行,而实际进行具体处理的是小弟Controller这也的拆分设计也很比较合理。

最后
在之后文章中我会解释如何具体实现本篇提及的切面功能。