第一章:Android开发项目 ---- Module底层依赖封装
目录
系列文章目录
前言
一、Module封装
二、库封装
1.Utils库
2.VideoBase库
总结
前言
随着Android版本不断提升,以前粗放的管理系统逐步进行权限收缩。在一些系统开发中,系统内置应用开发使用调整后的系统API,但同时也有更多网络库不在系统中。系统打包时,又无法像Android Studio一样进行下载依赖,按照build.gradle进行打包。这样就会出现很多麻烦的问题。
一、Module封装将功能类似的代码放置到一个包中,和主体App的包进行区分,进行物理分割。
更好的情况是单独管理Module,App主项目中build.gradle中引入module。或者将module放置到maven仓库中(或者公司私有仓库中),使用网络依赖。
这样既进行了物理区分,也可以进行模块区分,功能区分,互不干扰。一个模块发生故障,不影响其他模块正常运行。具有很高的可扩展行。
二、库封装由于我采用的是Android系统统一编译,生成系统内置app,系统编译过程和gradle编译不一样,所以不能采用网络库。只能进行网络库重写,或者将库下载,放入到libs中,进行引用
1.Utils库基础工具库,不依赖任何第三方包。
自定义工具依赖包中包含:
a、DLog日志输出
public final class DLog {
public static void d() {
printLog(D, null, DEFAULT_MESSAGE);
}
public static void d(Object msg) {
printLog(D, null, msg);
}
public static void d(String tag, Object... objects) {
printLog(D, tag, objects);
}
public static void i() {
printLog(I, null, DEFAULT_MESSAGE);
}
public static void i(Object msg) {
printLog(I, null, msg);
}
public static void i(String tag, Object... objects) {
printLog(I, tag, objects);
}
...
private static void printLog(int type, String tagStr, Object... objects) {
if (!IS_SHOW_LOG) {
return;
}
String[] contents = wrapperContent(STACK_TRACE_INDEX_5, tagStr, objects);
String tag = contents[0];
String msg = contents[1];
String headString = contents[2];
switch (type) {
case V:
case D:
case I:
case W:
case E:
case A:
BaseLog.printDefault(type, tag, headString + msg);
break;
case JSON:
JsonLog.printJson(tag, msg, headString);
break;
case XML:
XmlLog.printXml(tag, msg, headString);
break;
}
}
...
public static void printDefault(int type, String tag, String msg) {
int index = 0;
int length = msg.length();
int countOfSub = length / MAX_LENGTH;
if (countOfSub > 0) {
for (int i = 0; i < countOfSub; i++) {
String sub = msg.substring(index, index + MAX_LENGTH);
printSub(type, tag, sub);
index += MAX_LENGTH;
}
printSub(type, tag, msg.substring(index, length));
} else {
printSub(type, tag, msg);
}
}
private static void printSub(int type, String tag, String sub) {
switch (type) {
case DLog.V:
Log.v(tag, sub);
break;
case DLog.D:
Log.d(tag, sub);
break;
case DLog.I:
Log.i(tag, sub);
break;
case DLog.W:
Log.w(tag, sub);
break;
case DLog.E:
Log.e(tag, sub);
break;
case DLog.A:
Log.wtf(tag, sub);
break;
}
}
}
其中内部最底层实现还是Android原生的Log日志输出,修改了输出样式和效果,并可以输出XML和JSON内容。
b、Task线程任务,替换AsyncTask
参考Bolts源码,进行线程和UI进程的切换功能实现。
c、部分特殊工具
BitmapUtils、图片转换,保存,读取,缩放等功能方法。 DensityUtil、dp和px之间的爱恨情仇。 FileUtil、文件相关 *** 作 . . .
可以在内部增加更多的方法,这里只是罗列了部分方法。
※ 生成jar包
因为Utils这个Module中并没有任何资源文件,可以直接打jar包进行引用。
在Utils目录下找到build.gradle
android {
...
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
task makeJar(type: Copy) {
//删除存在的
//delete 'build/libs/Utils-1.0.0.jar'
//设置拷贝的文件
from('build/intermediates/aar_main_jar/release/')
//打进jar包后的文件目录
into('build/libs/')
//将classes.jar放入build/libs/目录下
//include ,exclude参数来设置过滤
include('classes.jar')
//重命名
rename ('classes.jar', 'Utils-1.0.0.jar')
}
makeJar.dependsOn(build)
}
Android Studio右侧的Gradle找到Utils- --->other ---->makeJar
双击makeJar
生成Utils-1.0.0.jar,复制到app的libs中,即可引用使用。
2.VideoBase库任务功能依赖库,自己封装的功能库,不包含业务逻辑。
由于Android高版本系统下编辑时,无法找到dataBinding。导致一直打包失败。所以,自己封装了一套仿MVVM的框架,可以使用。
BaseApplication基础的Application。增加了当前打开的Activity监听,是否进入后台模式判断
BaseActivity是基础Activity类,在这里定义仿照的DataBinding
public abstract class BaseActivity extends AppCompatActivity {
protected DD dinding;
protected V viewModel;
protected int screenOrientation;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
screenOrientation = this.getResources().getConfiguration().orientation;
getConst();
dinding = ViewManagerUtil.setContentView(this, layoutId(), getDindingClass());
dinding.findView(getListener());
viewModel = initViewModel();
initView(savedInstanceState);
initObservableView();
}
protected void getConst() {
if (SharePerferenceController.getInstance().getValue(SpEnum.IMAGE_WIDTH, 0) == 0
|| SharePerferenceController.getInstance().getValue(SpEnum.IMAGE_HEIGHT, 0) == 0) {
DisplayMetrics metrics = getResources().getDisplayMetrics();
SharePerferenceController.getInstance().putValue(SpEnum.IMAGE_WIDTH, metrics.widthPixels / 2);
SharePerferenceController.getInstance().putValue(SpEnum.IMAGE_HEIGHT, metrics.heightPixels / 2);
}
}
protected FindViewListener getListener() {
return null;
}
/**
* 获取界面Layout
*
* @return 返回layout
*/
protected abstract int layoutId();
/**
* 获取ViewModel对象
*
* @return 返回对象
*/
private V initViewModel() {
ViewModelProvider.AndroidViewModelFactory instance = ViewModelProvider.AndroidViewModelFactory.getInstance(getApplication());
return new ViewModelProvider(this, instance).get(getViewModelClass());
}
/**
* 获取ViewModel
*
* @return
*/
protected abstract Class getDindingClass();
/**
* 获取ViewModel
*
* @return
*/
protected abstract Class getViewModelClass();
/**
* 初始化UI
*
* @param savedInstanceState
*/
public abstract void initView(Bundle savedInstanceState);
/**
* 初始化监听
*/
public abstract void initObservableView();
@Override
protected void onDestroy() {
super.onDestroy();
DLog.i("界面调用onDestroy");
}
public DD getDinding() {
return dinding;
}
public V getViewModel() {
return viewModel;
}
}
以下代码是简化重写的DataBinding。
/**
* 本来是自动生成的,我代码无法自动生成,所有给了个固定类,不调整xml布局
*/
public abstract class DataDinding {
}
/**
* 这里拿到所有注册的控件id
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface DinView {
int value();
}
/**
* 可以通过该类,获取Activity对应的xml中的所有控件
*/
public class ViewManagerUtil {
/**
* 通过注入,获取对应的绑定实体信息
*
* @param activity
* @param layoutId
* @param
* @return
*/
public static T setContentView(@NonNull Activity activity, int layoutId,Class cls) {
activity.setContentView(layoutId);
try {
T t = cls.newInstance();
Field[] fields = t.getClass().getDeclaredFields();
for (Field field:fields) {
//设置访问权限
field.setAccessible(true);
//判断是否被BindingText注解修饰
if(field.isAnnotationPresent(DinView.class)){
//获取指定注解
DinView annotation = field.getAnnotation(DinView.class);
//获取到控件
View view = findById(activity,annotation.value());
//反射设置属性的值
//设置访问权限,允许 *** 作private的属性
field.setAccessible(true);
try {
//赋值
field.set(t, view);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
return t;
} catch (Exception e) {
return (T) new DataDinding() {
};
}
}
}
如何使用?
public class MainActivity extends BaseActivity {
@Override
protected int layoutId() {
return R.layout.activity_main;
}
@Override
protected Class getDindingClass() {
return MainDindingActivity.class;
}
@Override
protected Class getViewModelClass() {
return MainViewModel.class;
}
@Override
public void initView(Bundle savedInstanceState) {
}
@Override
public void initObservableView() {
viewModel.getAction().observe(this, new Observer() {
@Override
public void onChanged(ActionView action) {
if (action != null) {
doAction(action);
}
}
});
}
private void doAction(ActionView action) {
}
}
public class MainViewModel extends ViewModel{}
public class MainDindingActivity extends DataDinding {
@DinView(R.id.id_main_table)
public TableRow idMainTable;
@DinView(R.id.id_main_txt)
public EditText idMainTxt;
}
所有的控件 *** 作都在Activity中,业务 *** 作都在viewModel中。控件对象在dataDinding中。实现三权分立。独立控制功能。当然还不完善
总结
内部封装的功能还有很多。先讲解Module拆分的原则和功能。
拆分原则:
1、单一职责,一个module只有一个职责,只负责一块。
2、服务颗粒度适中,不用拆到很多module,根据实际情况进行拆分。
3、结构框架,大结构固定的情况下,分module可以更便捷进行项目管理。
4、业务模型拆分,业务可以进行模块化拆分,并且业务之间耦合度不高,可以进行分业务包管理
5、迭代拆分,老项目和新项目不是一开始就拆分好了,而是在开发迭代过程中,逐步优化拆分的结果。
6、避免环形依赖和双向依赖。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)