android模块
❶ Android模块化开发解耦需要注意的一些事项
模块化开发的目的 - 解耦,所以我们的注意事项,都应该围绕着解耦来做。
❷ Android硬件抽象层模块编写规范
硬件抽象层模块编写规范
硬件抽象层最终都会生成.so文件,放到系统对应的目录中。在系统使用的时候,系统会去对应目录下加载so文件,实现硬件抽象层的功能。因此硬件抽象层的加载过程就是我们使用so的一个接口。先了解加载过程从源头了解抽象层模块儿的编写规范。
1、硬件抽象层加载过程
系统在加载so的过程中,会去两个目录下查找对应id的so文件。这两个目录分别是/system/lib/hw和/vendor/lib/hw。
so文件的名字分为两个部分例如id.prop.so,第一部分是模块id。第二部分是系统prop的值,获取顺序为“ro.hardware”、“ro.procat.board”、“ro.board.platform”、“ro.arch”,如果prop都找不到的话,就用default。(不是找不到prop的值,是找不到prop值对应的so文件)。
负责加载硬件抽象层模块的函数是hw_get_mole,所在的文件是/hardware/libhardware/hardware.c如下:
/** Base path of the hal moles */
#if defined(__LP64__)
#define HAL_LIBRARY_PATH1 "/system/lib64/hw"
#define HAL_LIBRARY_PATH2 "/vendor/lib64/hw"
#else
#define HAL_LIBRARY_PATH1 "/system/lib/hw"
#define HAL_LIBRARY_PATH2 "/vendor/lib/hw"
#endif
/**
* There are a set of variant filename for moles. The form of the filename
* is ".variant.so" so for the led mole the Dream variants
* of base "ro.proct.board", "ro.board.platform" and "ro.arch" would be:
*
* led.trout.so
* led.msm7k.so
* led.ARMV6.so
* led.default.so
*/
static const char *variant_keys[] = {
"ro.hardware", /* This goes first so that it can pick up a different
file on the emulator. */
"ro.proct.board",
"ro.board.platform",
"ro.arch"
};
static const int HAL_VARIANT_KEYS_COUNT =
(sizeof(variant_keys)/sizeof(variant_keys[0]));
/**
* Load the file defined by the variant and if successful
* return the dlopen handle and the hmi.
* @return 0 = success, !0 = failure.
*/
static int load(const char *id,
const char *path,
const struct hw_mole_t **pHmi)
{
int status;
void *handle;
struct hw_mole_t *hmi;
/*
* load the symbols resolving undefined symbols before
* dlopen returns. Since RTLD_GLOBAL is not or'd in with
* RTLD_NOW the external symbols will not be global
*/
handle = dlopen(path, RTLD_NOW);
if (handle == NULL) {
char const *err_str = dlerror();
ALOGE("load: mole=%s\n%s", path, err_str?err_str:"unknown");
status = -EINVAL;
goto done;
}
/* Get the address of the struct hal_mole_info. */
const char *sym = HAL_MODULE_INFO_SYM_AS_STR;
hmi = (struct hw_mole_t *)dlsym(handle, sym);
if (hmi == NULL) {
ALOGE("load: couldn't find symbol %s", sym);
status = -EINVAL;
goto done;
}
/* Check that the id matches */
if (strcmp(id, hmi->id) != 0) {
ALOGE("load: id=%s != hmi->id=%s", id, hmi->id);
status = -EINVAL;
goto done;
}
hmi->dso = handle;
/* success */
status = 0;
done:
if (status != 0) {
hmi = NULL;
if (handle != NULL) {
dlclose(handle);
handle = NULL;
}
} else {
ALOGV("loaded HAL id=%s path=%s hmi=%p handle=%p",
id, path, *pHmi, handle);
}
*pHmi = hmi;
return status;
}
/*
* Check if a HAL with given name and subname exists, if so return 0, otherwise
* otherwise return negative. On success path will contain the path to the HAL.
*/
static int hw_mole_exists(char *path, size_t path_len, const char *name,
const char *subname)
{
snprintf(path, path_len, "%s/%s.%s.so",
HAL_LIBRARY_PATH2, name, subname);
if (access(path, R_OK) == 0)
return 0;
snprintf(path, path_len, "%s/%s.%s.so",
HAL_LIBRARY_PATH1, name, subname);
if (access(path, R_OK) == 0)
return 0;
return -ENOENT;
}
int hw_get_mole_by_class(const char *class_id, const char *inst,
const struct hw_mole_t **mole)
{
int i;
char prop[PATH_MAX];
char path[PATH_MAX];
char name[PATH_MAX];
char prop_name[PATH_MAX];
if (inst)
snprintf(name, PATH_MAX, "%s.%s", class_id, inst);
else
strlcpy(name, class_id, PATH_MAX);
/*
* Here we rely on the fact that calling dlopen multiple times on
* the same .so will simply increment a refcount (and not load
* a new of the library).
* We also assume that dlopen() is thread-safe.
*/
/* First try a property specific to the class and possibly instance */
snprintf(prop_name, sizeof(prop_name), "ro.hardware.%s", name);
if (property_get(prop_name, prop, NULL) > 0) {
if (hw_mole_exists(path, sizeof(path), name, prop) == 0) {
goto found;
}
}
/* Loop through the configuration variants looking for a mole */
for (i=0 ; i<HAL_VARIANT_KEYS_COUNT; i++) {
if (property_get(variant_keys[i], prop, NULL) == 0) {
continue;
}
if (hw_mole_exists(path, sizeof(path), name, prop) == 0) {
goto found;
}
}
/* Nothing found, try the default */
if (hw_mole_exists(path, sizeof(path), name, "default") == 0) {
goto found;
}
return -ENOENT;
found:
/* load the mole, if this fails, we're doomed, and we should not try
* to load a different variant. */
return load(class_id, path, mole);
}
int hw_get_mole(const char *id, const struct hw_mole_t **mole)
{
return hw_get_mole_by_class(id, NULL, mole);
}
找到so文件之后,调用方法load方法去加载对应的so文件,并返回hw_mole_t结构体。load方法源码在上面程序中。
load方法首先调用dlopen加载对应的so文件到内存中。然后用dlsym方法找到变量HAL_MODULE_INFO_SYM_AS_STR符号对应的地址,这个地址也就是一个hw_mole_t结构体,然后从这个结构体中拿出id比对load方法出入的id是否一致,如果是的话表示打开成功。加载过程完成。
HAL_MODULE_INFO_SYM_AS_STR这个符号值为HMI,也就是必须要保证这个符号之后是一个hw_mole_t。接下来的规范中有这个要求。
到此,模块加载完成
2、硬件抽象层模块编写规范
硬件抽象层有两个结构体,一个是hw_mole_t和hw_device_t,定义在hardware.h中。
首先说一下hw_mole_t的编写规范。
1、必须要有一个“自定义硬件抽象层结构体”,且结构体第一个变量类型要为hw_mole_t。
2、必须存在一个HARDWARE_MODULE_INFO_TAG的符号,且指向“自定义硬件抽象层结构体”。在加载的时候根据这个符号找到地址,并把地址的转变为hw_mole_t,这也是为什么第一条中hw_mole_t必须要在第一个的原因。
3、hw_mole_t的tag必须为HARDWARE_MODULE_TAG
4、结构体中要有一个方法列表,其中要有一个open方法。用open方法获得hw_device_t
接下来说一下hw_device_t的编写规范
1、必须要有一个“自定义硬件设备结构体”,且结构体第一个变量类型要为hw_device_t。
2、hw_device_t的tag必须为HARDWARE_DEVICE_TAG
3、要有一个close函数指针,来关闭设备
按照上面规范编写的硬件抽象层就可以由系统加载并正确获取到device。具体的应用层逻辑在device中实现。
❸ Android 模块之旅:ARoutrer框架使用教程
随着公司项目越来越大,人员增多,项目会出现难维护、新人入职后,需要花费很多时间去熟悉项目。最重要的是,每次编译时间真的太久了!!!为了解决这个问题,项目重构、模块化需要提上日程。项目拆分成模块之后,页面的跳转就不能直接startActivity 调用具体的activity了,因为这个Activity已经在另外一个模块中,直接用显示引用是提示不出来的,这时需要通过借助路由库来实现页面的跳转,当然通过反射的方式也是可以跳转到对应页面的。通过这样的路由跳转,而不是显示引用,就达到了模块之间解耦的目的,在不需要的时候,可以不需要引入这个模块编译,提高开发速度,发布的时候又能很方便的集成进来,功能不受影响,这就实现了模块化的第一步。路由框架推荐使用阿里开源的ARouter路由框架,毕竟是大厂开源的框架,稳定性、可靠性也相对较高。
路由路径,我们可以封装一个 RouterManger 工具类放在 moudle_base 模块中,统一管理整个项目的 Path 及路由框架的初始化操作, 示例如下:
我们经常需要在目标页面中配置一些属性,比方说"是否需要登陆"之类的
可以通过 Route 注解中的 extras 属性进行扩展,这个属性是一个 int值,换句话说,单个int有4字节,也就是32位,可以配置32个开关
剩下的可以自行发挥,通过字节操作可以标识32个开关,通过开关标记目标页面的一些属性,在拦截器中可以拿到这个标记进行业务逻辑判断
ARouter更加详细的使用教程可以前往官方GitHub查阅,上述为个人使用过程中觉得需要记录下来东西,不足之处,敬请见谅
❹ 什么是android应用模块开发
android应用模块开发:
在android的项目开发中,都会遇到后期功能拓展增强与主程序代码变更的现实矛盾,也就是程序的灵活度。
由于linux平台的安全机制,再加上dalvik的特殊机制,各种权限壁垒,使得开发一个灵活多变的程序,变得比较困难,不像pc平台下那么容易。
瞅瞅elipse的插件,瞅瞅360的插件,在android下,我们一开始很难写好一个主程序,然后通过插件机制来应对以后的功能拓展,于是程序变得不那么灵活多变了。
比如一款android下的安全软件,新版本增加了一个功能,如短信拦截,往往会因为一个模块的增加,而重新编译一个apk包,这样周而复始,哪怕只增加50kb的功能代码,用户也需要升级一个完整的apk,往往是5~6M的体积。
❺ Android核心模块结构层次有哪些呢
Android作为一个移动设备的平台,其软件层次结构包括了一个操作系统(OS),中间件(MiddleWare)和应用程序(Application)。
根据Android的软件框图,其Android核心模块结构自下而上分为以下几个层次:
第一、操作系统层(OS)
第二、各种库(Libraries)和Android 运行环境(RunTime)
第三、应用程序框架(Application Framework)
第四、应用程序(Application)
❻ MoleService-Android模块之间解耦问题实现
模块间解耦库,解决mole之间的依赖问题,github地址: https://github.com/breaktian/MoleServiceDemo
项目大了之后,mole增多了,尤其是业务模块之间的依赖关系变得复杂,而且gradle不允许双向依赖,
比如说biz-a模块依赖biz-b模块,如果biz-b模块想使用biz-a模块的服务怎么办?biz-b再去依赖biz-a gradle编译会出错
demo项目的模块:App、biz-login、biz-usercenter、shell。其中shell模块是公共模块,他们的依赖关系是App依赖biz-login、biz-usercenter、biz-shell,
biz-login依赖shell,biz-usercenter依赖shell。其实shell就是一个公共模块。biz-login和biz-usercenter没有依赖关系。
当然,任何模块都可以提供服务,而且任何模块都能使用协议中已经存在的服务。这样之前繁杂冗余的业务模块之间的依赖就没有了,还可以提高编译的速度。
❼ androidstudio如何把模块由app调用
androidstudio把模块由app调用方法如下:
1、自己创建一个新的android项目,选择EmptyActivity,一直选择默认项file->new->importmole。
2、选择模块文件,点击finish。
3、点击file->projectStructure。
4、选中Moles下的app,注意这个app就是自己newproject的mole。
5、点击+号,选中Moledependency。
6、选中之前导入的模块,点击ok。
❽ android 模块化中打开其他模块activity的方式
AndroidManifest.xml 中配置 meta-data
在Activity中,通过packageyManage获取到activityInfo再获取到该activity的meta-data
获取到配置的meta-date value之后,再通过反射去创建一个需要的activity实例
这样用的好处之一就是在模块化APP中不同模块可以通过包名去调用其他模块的内容。
总结:
获取meta-data的方法只是一种思路,通过packageManage获取到meta-data的value值(需要跳转到的activity包路径)
实质上就是通过反射去创建一个activity实例,这样的思路还可以用在其他地方,比如后端某一个表中新建一个action字段等等...
❾ 如何学习android框架,框架分为哪些模块
其实主要是看你的工作中会用到什么,感觉还是先把Android的基础学好,毕竟框架也是在Android的基础上面进行开发的,你说的这几个框架我没怎么用过,大概看过一点,比如xutils和ThinkAndroid,他们都有一些自己的模块如view,http,bitmap相关的模块,这些模块把一些常用的操作都进行了封装,直接拿过来使用就可以了,这样确实减少了开发的工作,也会减少工作中可能会犯的一些错误,比如如果bitmap处理不好就很容易造成内存的问题。网上对这些框架有比较详细的介绍和每个框架里面实现的模块以及各个模块支持的功能。对比一下哪个是你工作中最需要的,然后学习一下即可,学会了一种那么其他的框架在看的时候就可以做到举一反三了。不过在学习框架的同时还是要把android的基础多学习一下的。
❿ Android模块化设计方案之使用代理模式解耦
Android模块化设计方案系列文章:
1、 Android模块化设计方案模型图
2、 Android模块化设计方案之接口API化
3、 Android模块化设计方案之使用代理模式解耦
本篇是Android模块化设计方案的第三篇,也是对 第一篇 中ThridLibs Proxy模块进行说明。
很多人觉得对那些优秀的第三方依赖库再次封装是一件多余的事情,因为这些库可能出自大神/大厂,或有非常高的star并且使用起来十分稳定,可以在项目中直接拿来使用。当然每个开发者都有自己的态度,我也只是根据以往的经验,表达一下自己的看法。
作为从了解四大组件就不愁找不到工作的互联网大时代中一路走来的Android老鸟,经历了网路请求框架从HttpConnection到Volley再到OkHttp,也经历了图片加载框架从UniversalImageLoader到Picasso再到Gilde,技术的迭代随时都会发生。让项目架构具有良好的扩展性是在设计之初就需要考虑的东西。
那么接下来我用一个简单的demo来演示一下如何使用代理模式对第三方框架进行解耦。
现在我们有一个名为 thirdlib 的模块,为我们提供图片加载功能。
第一步:我们创建了一个新的模块 thridlibproxy ,并且该模块依赖于 thirdlib ,我们在该模块中创建包私有的接口ImageLoaderInterface,这个接口中把thirdlib模块中提供的功能抽象为接口:
第二步:创建包私有的接口的实现类ImageLoaderOneImpl,类中图片加载的业务逻辑是通过调用 thirdlib 中的ImageLoader类实现的:
第三步:我们提供一个供外部调用的ImageLoaderOneImpl接口代理类ImageLoaderProxy:
最后我们就可以通过ImageLoaderProxy中提供的loadImage方法进行图片的加载了。
看到这里有些盆友就会问了,在第二步的时候,我们就完成了 thirdlib 的封装工作,为什么还要有第三步?还有我写一个单例类直接对 thirdlib 进行封装不就行了,为什么还要抽象出接口?
原因很简单,为的就是尽可能的满足软件设计七大原则中的第一个: 开闭原则 。
一个好的软件设计,需要对拓展开放,对修改关闭。我们在设计之初就要想到,在更换图片加载框架之后如何最大程度上满足开闭原则。
如果直接对 thirdlib 进行封装,是面向类的开发而不是面向接口。如果此时更换图片加载类库,那必然会对封装出来的类进行大量的修改,把原来的实现替换为新的实现。
使用代理模式的好处就是,我新创建一个被代理的类ImageLoaderTwoImpl:
然后只需要对第三步中的被代理类进行替换就行了。
在想要达到相同效果的时候,最大程度的满足了开闭原则。
我们业务层模块也和第三方库实现了完全的解耦,我不需要知道 thridlibproxy 是如何帮我完成图片加载工作的,但是只要调用它提供的方法就完事儿的,这也符合软件设计七大原则中的: 最少知道原则 。
关于为何以及怎么通过代理调用第三方依赖库,到这里就介绍完毕了,赶快动手试试吧~
我只想说: 原则是死的,人是活的😹
如果觉得有收获的话,欢迎点赞评论以及关注~