前语
最近发现这个项目好似迎来了第二春,GitHub上的Start和Fork增加的很快,我的猜测是学生在经过这个项目来学习和完结自己的作业。跟着Android版别的更新,Android Studio的更新,项目中一些内容不能在新版别中很好的运用,乃至呈现编译不了的状况,这对我来说没啥,但是关于拿到项目满心欢喜的学生来说,运转不了,无疑是丧命的,而我写在项目Readme下面我将演示一下怎样在本地运转这个项目的代码。
正文
在之前写代码的时分还是有一些细节没有做到位,例如代码版别的办理就没有做,导致你看过前几篇文章,跟着写遇到问题,想要看源码,发现源码没有差异章节,而是全体一同的,这无疑给学习的同学造成了费事,那么我这篇文章在写之前将之前的代码增加到一个分支中,你学习的话先下载分支的代码,然后跟着写,写完之后便是当时最新的版别代码,这儿的版别是2.8。项目地址:GoogWeather
你切换到Release_2.8再去下载便是之前的一切代码,下载代码你必定会吧。
一、新版Android Studio编译运转
下载代码之后,咱们就需求在Android Studio中运转,这儿咱们能够运用Google官网中最新的AS版别,这儿我运用的版别如下图所示:
这儿的版别是海豚,也归于比较新的版别了。你现在下载的或许比这个还要新一点,不过也没联系,操作办法是相同的,由于我开端写这个项目的时分是20年4月份,那时分用的是Android Studio3.5.2,和现在的新版别差别还是蛮大的,下面咱们经过AS翻开这个项目。
翻开之后AS会查看你这个项目采用的是什么版别的gradle,假如查看到当时电脑环境没有此项目中的gradle,就会下载,这儿要留意网络环境问题,假如一个网络环境不行就切换其他的网络环境,例如换个WIFI,运用手机热点等办法。
下载好之后AS就会依据这个gradle来编译你的项目,留意一点,高版别AS能够编译低版别的项目,而假如低版别AS项目编译gradle版别高于AS本身gradle版别的项目,则需求下降项目版别,或许提高AS版别,这两种办法就不打开讲了。还有一点便是编译的时分和项目的JDK也有联系,例如我之前的项目采用的JDK是1.8,AS中自带了两个1.8和11两个版别,新项目都是采用11的版别。JDK没有问题之后就会下载你的项目所依靠的长途仓库代码,下载之后再进行编译。这个进程或许会比较长,和项目所运用的库多少及当时网速快慢有关。最终一点,项目运用的Android SDK是28,因而会在编译进程中,提示你下载28的SDK,下载之后再编译就好了,现在我编译了20分钟,总算编译完结了。
① 升级项目gradle版别
在编译完结之后,你或许会看到这样一个提示窗口。
在Android Studio的右下角呈现,什么状况下会呈现呢?当你的项目gradle版别与当时AS的gradle版别不匹配时就会呈现,咱们点击这个upgraded,呈现弹窗。
点击Begin Upgrade ,开端升级项目的gradle版别。
这儿点击Run Selected Steps,运转选中进程。相同会下载gradle版别,这儿下载的是6.7.1,下载完会进行编译。这个进程大约也要十几分钟,完结后,再看。
然后经过下拉框,将4.2.2改成7.3.0,再点击Run Selected Steps,这儿也需求一点时间。
这儿只剩下最终一步了,最终这个是主张进程,可做可不做。
② 切换JDK版别
做完之后,咱们运转一下,然后会遇到一个问题。
咱们的项目之前采用1.8,而现在更新了项目的gradle版别,这个版别最低要求是11,所以咱们需求更改项目的JDK版别。怎样修正呢?点击File → Settings… → Gradle。
这儿会看到Gradle JDK是1.8,点击右边的下拉按钮,咱们切换到11
然后点击 Apply 按钮,运用一下方才的修正,再点击 OK 封闭这个窗口,然后咱们再运转一下,这儿要用真机运转。由于虚拟机缺少定位传感器,一同SDK纷歧定兼容虚拟机。
③ BuildConfig报错
运转后发现报错了。
修正的办法很简略,如下图所示,咱们补全一下报名就能够了。
下面没有报错了,咱们再运转一下:
OK,没有问题,现在能够正常运转了,查看一下布局预览是否能正常显现。布局预览没有问题,那么咱们的项目也在新版别的AS上面跑起来了。在你们哪里纷歧定能定位成功,由于还需求修正一个当地。
二、百度的SDK运用
鉴权失利,这个会导致无法进行定位,下面说一下这个问题是怎样产生和处理的。
这儿要留意一个问题,首要你在百度地图开放渠道上是否创立了运用,没有创立的话,你就需求去创立。创立运用的办法,在天气App的榜首篇文章中现已说明晰,先不要着急去看,听我说完,创立运用需求几个条件,发布版SHA1、开发版SHA1、运用包名。
① 开发版SHA1的效果是什么?
开发版SHA1是让你能够在debug运转形式下运用SDK中的功用,留意这个debug运转要在真机上,不要妄想运用虚拟机或许模拟器,问题一大堆,你要是愿意死磕,也能够,鱼死不死不好说,但网必定破。
② 什么时分需求替换开发版SHA1?
开发版SHA1跟着你本地的环境改动而改动,就拿咱们当时这种状况来说,本地没有项目,下载下来到AS中进行编译,这时就需求替换开发版SHA1的值,假如你之前没有创立百度地图渠道运用的话,则便是在创立运用的时分将开发版SHA1填进去。另一种状况,比方之前的项目在文件夹A下,现在你挪到文件夹B下,那么你相同需求再次获取项目的开发版SHA1的值,更新渠道上的开发版SHA1值。
③ 怎样获取开发版SHA1?
由于Android Studio版别发生了改动,获取开发版SHA1的获取办法也相同改动了,在你准备获取SHA1版别之后请先装备好Java JDK的环境变量,再来操作。假设你现已装备好了环境变量,下面进行开发版SHA1的获取,Win + R ,输入cmd,进入指令窗口。
cd .android
先切换到.android目录下,然后输入keytool -list -v -keystore debug.keystore。
keytool -list -v -keystore debug.keystore
回车之后会让你输入密钥,默许的密钥便是android,你输入的时分是不行见的,光标也不会有反应,你只管输入就行,输入完回车就能看到SHA1了,如下图所示。
这儿的SHA1便是开发版SHA1,然后将SHA1值更新一下再保存。
现在你再运转一般来说就不会呈现定位不成功的状况,也不会呈现SDK鉴权失利的状况了。
④ 发布版SHA1的效果是什么?
开发版SHA1的效果是让你在电脑本地经过Android Studio调试运转的时分,能够运用正常运用SDK中功用。而一个运用你不或许只需自己在运用吧,你或许会发给别人,这个时分你就需求将项目打包成APK,将apk发布给别人装置,至于怎样打包,我也有文章说明,搜一下就能够了。而获取发布版SHA1,你需求先成功打一个包,然后再进行发布版SHA1的获取,详细的操作获取办法参考榜首篇文章,那个大体没有改动,只需最终不用挑选v1、v2。
三、依靠库更新
首要咱们需求修正app的build.gradle和mvplibrary的build.gradle。
app的build.gradle代码如下:
apply plugin: 'com.android.application'
android {
compileSdkVersion 31
defaultConfig {
applicationId "com.llw.goodweather"
minSdkVersion 21
targetSdkVersion 31
versionCode 1
versionName "2.8"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {//指定运用的JDK11
sourceCompatibility JavaVersion.VERSION_11
targetCompatibility JavaVersion.VERSION_11
}
// 自定义打包
android.applicationVariants.all { variant ->
variant.outputs.all {
outputFileName = "GoodWeather${variant.versionName}.apk"
}
}
sourceSets {
main {
jniLibs.srcDir 'libs'
//disable automatic ndk-build
}
}
namespace 'com.llw.goodweather'
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test:runner:1.4.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
//butterknife 这个部分比较特别,所以不管是模块还是项目里都要引入依靠,不然你的控件会报空目标
implementation 'com.jakewharton:butterknife:10.2.1'
annotationProcessor 'com.jakewharton:butterknife-compiler:10.2.0'
implementation project(':mvplibrary')//引入模块 然后将项目里的依靠移动到模块的build.gradle里
//Bugly SDK
implementation 'com.tencent.bugly:crashreport:3.4.4'
// 友盟根底组件库(一切友盟业务SDK都依靠根底组件库)
implementation "com.umeng.umsdk:common:9.5.2" //(必选)
implementation "com.umeng.umsdk:asms:1.4.1" // asms包依靠(必选)
implementation "com.umeng.umsdk:apm:1.7.0" // U-APM包依靠(必选)
}
api版别由28更改为31,一些依靠库的版别更新了,有第三方的,也有android自己的库,jdk版别也更新了。
下面是mvplibrary的build.gradle。
apply plugin: 'com.android.library'
android {
compileSdkVersion 31
defaultConfig {
minSdkVersion 21
targetSdkVersion 31
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles 'consumer-rules.pro'
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_11
targetCompatibility JavaVersion.VERSION_11
}
namespace 'com.llw.mvplibrary'
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
api 'androidx.appcompat:appcompat:1.4.1'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test:runner:1.4.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
//在模块中增加的依靠若想在项目中运用,则implementation改成api
//butterknife 绑定视图依靠BindView,离别findById,不过你还得装置一个butterknife插件才行
api 'com.jakewharton:butterknife:10.1.0'
annotationProcessor 'com.jakewharton:butterknife-compiler:10.1.0'
//Google Material控件,以及迁移到AndroidX下一些控件的依靠
api 'com.google.android.material:material:1.6.0'//更强
api 'androidx.lifecycle:lifecycle-extensions:2.2.0'
api 'androidx.annotation:annotation:1.3.0'
api 'androidx.legacy:legacy-support-v4:1.0.0'
//RecyclerView最好的适配器,让你的适配器一目了然,离别代码冗余
api 'com.github.CymChad:BaseRecyclerViewAdapterHelper:3.0.4'
//图片加载结构
api 'com.github.bumptech.glide:glide:4.10.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.10.0'
//权限请求结构
api 'com.tbruyelle.rxpermissions2:rxpermissions:0.9.4@aar'
//状态栏
api 'com.readystatesoftware.systembartint:systembartint:1.0.3'
//支持okhttp
api 'com.squareup.okhttp3:okhttp:3.14.9'
//retrofit2
api 'com.squareup.retrofit2:retrofit:2.9.0'
//这儿用api 是为了让其他模块也能够运用gson
api 'com.squareup.retrofit2:converter-gson:2.9.0'
//日志拦截器
api 'com.squareup.okhttp3:logging-interceptor:3.10.0'
api 'com.squareup.retrofit2:adapter-rxjava2:2.4.0'
//rxjava
api 'io.reactivex.rxjava2:rxandroid:2.1.1'
api 'io.reactivex.rxjava2:rxjava:2.2.12'
api 'androidx.preference:preference:1.2.0'
//阿里巴巴 FastJson
api 'com.alibaba:fastjson:1.2.57'
//下拉改写结构
api 'com.scwang.smartrefresh:SmartRefreshLayout:1.1.0-alpha-14'
//没有运用特别Header,能够不加这行
api 'com.scwang.smartrefresh:SmartRefreshHeader:1.1.0-alpha-14'
//自在嵌套的RadioGroup
api 'com.github.fodroid:XRadioGroup:v1.5'
//EventBus
api 'org.greenrobot:eventbus:3.1.1'
//蠕虫蠕动动画TabLayout
api 'com.ogaclejapan.smarttablayout:library:2.0.0@aar'
//Optional: see how to use the utility.
api 'com.ogaclejapan.smarttablayout:utils-v4:2.0.0@aar'
//Android SQLite操作结构
api 'org.litepal.guolindev:core:3.1.1'
//列表item侧滑删去
api 'com.github.mcxtzhang:SwipeDelMenuLayout:V1.3.0'
//下拉框
api 'com.github.arcadefire:nice-spinner:1.4.3'
}
① AndroidManifest.xml更新
这儿相同更改了一些库的版别,会造成什么问题咱们现在尚未可知,有问题再处理便是了,下面Sync Now,然后运转。
这儿呈现了问题,由于31表明Android 12,在Android 12中android:export需求显式指定元素<activitycom.llw.goodweather.ui.SplashActivity>。针对Android 12及更高版别的运用,当相应的组件定义了目的过滤器时,需求为“Android:exported”指定显式值。意思很明显咱们的发动页面,需求增加exported属性,并且值设置为true。在AndroidManifest.xml中找到SplashActivity。
修正后运转一下。
② BaseRecyclerViewAdapterHelper更新
这儿运用的是3.0.4版别,相较于之前的改版,改动不到,但由于一个类的途径更改,所以代码中涉及到的当地相同需求替换。
如图所示,咱们发现这个com.chad.library.adapter.base包下,现已没有这个BaseViewHolder
了,那么咱们重新导包试试看,将之前的那个报错的导报句子删去掉,然后鼠标悬停在BaseViewHolder上面。
运用方便键Alt + Enter进行导包,导包后会增加一行import代码:
import com.chad.library.adapter.base.viewholder.BaseViewHolder;
咱们再比照之前报错的那个导包句子看看
import com.chad.library.adapter.base.BaseViewHolder;
能够看到,差异只是新版别中多了一个viewholder包的层级,那么咱们就只需求将新的这个导报句子替换掉报错的导包句子即可,运用全局替换,方便键Ctrl + Shift + R 。
上面一行是本来的报错导包,下面这一行是咱们需求替换的导包句子,有21处需求替换,点击Replace All,替换一切,会弹窗提示你,问你是否确定要这么做,点击Replace。替换完结之后,咱们再运转试试看。
发现了一个新的过错,是增加点击工作的办法没有了,因而咱们还需求修正这个部分的代码。首要将
helper.addOnClickListener(R.id.item_city);
这行代码注释掉或许删掉,然后咱们进入运用适配器监听点击的当地,在MainActivity中,你找到如下图所示的代码:
这个OnItemChildClickListener
接口也没有了,那么咱们需求怎样增加子控件的点击工作呢?修正办法如下图所示:
这儿能够看到咱们经过
areaAdapter.addChildClickViewIds(R.id.item_city);
增加需求进行点击的控件Id,留意这儿能够是多个控件Id,例如:
areaAdapter.addChildClickViewIds(R.id.item_city, R.id.item_area);
你会发现new OnItemChildClickListener()是灰色的,这表明能够省掉掉,精简代码,运用Lambda表达式,点击灰色部分,运用方便键,Alt + Enter,回车呈现弹窗。
这儿点击Relpace with lambda选项,替换为lambda,替换后如下图所示。
这儿你能够替换也能够不替换,随你自己。关于适配器增加点击工作的办法你现已学会了,那么你能够更改其他的适配器中的点击办法了,这个就没有方便的办法了,你需求一个个去改,我就不重复说明晰。一切适配器改完之后再运转看看,哦豁,又报错了。
这个报错的原因是mContext值没有了,这是一个上下文,之前的依靠库版别中是有的,现在没有了,就需求替换了,将mContext,getContext()
即可,自行替换就好了。然后再运转你会发现,不报错了,能够运转了,这个库的问题改完了。但是还有一个躲藏问题在WallPaperAdapter类中。
这个getAdapterPosition()办法没有了,这个咱们也需求替换,将
helper.getAdapterPosition()
改成
getItemPosition(item)
即可。
好了,这个依靠库咱们就改完了,开不高兴?来人,奏乐,起舞,老子改了大半天BUG了,还不能享用享用吗?嗯?
四、替换ButterKnife
为什么要替换掉呢?由于在新版Android Studio中你现已不能运用ButterKnife的插件了,ButterKnife的作者也告知咱们不再维护这个库了,推荐咱们运用ViewBinding。
① 敞开ViewBinding
首要要运用ViewBinding,咱们需求先敞开它。在app的build.gradle的android{}闭包中增加如下所示代码:
buildFeatures {
viewBinding true //敞开ViewBinding
}
然后Sync Now,下面咱们以AboutUsActivity为例来修正一下,运用ViewBinding。
② 创立UiVBCallback
还记住之前咱们运用的结构吗?是MVP,现在咱们去掉了ButterKnife,所以响应的底层也需求改动,之前咱们有一个UiCallBack,所以为了差异,我在base包下新建了一个vb包,表明这是运用ViewBinding所需求的一些类和接口,那么咱们在vb包下新建一个UiVBCallback接口,代码如下:
public interface UiVBCallback {
default void onRegister(){}
//初始化savedInstanceState
default void initBeforeView(Bundle savedInstanceState) {}
//初始化
void initData();
}
这儿三个办法,很简略,前面两个不是必需求完成的,最终一个是必需求完成的,由于咱们会涉及到ViewBinding的简略封装,除了榜首个onRegister()办法你不清楚,其他的办法你之前应该都见过了,这个onRegister()的效果实际上是为了让你更好的运用Activity Result API,由于咱们startActivityResult()过时了。详细的你能够上网看一下,这儿就不打开说明晰,用到了再说。
③ 创立BaseVBActivity
为了能让一切的Activity都运用ViewBinding,咱们创立一个类似于BaseActivity的抽象基类,在com.llw.mvplibrary.base.vb包下新建BaseVBActivity类,代码如下:
public abstract class BaseVBActivity<T extends ViewBinding> extends AppCompatActivity implements UiVBCallback {
public T binding;
protected Activity context;
private static final int FAST_CLICK_DELAY_TIME = 500;
private static long lastClickTime;
private Dialog mDialog;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
onRegister();
super.onCreate(savedInstanceState);
initBeforeView(savedInstanceState);
this.context = this;
//增加继承这个BaseVBActivity的Activity
BaseApplication.getActivityManager().addActivity(this);
Type type = this.getClass().getGenericSuperclass();
if (type instanceof ParameterizedType) {
try {
Class<T> clazz = (Class<T>) ((ParameterizedType) type).getActualTypeArguments()[0];
//反射
Method method = clazz.getMethod("inflate", LayoutInflater.class);
binding = (T) method.invoke(null, getLayoutInflater());
} catch (Exception e) {
e.printStackTrace();
}
setContentView(binding.getRoot());
}
initData();
}
/**
* 弹窗呈现
*/
protected void showLoadingDialog() {
if (mDialog == null) {
mDialog = new Dialog(context, R.style.loading_dialog);
}
mDialog.setContentView(R.layout.dialog_loading);
mDialog.setCancelable(false);
mDialog.getWindow().setBackgroundDrawableResource(android.R.color.transparent);
mDialog.show();
}
/**
* 弹窗消失
*/
protected void dismissLoadingDialog() {
if (mDialog != null) {
mDialog.dismiss();
}
mDialog = null;
}
/**
* 回来
*/
protected void Back(Toolbar toolbar) {
toolbar.setNavigationOnClickListener(v -> {
context.finish();
if (!isFastClick()) {
context.finish();
}
});
}
/**
* 两次点击间隔不能少于500ms
*
* @return flag
*/
protected static boolean isFastClick() {
boolean flag = true;
long currentClickTime = System.currentTimeMillis();
if ((currentClickTime - lastClickTime) >= FAST_CLICK_DELAY_TIME) {
flag = false;
}
lastClickTime = currentClickTime;
return flag;
}
}
这儿的中心思想便是反射。
④ 运用BaseVBActivity
下面咱们修正一下AboutUsActivity中的代码,如下所示:
public class AboutUsActivity extends BaseVBActivity<ActivityAboutUsBinding> implements View.OnClickListener {
private String updateUrl = null;
private String updateLog = null;
private boolean is_update = false;
/**
* 博客地址
*/
private final String CSDN_BLOG_URL = "https://blog.csdn.net/qq_38436214/category_9880722.html";
/**
* 源码地址
*/
private final String GITHUB_URL = "https://github.com/lilongweidev/GoodWeather";
@Override
public void initData() {
Back(binding.toolbar);
//蓝色状态栏
StatusBarUtil.setStatusBarColor(context, R.color.about_bg_color);
//设置文字下划线
binding.tvCopyEmail.getPaint().setFlags(Paint.UNDERLINE_TEXT_FLAG);
//抗锯齿
binding.tvCopyEmail.getPaint().setAntiAlias(true);
binding.tvVersion.setText(APKVersionInfoUtils.getVerName(context));
AppVersion appVersion = LitePal.find(AppVersion.class, 1);
updateLog = appVersion.getChangelog();
//提示更新
if (!appVersion.getVersionShort().equals(APKVersionInfoUtils.getVerName(context))) {
is_update = true;
//显现红点
binding.vRed.setVisibility(View.VISIBLE);
updateUrl = appVersion.getInstall_url();
updateLog = appVersion.getChangelog();
} else {
//躲藏红点
binding.vRed.setVisibility(View.GONE);
is_update = false;
}
//增加点击工作
binding.layAppVersion.setOnClickListener(this);
binding.tvBlog.setOnClickListener(this);
binding.tvCode.setOnClickListener(this);
binding.tvCopyEmail.setOnClickListener(this);
binding.tvAuthor.setOnClickListener(this);
}
@SuppressLint("NonConstantResourceId")
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.lay_app_version://版别更新
if (is_update) {
showUpdateAppDialog(updateUrl, updateLog);
} else {
ToastUtils.showShortToast(context, "当时已是最新版别");
}
break;
case R.id.tv_blog://博客地址
jumpUrl(CSDN_BLOG_URL);
break;
case R.id.tv_code://源码地址
jumpUrl(GITHUB_URL);
break;
case R.id.tv_copy_email://仿制邮箱
ClipboardManager myClipboard = (ClipboardManager) context.getSystemService(CLIPBOARD_SERVICE);
ClipData myClip = ClipData.newPlainText("text", "lonelyholiday@qq.com");
myClipboard.setPrimaryClip(myClip);
ToastUtils.showShortToast(context, "邮箱已仿制");
break;
case R.id.tv_author://作者
ToastUtils.showShortToast(context, "你为啥关键我呢?");
break;
default:
ToastUtils.showShortToast(context, "点你咋的!");
break;
}
}
/**
* 跳转URL
*
* @param url 地址
*/
private void jumpUrl(String url) {
if (url != null) {
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url)));
} else {
ToastUtils.showShortToast(context, "未找到相关地址");
}
}
AlertDialog updateAppDialog = null;
/**
* 更新弹窗
*
* @param downloadUrl 下载地址
* @param updateLog 更新内容
*/
private void showUpdateAppDialog(String downloadUrl, String updateLog) {
AlertDialog.Builder builder = new AlertDialog.Builder(context)
.addDefaultAnimation()//默许弹窗动画
.setCancelable(true)
.setText(R.id.tv_update_info, updateLog)
.setContentView(R.layout.dialog_update_app_tip)//载入布局文件
.setWidthAndHeight(SizeUtils.dp2px(context, 270), ViewGroup.LayoutParams.WRAP_CONTENT)//设置弹窗宽高
.setOnClickListener(R.id.tv_cancel, v -> {//取消
updateAppDialog.dismiss();
}).setOnClickListener(R.id.tv_fast_update, v -> {//立即更新
ToastUtils.showShortToast(context, "正在后台下载,下载后会自动装置");
downloadApk(downloadUrl);
updateAppDialog.dismiss();
});
updateAppDialog = builder.create();
updateAppDialog.show();
}
/**
* 清除APK
*/
public static File clearApk(String apkName) {
File apkFile = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), apkName);
if (apkFile.exists()) {
apkFile.delete();
}
return apkFile;
}
/**
* 下载APK
*/
private void downloadApk(String downloadUrl) {
clearApk("GoodWeather.apk");
//下载办理器 获取体系下载服务
DownloadManager downloadManager = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(downloadUrl));
//设置运转运用的网络类型,移动网络或许Wifi都能够
request.setAllowedNetworkTypes(request.NETWORK_MOBILE | request.NETWORK_WIFI);
//设置是否允许漫游
request.setAllowedOverRoaming(true);
//设置文件类型
MimeTypeMap mimeTypeMap = MimeTypeMap.getSingleton();
String mimeString = mimeTypeMap.getMimeTypeFromExtension(MimeTypeMap.getFileExtensionFromUrl(downloadUrl));
request.setMimeType(mimeString);
//设置下载时或许下载完结时,告诉栏是否显现
request.setNotificationVisibility(request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
request.setTitle("下载新版别");
request.setVisibleInDownloadsUi(true);//下载UI
//sdcard目录下的download文件夹
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "GoodWeather.apk");
//将下载请求放入队列
downloadManager.enqueue(request);
}
}
在这儿面我将关于ButterKnife的注解都删去掉了,findViewBinding经过ViewBinding的编译时技术在编译进程中就给咱们生成了findViewById的代码了,这个代码就在ActivityAboutUsBinding类中,这个类是编译时生成了,只需你是layout下的xml,在敞开了ViewBinding之后都会生成对应的类文件,文件命名规矩便是布局名称 驼峰 + Binding,例如布局名称为activity_main.xml,生成的文件便是ActivityMainBinding,掌握这个规则就好了,文件中心就这么多,控件实例化了,但是咱们还是需求自己写控件点击的代码,还是比较简略的吧。这个封装的中心思路便是经过编译时生成类,类继承自ViewBinding,经过泛型能够传入任何继承自ViewBinding的类,传入的类经过反射拿到详细的类,再经过类拿到里边的办法,经过办法拿到实例化之后的binding,最终setContentView,将binding.getRoot()设置进去即可,留意一点反射会比不反射在编译的时分耗时一些,子类能够直接拿到父类的binding,经过binding得到xml中的控件id,你会看到很多的binding.xxx,相信你应该能够了解了,不了解也没有联系,你先用,用的多了就了解了,一同我去掉了getLayoutId()。
⑤ 创立MvpVBActivity
现在基本的Activity能够运用ViewBinding了,下面是用到MVP的Activity,这儿咱们依然保留之前的办法,所以咱们需求创立一个能够运用ViewBinding的MVPActivity,在mvp包下新建MvpVBActivity,代码如下:
public abstract class MvpVBActivity<T extends ViewBinding, P extends BasePresenter> extends BaseVBActivity<T> {
protected P mPresent;
@Override
public void initBeforeView(Bundle savedInstanceState) {
mPresent = createPresent();
mPresent.attach((BaseView) this);
}
protected abstract P createPresent();
@Override
public void onDestroy() {
super.onDestroy();
mPresent.detach((BaseView) this);
}
}
全体上来说,改动不是很大,不过这种办法你能够多加了解一下。
好了,下面咱们来运用一下MvpVBActivity。
⑥ 运用MvpVBActivity
相同咱们需求一个例子来运用这个MvpVBActivity,那么就来改造一下WallPaperActivity吧。
这儿咱们在泛型里边增加了一个ActivityWallPaperBinding,然后修正一下initData办法。
@Override
public void initData() {
//加载弹窗
showLoadingDialog();
//高亮状态栏
StatusBarUtil.StatusBarLightMode(this);
//左上角的回来
Back(binding.toolbar);
initWallPaperList();
binding.fabSetting.setOnClickListener(v -> {
binding.fabSetting.hide();
int type = SPUtils.getInt(Constant.WALLPAPER_TYPE, 4, context);
showSettingDialog(type);
});
}
由于只需一个点击工作,我就直接写在这儿面了,本来的点击注解记住删去掉哦,运用便是这么的简略,你学会了吗?后续的其他Activity自己去修正,不会也没有联系,源码就在哪里,你拿去比照看一下就能够了,记住一个工作,假如你的电脑环境,版别,代码、运转环境和作者相同,SDK装备没有问题,那么你就必定没有问题,那么假如有问题,怎样办,找到问题的发生原因,或许一开端你还不够熟练,但是处理问题比制作问题更能让一个人成长,实在处理不了再去求助,才会有醍醐灌顶的效果,遇到问题先自己想办法处理,这儿说一个标准吧,遇到问题之后,百度上查找,前面七页成果你都看一遍,百分之八十的问题就能处理,耐心很重要,很重要,千万不要浮躁,牢记、牢记。
⑦ 去掉ButterKnife依靠
现在咱们现已不需求ButterKnife了,能够去掉了,有五处当地,榜首个当地,在工程的build.gradle中去掉butterknife的插件。
第二个当地,在app模块的build.gradle中去掉butterknife的依靠库和注解处理器库。
第三个当地,在mvplibrary模块的build.gradle中butterknife的依靠库和注解处理器库。
现在关于gradle中的改动就完结了,Sync Now,然后运转一下,看看App中是否哪里有报错,查看是否还有别的类运用了依靠库中的注解和办法。不出意外的话。
第五处,你的BaseActivity会报错,由于现在现已有了BaseVBActivity了,所以BaseActivity能够删掉,或许你把BaseActivity里边的关于butterknife的信息删掉也能够,留意BaseFragment中的相关信息也要删掉。
第四处,删掉KnifeKit,连同kit包一同删掉。
好了,你能够再次运转有残留包名的就删掉,直到你能够正常运转到手机上即可。
五、保存图片的适配
之前的版别是根据Android10做的,而现在目标版别是Android12,因而保存图片的途径需求改动一下,也很简略。依据版别修正一下途径的值就能够了,翻开ImageActivity,找到saveImageToGallery()
办法,修正代码如下图所示:
然后你就能够在Android10以上的版别下载图片成功了。
六、源码
时隔一年多再次更新,老来俏啊~
源码地址:GoodWeather 欢迎 Star 和 Fork
本文正在参加「金石计划 . 分割6万现金大奖」