前言

本文所讲的组件化案例是基于自己开源的组件化框架项目
github上地址github.com/HelloChenJi…
其中即时通讯(Chat)模块是单独的项目
github上地址github.com/HelloChenJi…

1.什么是组件化?

项目发展到一定阶段时,随着需求的增加以及频繁地变更,项目会越来越大,代码变得越来越臃肿,耦合会越来越多,开发效率也会降低,这个时候我们就需要对旧项目进行重构即模块的拆分,官方的说法就是组件化。

2.为什么需要组件化和组件化带来的好处?

1、 现在Android项目中代码量达到一定程度,编译将是一件非常痛苦的事情,一般都需要变异5到6分钟。Android studio推出instant run由于各种缺陷和限制条件(比如采用热修复tinker)一般情况下是被关闭的。而组件化框架可以使模块单独编译调试,可以有效地减少编译的时间。
2、通过组件化可以更好的进行并行开发,因为我们可以为每一个模块进行单独的版本控制,甚至每一个模块的负责人可以选择自己的设计架构而不影响其他模块的开发,与此同时组件化还可以避免模块之间的交叉依赖,每一个模块的开发人员可以对自己的模块进行独立测试,独立编译和运行,甚至可以实现单独的部署。从而极大的提高了并行开发效率。

3.组件化的基本框架

 

3.1组件框架图

3.1组件框架图

 

 

3.2项目结构图

3.2项目结构图

 

4.组件化框架的具体实现

4.1、基类库的封装

 

4.1基类库图

4.1基类库图


基类库中主要包括开发常用的一些框架。
1、网络请求(多任务下载和上传,采用Retrofit+RxJava框架)
2、图片加载(策略模式,Glide与Picasso之间可以切换)
3、通信机制(RxBus)
4、基类adapter的封装(支持item动画、多布局item、下拉和加载更多、item点击事件)
5、基类RecyclerView的封装(支持原生风格的下拉加载,item侧滑等)
6、mvp框架
7、各组件的数据库实体类
8、通用的工具类
9、自定义view(包括对话框,ToolBar布局,圆形图片等view的自定义)
10、dagger的封装(用于初始化全局的变量和网络请求等配置)
等等

 

4.2组件模式和集成模式切换的实现

music组件下的build.gradle文件,其他组件类似。

//控制组件模式和集成模式
if (rootProject.ext.isAlone) {apply plugin: 'com.android.application'
} else {apply plugin: 'com.android.library'
}
apply plugin: 'com.neenbedankt.android-apt'
android {compileSdkVersion rootProject.ext.android.compileSdkVersionbuildToolsVersion rootProject.ext.android.buildToolsVersiondefaultConfig {if (rootProject.ext.isAlone) {//   组件模式下设置applicationIdapplicationId "com.example.cootek.music"}minSdkVersion rootProject.ext.android.minSdkVersiontargetSdkVersion rootProject.ext.android.targetSdkVersionversionCode rootProject.ext.android.versionCodeversionName rootProject.ext.android.versionNametestInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"if (!rootProject.ext.isAlone) {
//   集成模式下Arouter的配置,用于组件间通信的实现javaCompileOptions {annotationProcessorOptions {arguments = [moduleName: project.getName()]}}}}buildTypes {release {minifyEnabled falseproguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'}}compileOptions {sourceCompatibility JavaVersion.VERSION_1_7targetCompatibility JavaVersion.VERSION_1_7}sourceSets {main {//控制两种模式下的资源和代码配置情况if (rootProject.ext.isAlone) {manifest.srcFile 'src/main/module/AndroidManifest.xml'java.srcDirs = ['src/main/java', 'src/main/module/java']res.srcDirs = ['src/main/res', 'src/main/module/res']} else {manifest.srcFile 'src/main/AndroidManifest.xml'}}}
}
dependencies {compile fileTree(dir: 'libs', include: ['*.jar'])androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {exclude group: 'com.android.support', module: 'support-annotations'})
//   依赖基类库compile project(':commonlibrary')
//用作颜色选择器compile 'com.afollestad.material-dialogs:commons:0.9.1.0'apt rootProject.ext.dependencies.dagger2_compilerif (!rootProject.ext.isAlone) {
//  集成模式下需要编译器生成路由通信的代码apt rootProject.ext.dependencies.arouter_compiler}testCompile 'junit:junit:4.12'
}

集成模式

1、首先需要在config,gradle文件中设置isAlone=false

ext {isAlone = false;//false:作为Lib组件存在, true:作为application存在

2、然后Sync 下。
3、最后选择app运行即可。

运行.png

 

组件模式

1、首先需要在config,gradle文件中设置isAlone=true

ext {isAlone = true;//false:作为Lib组件存在, true:作为application存在复制代码

2、然后Sync 下。
3、最后相应的模块(new、chat、live、music、app)进行运行即可。

4.3第三方开源库和组件版本号的管理

config.gradle文件的配置情况

ext {isAlone = false;//false:作为集成模式存在, true:作为组件模式存在//  各个组件版本号的统一管理android = [compileSdkVersion: 24,buildToolsVersion: "25.0.2",minSdkVersion    : 16,targetSdkVersion : 22,versionCode      : 1,versionName      : '1.0.0',]libsVersion = [// 第三方库版本号的管理supportLibraryVersion = "25.3.0",retrofitVersion = "2.1.0",glideVersion = "3.7.0",loggerVersion = "1.15",
//            eventbusVersion = "3.0.0",gsonVersion = "2.8.0",butterknife = "8.8.0",retrofit = "2.3.0",rxjava = "2.1.1",rxjava_android = "2.0.1",rxlifecycle = "2.1.0",rxlifecycle_components = "2.1.0",dagger_compiler = "2.11",dagger = "2.11",greenDao = "3.2.2",arouter_api = "1.2.2",arouter_compiler = "1.1.3",transformations = "2.0.2",rxjava_adapter = "2.3.0",gson_converter = "2.3.0",scalars_converter = "2.3.0",rxpermission = "0.9.4",eventbus="3.0.0",support_v4="25.4.0",okhttp3="3.8.1"]//  依赖库管理dependencies = [appcompatV7               : "com.android.support:appcompat-v7:$rootProject.supportLibraryVersion",design                    : "com.android.support:design:$rootProject.supportLibraryVersion",cardview                  : "com.android.support:cardview-v7:$rootProject.supportLibraryVersion",palette                   : "com.android.support:palette-v7:$rootProject.supportLibraryVersion",recycleview               : "com.android.support:recyclerview-v7:$rootProject.supportLibraryVersion",support_v4                : "com.android.support:support-v4:$rootProject.support_v4",annotations               : "com.android.support:support-annotations:$rootProject.supportLibraryVersion",eventBus                  : "org.greenrobot:eventbus:$rootProject.eventbus",glide                     : "com.github.bumptech.glide:glide:$rootProject.glideVersion",gson                      : "com.google.code.gson:gson:$rootProject.gsonVersion",logger                    : "com.orhanobut:logger:$rootProject.loggerVersion",butterknife               : "com.jakewharton:butterknife:$rootProject.butterknife",butterknife_compiler      : "com.jakewharton:butterknife-compiler:$rootProject.butterknife",retrofit                  : "com.squareup.retrofit2:retrofit:$rootProject.retrofit",okhttp3                   : "com.squareup.okhttp3:okhttp:$rootProject.retrofit",retrofit_adapter_rxjava2  : "com.squareup.retrofit2:adapter-rxjava2:$rootProject.rxjava_adapter",retrofit_converter_gson   : "com.squareup.retrofit2:converter-gson:$rootProject.gson_converter",retrofit_converter_scalars: "com.squareup.retrofit2:converter-scalars:$rootProject.scalars_converter",rxpermission              : "com.tbruyelle.rxpermissions2:rxpermissions:$rootProject.rxpermission@aar",rxjava2                   : "io.reactivex.rxjava2:rxjava:$rootProject.rxjava",rxjava2_android           : "io.reactivex.rxjava2:rxandroid:$rootProject.rxjava_android",rxlifecycle2              : "com.trello.rxlifecycle2:rxlifecycle:$rootProject.rxlifecycle",rxlifecycle2_components   : "com.trello.rxlifecycle2:rxlifecycle-components:$rootProject.rxlifecycle_components",dagger2_compiler          : "com.google.dagger:dagger-compiler:$rootProject.dagger_compiler",dagger2                   : "com.google.dagger:dagger:$rootProject.dagger",greenDao                  : "org.greenrobot:greendao:$rootProject.greenDao",transformations           : "jp.wasabeef:glide-transformations:$rootProject.transformations",
//路由通讯arouter_api               : "com.alibaba:arouter-api:$rootProject.arouter_api",arouter_compiler          : "com.alibaba:arouter-compiler:$rootProject.arouter_compiler"]
}

4.4、组件间通信实现

组件间通信的实现是采用阿里开源的Arouter路由通信。
github地址:github.com/alibaba/ARo…
在App工程中,初始化组件通信数据

private List<MainItemBean> getDefaultData() {List<MainItemBean> result=new ArrayList<>();MainItemBean mainItemBean=new MainItemBean();mainItemBean.setName("校园");mainItemBean.setPath("/news/main");mainItemBean.setResId(R.mipmap.ic_launcher);MainItemBean music=new MainItemBean();music.setName("音乐");music.setResId(R.mipmap.ic_launcher);music.setPath("/music/main");MainItemBean live=new MainItemBean();live.setName("直播");live.setResId(R.mipmap.ic_launcher);live.setPath("/live/main");MainItemBean chat=new MainItemBean();chat.setName("聊天");chat.setPath("/chat/splash");chat.setResId(R.mipmap.ic_launcher);result.add(mainItemBean);result.add(music);result.add(live);result.add(chat);return result;}

然后在设置每个item的点击事件时,启动组件界面跳转。

@Overridepublic void onItemClick(int position, View view) {MainItemBean item=mainAdapter.getData(position);ARouter.getInstance().build(item.getPath()).navigation();}

每个组件入口界面的设置(比如直播Live组件,其它组件类似)

@Route(path = "/live/main")
public class MainActivity extends BaseActivity<List<CategoryLiveBean>, MainPresenter> implements View.OnClickListener {

5.组件合并时res资源和AndroidManifest配置的问题

我们通过判断组件处于哪种模式来动态设置项目res资源和Manifest、以及代码的位置。以直播组件为例,其它组件类似。

 

直播组件框架

直播组件框架


直播组件的build.gradle文件对代码资源等位置的配置

 

sourceSets {main {if (rootProject.ext.isAlone) {manifest.srcFile 'src/main/module/AndroidManifest.xml'java.srcDirs = ['src/main/java', 'src/main/module/java']res.srcDirs = ['src/main/res', 'src/main/module/res']} else {manifest.srcFile 'src/main/AndroidManifest.xml'}}}

6.组件全局application的实现和数据的初始化

采用类似于Glide在Manifest初始化配置的方式来初始化各个组件的Application,以直播组件为例,其它类似。

在BaseApplication中,初始化ApplicationDelegate代理类

 @Overrideprotected void attachBaseContext(Context base) {super.attachBaseContext(base);applicationDelegate = new ApplicationDelegate();applicationDelegate.attachBaseContext(base);MultiDex.install(this);}

ApplicationDelegate内部是怎样的呢?继续看下去

public class ApplicationDelegate implements IAppLife {private List<IModuleConfig> list;private List<IAppLife> appLifes;private List<Application.ActivityLifecycleCallbacks> liferecycleCallbacks;public ApplicationDelegate() {appLifes = new ArrayList<>();liferecycleCallbacks = new ArrayList<>();}@Overridepublic void attachBaseContext(Context base) {
//   初始化Manifest文件解析器,用于解析组件在自己的Manifest文件配置的ApplicationManifestParser manifestParser = new ManifestParser(base);list = manifestParser.parse();
//解析得到的组件Application列表之后,给每个组件Application注入
context,和Application的生命周期的回调,用于实现application的同步if (list != null && list.size() > 0) {for (IModuleConfig configModule :list) {configModule.injectAppLifecycle(base, appLifes);configModule.injectActivityLifecycle(base, liferecycleCallbacks);}}if (appLifes != null && appLifes.size() > 0) {for (IAppLife life :appLifes) {life.attachBaseContext(base);}}}@Overridepublic void onCreate(Application application) {
//  相应调用组件Application代理类的onCreate方法if (appLifes != null && appLifes.size() > 0) {for (IAppLife life :appLifes) {life.onCreate(application);}}if (liferecycleCallbacks != null && liferecycleCallbacks.size() > 0) {for (Application.ActivityLifecycleCallbacks life :liferecycleCallbacks) {application.registerActivityLifecycleCallbacks(life);}}}@Overridepublic void onTerminate(Application application) {
//  相应调用组件Application代理类的onTerminate方法if (appLifes != null && appLifes.size() > 0) {for (IAppLife life :appLifes) {life.onTerminate(application);}}if (liferecycleCallbacks != null && liferecycleCallbacks.size() > 0) {for (Application.ActivityLifecycleCallbacks life :liferecycleCallbacks) {application.unregisterActivityLifecycleCallbacks(life);}}}
}

组件Manifest中application的全局配置

<meta-dataandroid:name="com.example.live.LiveApplication"android:value="IModuleConfig" />

ManifestParser会对其中value为IModuleConfig的meta-data进行解析,并通过反射生成实例。

public final class ManifestParser {private static final String MODULE_VALUE = "IModuleConfig";private final Context context;public ManifestParser(Context context) {this.context = context;}public List<IModuleConfig> parse() {List<IModuleConfig> modules = new ArrayList<>();try {ApplicationInfo appInfo = context.getPackageManager().getApplicationInfo(context.getPackageName(), PackageManager.GET_META_DATA);if (appInfo.metaData != null) {for (String key : appInfo.metaData.keySet()) {
//会对其中value为IModuleConfig的meta-data进行解析,并通过反射生成实例if (MODULE_VALUE.equals(appInfo.metaData.get(key))) {modules.add(parseModule(key));}}}} catch (PackageManager.NameNotFoundException e) {throw new RuntimeException("Unable to find metadata to parse IModuleConfig", e);}return modules;}//通过类名生成实例private static IModuleConfig parseModule(String className) {Class<?> clazz;try {clazz = Class.forName(className);} catch (ClassNotFoundException e) {throw new IllegalArgumentException("Unable to find IModuleConfig implementation", e);}Object module;try {module = clazz.newInstance();} catch (InstantiationException e) {throw new RuntimeException("Unable to instantiate IModuleConfig implementation for " + clazz, e);} catch (IllegalAccessException e) {throw new RuntimeException("Unable to instantiate IModuleConfig implementation for " + clazz, e);}if (!(module instanceof IModuleConfig)) {throw new RuntimeException("Expected instanceof IModuleConfig, but found: " + module);}return (IModuleConfig) module;}

这样通过以上步骤就可以在Manifest文件中配置自己组件的Application,用于初始化组件内的数据,比如在直播组件中初始化Dagger的全局配置

public class LiveApplication implements IModuleConfig,IAppLife {private static MainComponent mainComponent;@Overridepublic void injectAppLifecycle(Context context, List<IAppLife> iAppLifes) {
//  这里需要把本引用添加到Application的生命周期的回调中,以便实现回调iAppLifes.add(this);}@Overridepublic void injectActivityLifecycle(Context context, List<Application.ActivityLifecycleCallbacks> lifecycleCallbackses) {}@Overridepublic void attachBaseContext(Context base) {}@Overridepublic void onCreate(Application application) {
//     在onCreate方法中对Dagger进行初始化mainComponent= DaggerMainComponent.builder().mainModule(new MainModule()).appComponent(BaseApplication.getAppComponent()).build();}@Overridepublic void onTerminate(Application application) {if (mainComponent != null) {mainComponent = null;}}public static MainComponent getMainComponent() {return mainComponent;}
}

7.组件内网络请求和拦截器的实现

由于每个组件的BaseUrl和网络配置等可能不一样,所以每个组件可以在自己配置的dagger中的 MainConponent实现自己的网络请求和拦截器。
以直播组件为例,其它类似。
MainComponent

@PerApplication
@Component(dependencies = AppComponent.class, modules = MainModule.class)
public interface MainComponent {public DaoSession getDaoSession();public MainRepositoryManager getMainRepositoryManager();
}

MainModule代码

@Module
public class MainModule {@Provides@PerApplicationpublic MainRepositoryManager provideRepositoryManager(@Named("live") Retrofit retrofit, DaoSession daoSession) {return new MainRepositoryManager(retrofit, daoSession);}@Provides@Named("live")@PerApplicationpublic Retrofit provideRetrofit(@Named("live") OkHttpClient okHttpClient,@Nullable Gson gson){Retrofit.Builder builder=new Retrofit.Builder().baseUrl(LiveUtil.BASE_URL).addCallAdapterFactory(RxJava2CallAdapterFactory.create()).addConverterFactory(GsonConverterFactory.create(gson)).client(okHttpClient);return builder.build();}@Provides@Named("live")@PerApplicationpublic OkHttpClient provideOkHttpClient(@Named("live")LiveInterceptor interceptor){OkHttpClient.Builder builder=new OkHttpClient.Builder();builder.connectTimeout(10, TimeUnit.SECONDS).readTimeout(10,TimeUnit.SECONDS);builder.addInterceptor(interceptor);return builder.build();}@Provides@Named("live")@PerApplicationpublic LiveInterceptor provideNewsInterceptor(){return new LiveInterceptor();}
}

8.组件化实现的技术难点

8.1.greendao数据库的实现

greendao数据库初始化代码,在基类库的NetClientModule.java中

public DaoSession provideDaoSession(Application application) {DaoMaster.DevOpenHelper devOpenHelper = new DaoMaster.DevOpenHelper(application, "common_library_db", null);Database database = devOpenHelper.getWritableDb();DaoMaster master = new DaoMaster(database);return master.newSession();}

其中的DaoMaster是通过APT生成的,由于DaoMaster给全局的组件使用,所以只能将greendao 数据库放在基类库中,并且各个组件的实体类bean的创建也只能在基类库中进行,以分包命名进行区分,如下图。因为如果在组件内创建bean 会重新生成另一个副本DaoMaster并且不能操控其他组件的数据库实体,有很大的局限性。

 

基类库组件实体分包图

基类库组件实体分包图

 

8.2.资源命名冲突

官方说法是在每个module的build.gradle文件中配置资源文件名前缀
这种方法缺点就是,所有的资源名必须要以指定的字符串(moudle_prefix)做前缀,否则会异常报错,而且这方法只限定xml里面的资源,对图片资源并不起作用,所以图片资源仍然需要手动去修改资源名。
所以不是很推荐使用这种方法来解决资源名冲突。所以只能自己注意点,在创建资源的时候,尽量不让其重复。

resourcePrefix  "moudle_prefix"

8.3.butterKnife不能使用的原因

虽然Butterknife支持在lib中使用,但是条件是用 R2 代替 R ,在组件模式和集成模式的切换中,R2<->R之间的切换是无法完成转换的,切换一次要改动全身,是非常麻烦的!所以不推荐在组件化中使用Butterknife。

8.4.library重复依赖问题

1、可能大家会认为,每个组件都依赖基类库,基类库library次不是重复依赖了?其实并不会存在这样的问题,因为在构建APP的过程中Gradle会自动将重复的arr包排除,也就不会存在重复依赖基类库的情况。
2、但是第三方开源库依赖的包可能会与我们自己引用的包重复,所以我们需要将多余的包给排除出去。
基类库(CommonLibrary)中build.gradle

dependencies {compile fileTree(dir: 'libs', include: ['*.jar'])testCompile 'junit:junit:4.12'androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {exclude group: 'com.android.support', module: 'support-annotations'})compile(rootProject.ext.dependencies.appcompatV7) {exclude module: "support-v4"exclude module: "support-annotations"}compile rootProject.ext.dependencies.recycleviewcompile rootProject.ext.dependencies.designcompile(rootProject.ext.dependencies.support_v4) {exclude module: "support-annotations"}compile rootProject.ext.dependencies.annotationscompile(rootProject.ext.dependencies.butterknife) {exclude module: 'support-annotations'}compile rootProject.ext.dependencies.rxjava2compile(rootProject.ext.dependencies.rxjava2_android) {exclude module: "rxjava"}compile(rootProject.ext.dependencies.rxlifecycle2) {exclude module: 'rxjava'exclude module: 'jsr305'}compile(rootProject.ext.dependencies.rxlifecycle2_components) {exclude module: 'support-v4'exclude module: 'appcompat-v7'exclude module: 'support-annotations'exclude module: 'rxjava'exclude module: 'rxandroid'exclude module: 'rxlifecycle'}compile(rootProject.ext.dependencies.retrofit) {exclude module: 'okhttp'exclude module: 'okio'}compile(rootProject.ext.dependencies.retrofit_converter_gson) {exclude module: 'gson'exclude module: 'okhttp'exclude module: 'okio'exclude module: 'retrofit'}compile(rootProject.ext.dependencies.retrofit_adapter_rxjava2) {exclude module: 'rxjava'exclude module: 'okhttp'exclude module: 'retrofit'exclude module: 'okio'}compile rootProject.ext.dependencies.greenDaocompile rootProject.ext.dependencies.okhttp3compile rootProject.ext.dependencies.gsoncompile rootProject.ext.dependencies.glidecompile rootProject.ext.dependencies.eventBuscompile rootProject.ext.dependencies.dagger2compile(rootProject.ext.dependencies.rxpermission) {exclude module: 'rxjava'}compile rootProject.ext.dependencies.retrofit_converter_scalarsannotationProcessor rootProject.ext.dependencies.dagger2_compilerannotationProcessor rootProject.ext.dependencies.butterknife_compilercompile rootProject.ext.dependencies.butterknifecompile rootProject.ext.dependencies.transformationscompile rootProject.ext.dependencies.arouter_api
}

9.组件化与热修复的无缝连接

本开源项目是基于腾讯的bugly平台,用于监控异常信息、热修复和应用升级。
具体实现:
1、在工程的根目录build.gradle配置

buildscript {repositories {jcenter()}dependencies {classpath "com.tencent.bugly:tinker-support:1.0.8"}
}

然后在App 的build.gradle进行以下配置

dependencies {compile fileTree(include: ['*.jar'], dir: 'libs')androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {exclude group: 'com.android.support', module: 'support-annotations'})if (!rootProject.ext.isAlone) {compile project(':chat')compile project(':music')compile project(':news')compile project(':live')apt rootProject.ext.dependencies.arouter_compiler} else {compile project(':commonlibrary')}testCompile 'junit:junit:4.12'
//  依赖bugly相关SDKcompile 'com.tencent.bugly:crashreport_upgrade:1.3.1'compile 'com.tencent.bugly:nativecrashreport:latest.release'
}
apply from: 'tinker-support.gradle'

然后依赖其中的插件脚本

apply from: 'tinker-support.gradle'

其中的tinker-support.gradle文件如下:

apply plugin: 'com.tencent.bugly.tinker-support'
def bakPath = file("${buildDir}/bakApk/")
/*** 此处填写每次构建生成的基准包目录*/
def baseApkDir = "app-0831-17-50-44"
/*** 对于插件各参数的详细解析请参考*/
tinkerSupport {// 开启tinker-support插件,默认值trueenable = true// 自动生成tinkerId, 你无须关注tinkerId,默认为falseautoGenerateTinkerId = true// 指定归档目录,默认值当前module的子目录tinkerautoBackupApkDir = "${bakPath}"// 是否启用覆盖tinkerPatch配置功能,默认值false// 开启后tinkerPatch配置不生效,即无需添加tinkerPatchoverrideTinkerPatchConfiguration = true// 编译补丁包时,必需指定基线版本的apk,默认值为空// 如果为空,则表示不是进行补丁包的编译// @{link tinkerPatch.oldApk }baseApk =  "${bakPath}/${baseApkDir}/app-release.apk"// 对应tinker插件applyMappingbaseApkProguardMapping = "${bakPath}/${baseApkDir}/app-release-mapping.txt"// 对应tinker插件applyResourceMappingbaseApkResourceMapping = "${bakPath}/${baseApkDir}/app-release-R.txt"// 构建基准包跟补丁包都要修改tinkerId,主要用于区分tinkerId = "1.0.5-base_patch"// 打多渠道补丁时指定目录// buildAllFlavorsDir = "${bakPath}/${baseApkDir}"// 是否使用加固模式,默认为false// isProtectedApp = true// 是否采用反射Application的方式集成,无须改造ApplicationenableProxyApplication = true
}
/*** 一般来说,我们无需对下面的参数做任何的修改* 对于各参数的详细介绍请参考:* https://github.com/Tencent/tinker/wiki/Tinker-%E6%8E%A5%E5%85%A5%E6%8C%87%E5%8D%97*/
tinkerPatch {tinkerEnable = trueignoreWarning = falseuseSign = truedex {dexMode = "jar"pattern = ["classes*.dex"]loader = []}lib {pattern = ["lib/*/*.so"]}res {pattern = ["res/*", "r/*", "assets/*", "resources.arsc", "AndroidManifest.xml"]ignoreChange = []largeModSize = 100}packageConfig {}sevenZip {zipArtifact = "com.tencent.mm:SevenZip:1.1.10"
//        path = "/usr/local/bin/7za"}buildConfig {keepDexApply = false
//      tinkerId = "base-2.0.1"}
}

然后需要在Manifest配置文件配置如下

<activityandroid:name="com.tencent.bugly.beta.ui.BetaActivity"   android:configChanges="keyboardHidden|orientation|screenSize|locale"android:theme="@android:style/Theme.Translucent" /><providerandroid:name="android.support.v4.content.FileProvider"android:authorities="${applicationId}.fileProvider"android:exported="false"android:grantUriPermissions="true"><meta-dataandroid:name="android.support.FILE_PROVIDER_PATHS"android:resource="@xml/provider_paths"/></provider>

最后在Application中初始化bugly

public class App extends BaseApplication {@Overridepublic void onCreate() {super.onCreate();setStrictMode();// 设置是否开启热更新能力,默认为trueBeta.enableHotfix = true;// 设置是否自动下载补丁Beta.canAutoDownloadPatch = true;// 设置是否提示用户重启Beta.canNotifyUserRestart = true;// 设置是否自动合成补丁Beta.canAutoPatch = true;/***  全量升级状态回调*/Beta.upgradeStateListener = new UpgradeStateListener() {@Overridepublic void onUpgradeFailed(boolean b) {}@Overridepublic void onUpgradeSuccess(boolean b) {}@Overridepublic void onUpgradeNoVersion(boolean b) {Toast.makeText(getApplicationContext(), "最新版本", Toast.LENGTH_SHORT).show();}@Overridepublic void onUpgrading(boolean b) {Toast.makeText(getApplicationContext(), "onUpgrading", Toast.LENGTH_SHORT).show();}@Overridepublic void onDownloadCompleted(boolean b) {}};/*** 补丁回调接口,可以监听补丁接收、下载、合成的回调*/Beta.betaPatchListener = new BetaPatchListener() {@Overridepublic void onPatchReceived(String patchFileUrl) {Toast.makeText(getApplicationContext(), patchFileUrl, Toast.LENGTH_SHORT).show();}@Overridepublic void onDownloadReceived(long savedLength, long totalLength) {Toast.makeText(getApplicationContext(), String.format(Locale.getDefault(),"%s %d%%",Beta.strNotificationDownloading,(int) (totalLength == 0 ? 0 : savedLength * 100 / totalLength)), Toast.LENGTH_SHORT).show();}@Overridepublic void onDownloadSuccess(String patchFilePath) {Toast.makeText(getApplicationContext(), patchFilePath, Toast.LENGTH_SHORT).show();
//                Beta.applyDownloadedPatch();}@Overridepublic void onDownloadFailure(String msg) {Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_SHORT).show();}@Overridepublic void onApplySuccess(String msg) {Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_SHORT).show();}@Overridepublic void onApplyFailure(String msg) {Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_SHORT).show();}@Overridepublic void onPatchRollback() {Toast.makeText(getApplicationContext(), "onPatchRollback", Toast.LENGTH_SHORT).show();}};long start = System.currentTimeMillis();// 这里实现SDK初始化,appId替换成你的在Bugly平台申请的appId,调试时将第三个参数设置为trueBugly.init(this, "2e5309db50", true);long end = System.currentTimeMillis();}@Overrideprotected void attachBaseContext(Context base) {super.attachBaseContext(base);// you must install multiDex whatever tinker is installed!MultiDex.install(base);// 安装tinkerBeta.installTinker();}@TargetApi(9)protected void setStrictMode() {StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder().permitAll().build());StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().detectAll().penaltyLog().build());}
}

10.参考的项目

MVPArms
github.com/JessYanCodi…
全民直播
github.com/jenly1314/K…
音乐项目
github.com/hefuyicoder…
github.com/aa112901/re…
大象:PHPHub客户端
github.com/Freelander/…
MvpApp
github.com/Rukey7/MvpA…
CloudReader
github.com/youlookwhat…
非常感谢以上开源项目的作者!谢谢!

11.结束语

该组件框架是自己在暑假实习期间做的,由于实习公司的项目过于庞大和复杂,每次编译都需要花费10几分钟,心都碎了,所以才想尝试下组件化框架,摸索了很长时间,最后还是做出来了,大概花费2个多月的时间,由于最近项目上比较忙,所以没什么时间来完善,界面有点简陋,但逻辑基本实现了。

 

查看全文
如若内容造成侵权/违法违规/事实不符,请联系编程学习网邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

相关文章

  1. Android Studio 3.0找不到Android Device Monitor

    前提:一定要root 找到SDK目录文件夹tools下,然后输入命令montior,或者直接双击montior.bat文件。就会出现界面:然后进入skd/D:\SDK\platform-tools中执行命令: adb shell , 解决办法:要想查看data文件首先要获取手机root权限,成功root后,修改data权限即可查看data里面…...

    2024/5/1 21:48:40
  2. MongoDB单机集群搭建

    一、单机副本集部署方案: 单台物理机,一个主节点,一个副本节点,一个仲裁节点。 二、部署步骤 1、在mongodb目录下新建config目录(目录及位置可随意指定,在此按照config目录搭建),在config目录中新建主节点配置文件primary.conf (文件名可随意指定): [root@Thor conf…...

    2024/4/23 14:50:21
  3. lab05 IP地址OSPF配置

    lab05:IP地址OSPF配置 1、 IP:loopback0为VTEP,10.1.1.1 10.2.2.2 10.3.3.3 10.45.45.45 2、 Loopback1为router-id 3、 IGP,配置设备或故障为stub路由器,保持时间600s,优化ospf默认邻居建立收敛时间。 4、 Underlay网络中IP Fabric使用OSPF,并在leaf-1A、2A、2B、3…...

    2024/4/23 14:50:13
  4. 应用服务器/中间件漏洞总目录

    目录 WebLogic – 概述 – 漏洞 IIS – 概述 – 漏洞 Tomcat – 概述 – 漏洞 Apache – 概述 – 漏洞 JBOSS – 概述 – 漏洞 Nginx – 概述 – 漏洞 WebSphere – 概述 – 漏洞 Resin – 概述 – 漏洞 lighttpd – 概述 – 漏洞...

    2024/4/23 14:50:15
  5. 具有翻转效果的登录和注册页面(代码实现)

    HTML代码:<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><link rel="st…...

    2024/4/23 14:50:14
  6. C++ Primer Plus 第三章编程练习答案

    C++ Primer Plus 第三章编程练习答案 之前在学习 C++ Primer Plus这本书的时候,每章后面的练习都没找到答案,在GitHub上找到了一个项目:https://github.com/PytLab/Cpp-Primer-Plus 但是这个项目仔细看虽然答案很齐全 但是小错误有点多,于是我在这里分享下我的答案,不定期…...

    2024/4/23 14:50:10
  7. TCP通信服务器端实现第三步:调用listen 网络API,将套接字文件描述符,从主动变为被动文件描述符【linux】(zzv)

    listen函数函数原型功能返回值参数sockfdbacklog代码演示TCP服务器为什么要listen listen函数 函数原型 #include <sys/types.h> /* See NOTES */ #include <sys/socket.h> int listen(int sockfd, int backlog);功能 将套接字文件描述符,从主动文件描述…...

    2024/4/23 14:50:12
  8. Nginx + fastdfs的安装

    Nginx的安装可以直接查看《Linux安装nginx》 Github直通车 环境准备Centos7.x 两台,分别安装tracker与storage 下载安装包:libfatscommon:FastDFS分离出的一些公用函数包 FastDFS:FastDFS本体 fastdfs-nginx-module:FastDFS和nginx的关联模块 nginx:发布访问服务安装步骤…...

    2024/4/23 14:50:15
  9. 【Python】第012课,定义和使用列表,列表的运算符,列表元素的遍历i,列表的方法,元素位置和次数,元素排序和反转。

    目录定义和使用列表列表的运算符列表元素的遍历列表的方法元素位置和次数元素排序和反转定义和使用列表在Python中,列表是由一系元素按特定顺序构成的数据序列,这样就意味着定义一个列表类型的变量,可以保存多个数据,而且允许有重复的数据。跟上一课我们讲到的字符串类型一…...

    2024/5/1 22:31:00
  10. React小书没提到但是很有用的基础知识

    ReactDom.render渲染多个元素时需要包裹起来,但是不一定用div,也可以用其他的 1、<>yuan<> 2、ul等...

    2024/4/30 15:22:56
  11. 基于ensp的BGP组网实验2

    BGP组网实验2图1 网络拓扑图 对R6路由器进行基础配置 [Huawei]interface loopback 1 [Huawei-LoopBack1]ip address 1.1.1.1 255.0.0.0 [Huawei-LoopBack1]interface loopback 2 [Huawei-LoopBack2]ip address 6.6.6.6 255.0.0.0 [Huawei-LoopBack2]quit [Huawei]interface Et…...

    2024/4/17 5:45:46
  12. vscode搭建java开发环境 第三方包发QQ邮件

    配置setting.json 为下载的mail.jar包,activation.jar包找个家,不需要手动添加到classpath环境变量。邮件发送源码 用QQ邮箱发送,主要有两个点,一是获取授权码 二是发送,需要实现认证行为类实现作为Session保持会话 import java.util.Properties;import javax.mail.Authen…...

    2024/5/1 21:42:16
  13. NodeJS中的api之----fs的用法

    获取文件信息const fs=require(fs)fs.stat(spider.js,(error,stats)=>{if(error){console.log(error)}else{console.log(stats)console.log(`文件:${stats.isFile()}`)console.log(`目录:${stats.isDirectory()}`)} })2、使用mkdir创建目录 const fs=require(fs)fs.mkdir(lo…...

    2024/4/19 15:48:41
  14. 简单-LeetCode 面试题 01.02. 判定是否互为字符重排

    题目 来源:判定是否互为字符重排 给定两个字符串 s1 和 s2,请编写一个程序,确定其中一个字符串的字符重新排列后,能否变成另一个字符串。 示例解题思路及代码 1. 思路 暴力解法:遍历s1,若s2中包含该字母,则删除。当遍历至某个字母,s2中没有,则返回false;若遍历完s1,s…...

    2024/4/19 20:04:27
  15. 软连接和硬链接的区别

    定义不同软链接又叫符号链接,这个文件包含了另一个文件的路径名。可以是任意文件或目录,可以链接不同文件系统的文件。硬链接就是一个文件的一个或多个文件名。把文件名和计算机文件系统使用的节点号链接起来(目的是为了找到真正的文件)。因此我们可以用多个文件名与同一个…...

    2024/4/17 5:46:04
  16. Spring Boot中常见注解诠释

    一:@Mapper和@MapperScan 1、@Mapper @Mapper 将接口交给Spring进行管理,为这个接口生成一个实现类,让别的类进行引用、不再写mapper映射文件。 @Mapper //该注解将接口变成Spring容器中的一个bean public interface UserMapper {public List<User> findAll(); }2、@M…...

    2024/4/18 22:27:48
  17. 《深入浅出》Apache Dubbo与实战

    在Apache Dubbo (以下简称Dubbo)重新开源之前,Dubbo已经被很多公司广泛用于生产环境并获得了良好的反馈,很多公司内部也会建立私有分支自己维护,其中Dubbox就是基于Dubbo分支进行扩展并二次维护的。重新开源后,社区维护的Dubbo版本进行了大量“bug fix"和特性支持,收…...

    2024/4/18 4:13:02
  18. MapReduce 快速入门

    文章目录1. MapReduce 概述1.1 MapReduce 定义1.2 MapReduce 优缺点1.3 MapReduce 核心思想1.4 MapReduce 进程1.5 MapReduce 编程规范1.6 WordCount 案例实操1.6.1 需求1.6.2 需求分析1.6.3 编写程序2. Hadoop 序列化2.1 序列化概述2.2 自定义 bean 对象实现序列化接口2.3 序列…...

    2024/4/25 11:52:49
  19. Linux软件安装新方法

    文章目录linux一.前言二.原理理解三.方法四.总结 linux 一.前言 我们都知道 linux安装软件直接用apt install + 软件名称(输入应用名称如果系统内没有安装的话都会有下面的提示安装) 问题来了,这种是在有外网的情况下可以下载应用,如果没用网络我们应该如何安装 Linux和win…...

    2024/4/23 14:50:08
  20. python 列表生成器

    列表生成式:用来生成列表,在元列表的基础上生成一个新列表,可以让代码更简洁 格式 1: [exp for var in iterable] exp:表达式 var:变量 iterable:可迭代对象 执行过程: 1,先遍历可迭代对象中的元素 2,将此元素赋值给var 3,将var的值作用到exp这个表达式上 4,将表达式的…...

    2024/4/23 14:50:04

最新文章

  1. 踏上R语言之旅:解锁数据世界的神秘密码(三)

    多元相关与回归分析及R使用 文章目录 多元相关与回归分析及R使用一.变量间的关系分析1.两变量线性相关系数的计算2.相关系数的假设检验 二.一元线性回归分析的R计算三、回归系数的假设检验总结 一.变量间的关系分析 变量间的关系及分析方法如下&#xff1a; 1.两变量线性相关…...

    2024/5/1 22:28:37
  2. 梯度消失和梯度爆炸的一些处理方法

    在这里是记录一下梯度消失或梯度爆炸的一些处理技巧。全当学习总结了如有错误还请留言&#xff0c;在此感激不尽。 权重和梯度的更新公式如下&#xff1a; w w − η ⋅ ∇ w w w - \eta \cdot \nabla w ww−η⋅∇w 个人通俗的理解梯度消失就是网络模型在反向求导的时候出…...

    2024/3/20 10:50:27
  3. javaWeb网上零食销售系统

    1 绪 论 目前&#xff0c;我国的网民数量已经达到7.31亿人&#xff0c;随着互联网购物和互联网支付的普及&#xff0c;使得人类的经济活动进入了一个崭新的时代。淘宝&#xff0c;京东等网络消费平台功能的日益完善&#xff0c;使得人们足不出户就可以得到自己想要的东西。如今…...

    2024/5/1 12:59:25
  4. ssm框架中各层级介绍

    1、Spring&#xff08;业务逻辑层&#xff09;&#xff1a; Spring框架提供了依赖注入&#xff08;DI&#xff09;和面向切面编程&#xff08;AOP&#xff09;等功能&#xff0c;可以帮助管理Java应用程序中的对象依赖关系和提供横切关注点的支持。 在SSM框架中&#xff0c;S…...

    2024/4/30 2:49:54
  5. 【外汇早评】美通胀数据走低,美元调整

    原标题:【外汇早评】美通胀数据走低,美元调整昨日美国方面公布了新一期的核心PCE物价指数数据,同比增长1.6%,低于前值和预期值的1.7%,距离美联储的通胀目标2%继续走低,通胀压力较低,且此前美国一季度GDP初值中的消费部分下滑明显,因此市场对美联储后续更可能降息的政策…...

    2024/5/1 17:30:59
  6. 【原油贵金属周评】原油多头拥挤,价格调整

    原标题:【原油贵金属周评】原油多头拥挤,价格调整本周国际劳动节,我们喜迎四天假期,但是整个金融市场确实流动性充沛,大事频发,各个商品波动剧烈。美国方面,在本周四凌晨公布5月份的利率决议和新闻发布会,维持联邦基金利率在2.25%-2.50%不变,符合市场预期。同时美联储…...

    2024/4/30 18:14:14
  7. 【外汇周评】靓丽非农不及疲软通胀影响

    原标题:【外汇周评】靓丽非农不及疲软通胀影响在刚结束的周五,美国方面公布了新一期的非农就业数据,大幅好于前值和预期,新增就业重新回到20万以上。具体数据: 美国4月非农就业人口变动 26.3万人,预期 19万人,前值 19.6万人。 美国4月失业率 3.6%,预期 3.8%,前值 3…...

    2024/4/29 2:29:43
  8. 【原油贵金属早评】库存继续增加,油价收跌

    原标题:【原油贵金属早评】库存继续增加,油价收跌周三清晨公布美国当周API原油库存数据,上周原油库存增加281万桶至4.692亿桶,增幅超过预期的74.4万桶。且有消息人士称,沙特阿美据悉将于6月向亚洲炼油厂额外出售更多原油,印度炼油商预计将每日获得至多20万桶的额外原油供…...

    2024/4/30 18:21:48
  9. 【外汇早评】日本央行会议纪要不改日元强势

    原标题:【外汇早评】日本央行会议纪要不改日元强势近两日日元大幅走强与近期市场风险情绪上升,避险资金回流日元有关,也与前一段时间的美日贸易谈判给日本缓冲期,日本方面对汇率问题也避免继续贬值有关。虽然今日早间日本央行公布的利率会议纪要仍然是支持宽松政策,但这符…...

    2024/4/27 17:58:04
  10. 【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响

    原标题:【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响近日伊朗局势升温,导致市场担忧影响原油供给,油价试图反弹。此时OPEC表态稳定市场。据消息人士透露,沙特6月石油出口料将低于700万桶/日,沙特已经收到石油消费国提出的6月份扩大出口的“适度要求”,沙特将满…...

    2024/4/27 14:22:49
  11. 【外汇早评】美欲与伊朗重谈协议

    原标题:【外汇早评】美欲与伊朗重谈协议美国对伊朗的制裁遭到伊朗的抗议,昨日伊朗方面提出将部分退出伊核协议。而此行为又遭到欧洲方面对伊朗的谴责和警告,伊朗外长昨日回应称,欧洲国家履行它们的义务,伊核协议就能保证存续。据传闻伊朗的导弹已经对准了以色列和美国的航…...

    2024/4/28 1:28:33
  12. 【原油贵金属早评】波动率飙升,市场情绪动荡

    原标题:【原油贵金属早评】波动率飙升,市场情绪动荡因中美贸易谈判不安情绪影响,金融市场各资产品种出现明显的波动。随着美国与中方开启第十一轮谈判之际,美国按照既定计划向中国2000亿商品征收25%的关税,市场情绪有所平复,已经开始接受这一事实。虽然波动率-恐慌指数VI…...

    2024/4/30 9:43:09
  13. 【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试

    原标题:【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试美国和伊朗的局势继续升温,市场风险情绪上升,避险黄金有向上突破阻力的迹象。原油方面稍显平稳,近期美国和OPEC加大供给及市场需求回落的影响,伊朗局势并未推升油价走强。近期中美贸易谈判摩擦再度升级,美国对中…...

    2024/4/27 17:59:30
  14. 【原油贵金属早评】市场情绪继续恶化,黄金上破

    原标题:【原油贵金属早评】市场情绪继续恶化,黄金上破周初中国针对于美国加征关税的进行的反制措施引发市场情绪的大幅波动,人民币汇率出现大幅的贬值动能,金融市场受到非常明显的冲击。尤其是波动率起来之后,对于股市的表现尤其不安。隔夜美国股市出现明显的下行走势,这…...

    2024/4/25 18:39:16
  15. 【外汇早评】美伊僵持,风险情绪继续升温

    原标题:【外汇早评】美伊僵持,风险情绪继续升温昨日沙特两艘油轮再次发生爆炸事件,导致波斯湾局势进一步恶化,市场担忧美伊可能会出现摩擦生火,避险品种获得支撑,黄金和日元大幅走强。美指受中美贸易问题影响而在低位震荡。继5月12日,四艘商船在阿联酋领海附近的阿曼湾、…...

    2024/4/28 1:34:08
  16. 【原油贵金属早评】贸易冲突导致需求低迷,油价弱势

    原标题:【原油贵金属早评】贸易冲突导致需求低迷,油价弱势近日虽然伊朗局势升温,中东地区几起油船被袭击事件影响,但油价并未走高,而是出于调整结构中。由于市场预期局势失控的可能性较低,而中美贸易问题导致的全球经济衰退风险更大,需求会持续低迷,因此油价调整压力较…...

    2024/4/26 19:03:37
  17. 氧生福地 玩美北湖(上)——为时光守候两千年

    原标题:氧生福地 玩美北湖(上)——为时光守候两千年一次说走就走的旅行,只有一张高铁票的距离~ 所以,湖南郴州,我来了~ 从广州南站出发,一个半小时就到达郴州西站了。在动车上,同时改票的南风兄和我居然被分到了一个车厢,所以一路非常愉快地聊了过来。 挺好,最起…...

    2024/4/29 20:46:55
  18. 氧生福地 玩美北湖(中)——永春梯田里的美与鲜

    原标题:氧生福地 玩美北湖(中)——永春梯田里的美与鲜一觉醒来,因为大家太爱“美”照,在柳毅山庄去寻找龙女而错过了早餐时间。近十点,向导坏坏还是带着饥肠辘辘的我们去吃郴州最富有盛名的“鱼头粉”。说这是“十二分推荐”,到郴州必吃的美食之一。 哇塞!那个味美香甜…...

    2024/4/30 22:21:04
  19. 氧生福地 玩美北湖(下)——奔跑吧骚年!

    原标题:氧生福地 玩美北湖(下)——奔跑吧骚年!让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 啊……啊……啊 两…...

    2024/5/1 4:32:01
  20. 扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!

    原标题:扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!扒开伪装医用面膜,翻六倍价格宰客!当行业里的某一品项火爆了,就会有很多商家蹭热度,装逼忽悠,最近火爆朋友圈的医用面膜,被沾上了污点,到底怎么回事呢? “比普通面膜安全、效果好!痘痘、痘印、敏感肌都能用…...

    2024/4/27 23:24:42
  21. 「发现」铁皮石斛仙草之神奇功效用于医用面膜

    原标题:「发现」铁皮石斛仙草之神奇功效用于医用面膜丽彦妆铁皮石斛医用面膜|石斛多糖无菌修护补水贴19大优势: 1、铁皮石斛:自唐宋以来,一直被列为皇室贡品,铁皮石斛生于海拔1600米的悬崖峭壁之上,繁殖力差,产量极低,所以古代仅供皇室、贵族享用 2、铁皮石斛自古民间…...

    2024/4/28 5:48:52
  22. 丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者

    原标题:丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者【公司简介】 广州华彬企业隶属香港华彬集团有限公司,专注美业21年,其旗下品牌: 「圣茵美」私密荷尔蒙抗衰,产后修复 「圣仪轩」私密荷尔蒙抗衰,产后修复 「花茵莳」私密荷尔蒙抗衰,产后修复 「丽彦妆」专注医学护…...

    2024/4/30 9:42:22
  23. 广州械字号面膜生产厂家OEM/ODM4项须知!

    原标题:广州械字号面膜生产厂家OEM/ODM4项须知!广州械字号面膜生产厂家OEM/ODM流程及注意事项解读: 械字号医用面膜,其实在我国并没有严格的定义,通常我们说的医美面膜指的应该是一种「医用敷料」,也就是说,医用面膜其实算作「医疗器械」的一种,又称「医用冷敷贴」。 …...

    2024/4/30 9:43:22
  24. 械字号医用眼膜缓解用眼过度到底有无作用?

    原标题:械字号医用眼膜缓解用眼过度到底有无作用?医用眼膜/械字号眼膜/医用冷敷眼贴 凝胶层为亲水高分子材料,含70%以上的水分。体表皮肤温度传导到本产品的凝胶层,热量被凝胶内水分子吸收,通过水分的蒸发带走大量的热量,可迅速地降低体表皮肤局部温度,减轻局部皮肤的灼…...

    2024/4/30 9:42:49
  25. 配置失败还原请勿关闭计算机,电脑开机屏幕上面显示,配置失败还原更改 请勿关闭计算机 开不了机 这个问题怎么办...

    解析如下&#xff1a;1、长按电脑电源键直至关机&#xff0c;然后再按一次电源健重启电脑&#xff0c;按F8健进入安全模式2、安全模式下进入Windows系统桌面后&#xff0c;按住“winR”打开运行窗口&#xff0c;输入“services.msc”打开服务设置3、在服务界面&#xff0c;选中…...

    2022/11/19 21:17:18
  26. 错误使用 reshape要执行 RESHAPE,请勿更改元素数目。

    %读入6幅图像&#xff08;每一幅图像的大小是564*564&#xff09; f1 imread(WashingtonDC_Band1_564.tif); subplot(3,2,1),imshow(f1); f2 imread(WashingtonDC_Band2_564.tif); subplot(3,2,2),imshow(f2); f3 imread(WashingtonDC_Band3_564.tif); subplot(3,2,3),imsho…...

    2022/11/19 21:17:16
  27. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机...

    win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”问题的解决方法在win7系统关机时如果有升级系统的或者其他需要会直接进入一个 等待界面&#xff0c;在等待界面中我们需要等待操作结束才能关机&#xff0c;虽然这比较麻烦&#xff0c;但是对系统进行配置和升级…...

    2022/11/19 21:17:15
  28. 台式电脑显示配置100%请勿关闭计算机,“准备配置windows 请勿关闭计算机”的解决方法...

    有不少用户在重装Win7系统或更新系统后会遇到“准备配置windows&#xff0c;请勿关闭计算机”的提示&#xff0c;要过很久才能进入系统&#xff0c;有的用户甚至几个小时也无法进入&#xff0c;下面就教大家这个问题的解决方法。第一种方法&#xff1a;我们首先在左下角的“开始…...

    2022/11/19 21:17:14
  29. win7 正在配置 请勿关闭计算机,怎么办Win7开机显示正在配置Windows Update请勿关机...

    置信有很多用户都跟小编一样遇到过这样的问题&#xff0c;电脑时发现开机屏幕显现“正在配置Windows Update&#xff0c;请勿关机”(如下图所示)&#xff0c;而且还需求等大约5分钟才干进入系统。这是怎样回事呢&#xff1f;一切都是正常操作的&#xff0c;为什么开时机呈现“正…...

    2022/11/19 21:17:13
  30. 准备配置windows 请勿关闭计算机 蓝屏,Win7开机总是出现提示“配置Windows请勿关机”...

    Win7系统开机启动时总是出现“配置Windows请勿关机”的提示&#xff0c;没过几秒后电脑自动重启&#xff0c;每次开机都这样无法进入系统&#xff0c;此时碰到这种现象的用户就可以使用以下5种方法解决问题。方法一&#xff1a;开机按下F8&#xff0c;在出现的Windows高级启动选…...

    2022/11/19 21:17:12
  31. 准备windows请勿关闭计算机要多久,windows10系统提示正在准备windows请勿关闭计算机怎么办...

    有不少windows10系统用户反映说碰到这样一个情况&#xff0c;就是电脑提示正在准备windows请勿关闭计算机&#xff0c;碰到这样的问题该怎么解决呢&#xff0c;现在小编就给大家分享一下windows10系统提示正在准备windows请勿关闭计算机的具体第一种方法&#xff1a;1、2、依次…...

    2022/11/19 21:17:11
  32. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”的解决方法...

    今天和大家分享一下win7系统重装了Win7旗舰版系统后&#xff0c;每次关机的时候桌面上都会显示一个“配置Windows Update的界面&#xff0c;提示请勿关闭计算机”&#xff0c;每次停留好几分钟才能正常关机&#xff0c;导致什么情况引起的呢&#xff1f;出现配置Windows Update…...

    2022/11/19 21:17:10
  33. 电脑桌面一直是清理请关闭计算机,windows7一直卡在清理 请勿关闭计算机-win7清理请勿关机,win7配置更新35%不动...

    只能是等着&#xff0c;别无他法。说是卡着如果你看硬盘灯应该在读写。如果从 Win 10 无法正常回滚&#xff0c;只能是考虑备份数据后重装系统了。解决来方案一&#xff1a;管理员运行cmd&#xff1a;net stop WuAuServcd %windir%ren SoftwareDistribution SDoldnet start WuA…...

    2022/11/19 21:17:09
  34. 计算机配置更新不起,电脑提示“配置Windows Update请勿关闭计算机”怎么办?

    原标题&#xff1a;电脑提示“配置Windows Update请勿关闭计算机”怎么办&#xff1f;win7系统中在开机与关闭的时候总是显示“配置windows update请勿关闭计算机”相信有不少朋友都曾遇到过一次两次还能忍但经常遇到就叫人感到心烦了遇到这种问题怎么办呢&#xff1f;一般的方…...

    2022/11/19 21:17:08
  35. 计算机正在配置无法关机,关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机...

    关机提示 windows7 正在配置windows 请勿关闭计算机 &#xff0c;然后等了一晚上也没有关掉。现在电脑无法正常关机以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;关机提示 windows7 正在配…...

    2022/11/19 21:17:05
  36. 钉钉提示请勿通过开发者调试模式_钉钉请勿通过开发者调试模式是真的吗好不好用...

    钉钉请勿通过开发者调试模式是真的吗好不好用 更新时间:2020-04-20 22:24:19 浏览次数:729次 区域: 南阳 > 卧龙 列举网提醒您:为保障您的权益,请不要提前支付任何费用! 虚拟位置外设器!!轨迹模拟&虚拟位置外设神器 专业用于:钉钉,外勤365,红圈通,企业微信和…...

    2022/11/19 21:17:05
  37. 配置失败还原请勿关闭计算机怎么办,win7系统出现“配置windows update失败 还原更改 请勿关闭计算机”,长时间没反应,无法进入系统的解决方案...

    前几天班里有位学生电脑(windows 7系统)出问题了&#xff0c;具体表现是开机时一直停留在“配置windows update失败 还原更改 请勿关闭计算机”这个界面&#xff0c;长时间没反应&#xff0c;无法进入系统。这个问题原来帮其他同学也解决过&#xff0c;网上搜了不少资料&#x…...

    2022/11/19 21:17:04
  38. 一个电脑无法关闭计算机你应该怎么办,电脑显示“清理请勿关闭计算机”怎么办?...

    本文为你提供了3个有效解决电脑显示“清理请勿关闭计算机”问题的方法&#xff0c;并在最后教给你1种保护系统安全的好方法&#xff0c;一起来看看&#xff01;电脑出现“清理请勿关闭计算机”在Windows 7(SP1)和Windows Server 2008 R2 SP1中&#xff0c;添加了1个新功能在“磁…...

    2022/11/19 21:17:03
  39. 请勿关闭计算机还原更改要多久,电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机怎么办...

    许多用户在长期不使用电脑的时候&#xff0c;开启电脑发现电脑显示&#xff1a;配置windows更新失败&#xff0c;正在还原更改&#xff0c;请勿关闭计算机。。.这要怎么办呢&#xff1f;下面小编就带着大家一起看看吧&#xff01;如果能够正常进入系统&#xff0c;建议您暂时移…...

    2022/11/19 21:17:02
  40. 还原更改请勿关闭计算机 要多久,配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以...

    配置windows update失败 还原更改 请勿关闭计算机&#xff0c;电脑开机后一直显示以以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;配置windows update失败 还原更改 请勿关闭计算机&#x…...

    2022/11/19 21:17:01
  41. 电脑配置中请勿关闭计算机怎么办,准备配置windows请勿关闭计算机一直显示怎么办【图解】...

    不知道大家有没有遇到过这样的一个问题&#xff0c;就是我们的win7系统在关机的时候&#xff0c;总是喜欢显示“准备配置windows&#xff0c;请勿关机”这样的一个页面&#xff0c;没有什么大碍&#xff0c;但是如果一直等着的话就要两个小时甚至更久都关不了机&#xff0c;非常…...

    2022/11/19 21:17:00
  42. 正在准备配置请勿关闭计算机,正在准备配置windows请勿关闭计算机时间长了解决教程...

    当电脑出现正在准备配置windows请勿关闭计算机时&#xff0c;一般是您正对windows进行升级&#xff0c;但是这个要是长时间没有反应&#xff0c;我们不能再傻等下去了。可能是电脑出了别的问题了&#xff0c;来看看教程的说法。正在准备配置windows请勿关闭计算机时间长了方法一…...

    2022/11/19 21:16:59
  43. 配置失败还原请勿关闭计算机,配置Windows Update失败,还原更改请勿关闭计算机...

    我们使用电脑的过程中有时会遇到这种情况&#xff0c;当我们打开电脑之后&#xff0c;发现一直停留在一个界面&#xff1a;“配置Windows Update失败&#xff0c;还原更改请勿关闭计算机”&#xff0c;等了许久还是无法进入系统。如果我们遇到此类问题应该如何解决呢&#xff0…...

    2022/11/19 21:16:58
  44. 如何在iPhone上关闭“请勿打扰”

    Apple’s “Do Not Disturb While Driving” is a potentially lifesaving iPhone feature, but it doesn’t always turn on automatically at the appropriate time. For example, you might be a passenger in a moving car, but your iPhone may think you’re the one dri…...

    2022/11/19 21:16:57