Android开发项目 ---- Module底层依赖封装

系列文章目录

第一章: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<DD extends DataDinding, V extends ViewModel> 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<DD> getDindingClass();

    /**
     * 获取ViewModel
     *
     * @return
     */
    protected abstract Class<V> 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 <T>
     * @return
     */
    public static <T extends DataDinding> T setContentView(@NonNull Activity activity, int layoutId,Class<T> 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<MainDindingActivity, MainViewModel> {
    @Override
    protected int layoutId() {
        return R.layout.activity_main;
    }
    @Override
    protected Class<MainDindingActivity> getDindingClass() {
        return MainDindingActivity.class;
    }
    @Override
    protected Class<MainViewModel> getViewModelClass() {
        return MainViewModel.class;
    }
    @Override
    public void initView(Bundle savedInstanceState) {
    }
    @Override
    public void initObservableView() {
        viewModel.getAction().observe(this, new Observer<ActionView>() {
            @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
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值