首页
归档
留言
友链
广告合作
壁纸
更多
美女主播
Search
1
博瑞GE车机升级/降级
5,649 阅读
2
Mac打印机设置黑白打印
5,043 阅读
3
修改elementUI中el-table树形结构图标
4,946 阅读
4
Mac客户端添加腾讯企业邮箱方法
4,705 阅读
5
intelliJ Idea 2022.2.X破解
4,459 阅读
后端开发
HarmonyOS Next
Web前端
微信开发
开发辅助
App开发
数据库
随笔日记
登录
/
注册
Search
标签搜索
Spring Boot
Java
Vue
Mac
Spring Cloud
MyBatis
WordPress
MacOS
asp.net
Element UI
Nacos
MySQL
.Net
Spring Cloud Alibaba
Mybatis-Plus
Typecho
jQuery
Java Script
IntelliJ IDEA
微信小程序
Laughing
累计撰写
629
篇文章
累计收到
1,421
条评论
首页
栏目
后端开发
HarmonyOS Next
Web前端
微信开发
开发辅助
App开发
数据库
随笔日记
页面
归档
留言
友链
广告合作
壁纸
美女主播
搜索到
629
篇与
的结果
2020-12-14
XUpdate:一个轻量级、高可用性的Android版本更新框架
一个轻量级、高可用性的Android版本更新框架。赶紧点击使用说明文档,体验一下吧!在提issue前,请先阅读【提问的智慧】,并严格按照issue模板进行填写,节约大家的时间。在使用前,请一定要仔细阅读使用说明文档,重要的事情说三遍!!!在使用前,请一定要仔细阅读使用说明文档,重要的事情说三遍!!!在使用前,请一定要仔细阅读使用说明文档,重要的事情说三遍!!!X系列库快速集成为了方便大家快速集成X系列框架库,我提供了一个空壳模版供大家参考使用: https://github.com/xuexiangjys/TemplateAppProject特征支持post和get两种版本检查方式,支持自定义网络请求。支持设置只在wifi下进行版本更新。支持静默下载(后台更新)、自动版本更新。提供界面友好的版本更新提示弹窗,可自定义其主题样式。支持自定义版本更新检查器、版本更新解析器、版本更新提示器、版本更新下载器、版本更新安装、出错处理。支持MD5文件校验、版本忽略、版本强制更新等功能。支持自定义文件校验方法【默认是MD5校验】。支持自定义请求API接口。兼容Android6.0、7.0、8.0、9.0和10.0。支持中文和英文两种语言显示(国际化)。支持Flutter插件使用:flutter_xupdate。支持React-Native插件使用:react-native-xupdate。组成结构本框架借鉴了AppUpdate中的部分思想和UI界面,将版本更新中的各部分环节抽离出来,形成了如下几个部分:版本更新检查器IUpdateChecker:检查是否有最新版本。版本更新解析器IUpdateParser:解析服务端返回的数据结果。版本更新提示器IUpdatePrompter:展示最新的版本信息。版本更新下载器IUpdateDownloader:下载最新的版本APK安装包。网络请求服务接口IUpdateHttpService:定义了进行网络请求的相关接口。除此之外,还有两个监听器:版本更新失败的监听器OnUpdateFailureListener。版本更新apk安装的监听器OnInstallListener。更新调度核心:版本更新业务代理IUpdateProxy:负责版本更新的流程控制,调用update开始进行版本更新流程。Demo更新后台服务由于github最近访问比较慢,如果需要更好地体验XUpdate,你可以点击自己搭建一个简易的版本更新服务。Demo下载蒲公英下载蒲公英下载的密码: xuexiangjysGithub下载2、快速集成指南目前支持主流开发工具AndroidStudio的使用,直接配置build.gradle,增加依赖即可.2.1、Android Studio导入方法,添加Gradle依赖1.先在项目根目录的 build.gradle 的 repositories 添加:allprojects { repositories { ... maven { url "https://jitpack.io" } } }2.然后在dependencies添加:以下是版本说明,选择一个即可。androidx版本:2.0.0及以上dependencies { ... // androidx版本 implementation 'com.github.xuexiangjys:XUpdate:2.0.4' }support版本:1.1.6及以下dependencies { ... // support版本 implementation 'com.github.xuexiangjys:XUpdate:1.1.6' }2.2、初始化XUpdate在Application进行初始化配置:XUpdate.get() .debug(true) .isWifiOnly(true) //默认设置只在wifi下检查版本更新 .isGet(true) //默认设置使用get请求检查版本 .isAutoMode(false) //默认设置非自动模式,可根据具体使用配置 .param("versionCode", UpdateUtils.getVersionCode(this)) //设置默认公共请求参数 .param("appKey", getPackageName()) .setOnUpdateFailureListener(new OnUpdateFailureListener() { //设置版本更新出错的监听 @Override public void onFailure(UpdateError error) { if (error.getCode() != CHECK_NO_NEW_VERSION) { //对不同错误进行处理 ToastUtils.toast(error.toString()); } } }) .supportSilentInstall(true) //设置是否支持静默安装,默认是true .setIUpdateHttpService(new OKHttpUpdateHttpService()) //这个必须设置!实现网络请求功能。 .init(this); //这个必须初始化【注意】:如果出现任何问题,可开启debug模式来追踪问题。如果你还需要将日志记录在磁盘上,可实现以下接口XUpdate.get().setILogger(new ILogger() { @Override public void log(int priority, String tag, String message, Throwable t) { //实现日志记录功能 } });2.3、版本更新实体信息(1) UpdateEntity字段属性字段名类型默认值备注mHasUpdatebooleanfalse是否有新版本mIsForcebooleanfalse是否强制安装:不安装无法使用appmIsIgnorablebooleanfalse是否可忽略该版本mVersionCodeint0最新版本codemVersionNameStringunknown_version最新版本名称mUpdateContentString""更新内容mDownloadEntityDownloadEntity/下载信息实体mIsSilentbooleanfalse是否静默下载:有新版本时不提示直接下载mIsAutoInstallbooleantrue是否下载完成后自动安装(2) DownloadEntity字段属性字段名类型默认值备注mDownloadUrlString""下载地址mCacheDirString""文件下载的目录mMd5String""下载文件的加密校验值(默认使用md5加密),用于校验,防止下载的apk文件被替换(最新演示demo中有计算校验值的工具)mSizelong0下载文件的大小【单位:KB】mIsShowNotificationbooleanfalse是否在通知栏上显示下载进度(3) PromptEntity字段属性字段名类型默认值备注mThemeColorintR.color.xupdate_default_theme_color主题色(进度条和按钮的背景色)mTopResIdintR.drawable.xupdate_bg_app_top顶部背景图片资源idmButtonTextColorint0按钮文字颜色mSupportBackgroundUpdatebooleanfalse是否支持后台更新mWidthRatiofloat-1(无约束)版本更新提示器宽度占屏幕的比例mHeightRatiofloat-1(无约束)版本更新提示器高度占屏幕的比例2.4、文件加密校验方式本框架默认使用的文件加密校验方法是MD5加密方式,当然如果你不想使用MD5加密,你也可以自定义文件加密器IFileEncryptor,以下是MD5文件加密器的实现供参考:/** * 默认的文件加密计算使用的是MD5加密 * * @author xuexiang * @since 2019-09-06 14:21 */ public class DefaultFileEncryptor implements IFileEncryptor { /** * 加密文件 * * @param file * @return */ @Override public String encryptFile(File file) { return Md5Utils.getFileMD5(file); } /** * 检验文件是否有效(加密是否一致) * * @param encrypt 加密值, 如果encrypt为空,直接认为是有效的 * @param file 需要校验的文件 * @return 文件是否有效 */ @Override public boolean isFileValid(String encrypt, File file) { return TextUtils.isEmpty(encrypt) || encrypt.equalsIgnoreCase(encryptFile(file)); } } 最后再调用XUpdate.get().setIFileEncryptor方法设置即可生效。3、版本更新3.1、默认版本更新直接调用如下代码即可完成版本更新操作:XUpdate.newBuild(getActivity()) .updateUrl(mUpdateUrl) .update();需要注意的是,使用默认版本更新,请求服务器返回的json格式应包括如下内容:{ "Code": 0, //0代表请求成功,非0代表失败 "Msg": "", //请求出错的信息 "UpdateStatus": 1, //0代表不更新,1代表有版本更新,不需要强制升级,2代表有版本更新,需要强制升级 "VersionCode": 3, "VersionName": "1.0.2", "ModifyContent": "1、优化api接口。\r\n2、添加使用demo演示。\r\n3、新增自定义更新服务API接口。\r\n4、优化更新提示界面。", "DownloadUrl": "https://raw.githubusercontent.com/xuexiangjys/XUpdate/master/apk/xupdate_demo_1.0.2.apk", "ApkSize": 2048 "ApkMd5": "..." //md5值没有的话,就无法保证apk是否完整,每次都会重新下载。框架默认使用的是md5加密。 }3.2、自动版本更新自动版本更新:自动检查版本 + 自动下载apk + 自动安装apk(静默安装)。只需要设置isAutoMode(true),不过如果设备没有root权限的话,是无法做到完全的自动更新(因为静默安装需要root权限)。XUpdate.newBuild(getActivity()) .updateUrl(mUpdateUrl) .isAutoMode(true) //如果需要完全无人干预,自动更新,需要root权限【静默安装需要】 .update();3.3、支持后台更新开启支持后台更新后, 用户点击“后台更新”按钮后,就可以进入到后台更新,不用一直在更新界面等待.XUpdate.newBuild(getActivity()) .updateUrl(mUpdateUrl) .supportBackgroundUpdate(true) .update();3.4、强制版本更新就是用户不更新的话,程序将无法正常使用。只需要服务端返回UpdateStatus字段为2即可。当然如果你自定义请求返回api的话,只需要设置UpdateEntity的mIsForce字段为true即可。3.5、自定义版本更新提示弹窗的主题通过设置更新顶部图片、主题色、按钮文字颜色、宽高比率等来实现自定义主题样式.promptThemeColor: 设置主题颜色promptButtonTextColor: 设置按钮的文字颜色promptTopResId: 设置顶部背景图片promptWidthRatio: 设置版本更新提示器宽度占屏幕的比例,默认是-1,不做约束promptHeightRatio: 设置版本更新提示器高度占屏幕的比例,默认是-1,不做约束XUpdate.newBuild(getActivity()) .updateUrl(mUpdateUrl) .promptThemeColor(ResUtils.getColor(R.color.update_theme_color)) .promptButtonTextColor(Color.WHITE) .promptTopResId(R.mipmap.bg_update_top) .promptWidthRatio(0.7F) .update();3.6、自定义版本更新解析器实现IUpdateParser接口即可实现解析器的自定义。XUpdate.newBuild(getActivity()) .updateUrl(mUpdateUrl3) .updateParser(new CustomUpdateParser()) //设置自定义的版本更新解析器 .update(); public class CustomUpdateParser implements IUpdateParser { @Override public UpdateEntity parseJson(String json) throws Exception { CustomResult result = JsonUtil.fromJson(json, CustomResult.class); if (result != null) { return new UpdateEntity() .setHasUpdate(result.hasUpdate) .setIsIgnorable(result.isIgnorable) .setVersionCode(result.versionCode) .setVersionName(result.versionName) .setUpdateContent(result.updateLog) .setDownloadUrl(result.apkUrl) .setSize(result.apkSize); } return null; } } 3.7、自定义版本更新检查器+版本更新解析器+版本更新提示器实现IUpdateChecker接口即可实现检查器的自定义。实现IUpdateParser接口即可实现解析器的自定义。实现IUpdatePrompter接口即可实现提示器的自定义。XUpdate.newBuild(getActivity()) .updateUrl(mUpdateUrl3) .updateChecker(new DefaultUpdateChecker() { @Override public void onBeforeCheck() { super.onBeforeCheck(); CProgressDialogUtils.showProgressDialog(getActivity(), "查询中..."); } @Override public void onAfterCheck() { super.onAfterCheck(); CProgressDialogUtils.cancelProgressDialog(getActivity()); } }) .updateParser(new CustomUpdateParser()) .updatePrompter(new CustomUpdatePrompter(getActivity())) .update(); public class CustomUpdatePrompter implements IUpdatePrompter { private Context mContext; public CustomUpdatePrompter(Context context) { mContext = context; } @Override public void showPrompt(@NonNull UpdateEntity updateEntity, @NonNull IUpdateProxy updateProxy, @NonNull PromptEntity promptEntity) { showUpdatePrompt(updateEntity, updateProxy); } /** * 显示自定义提示 * * @param updateEntity * @param updateProxy */ private void showUpdatePrompt(final @NonNull UpdateEntity updateEntity, final @NonNull IUpdateProxy updateProxy) { String updateInfo = UpdateUtils.getDisplayUpdateInfo(mContext, updateEntity); new AlertDialog.Builder(mContext) .setTitle(String.format("是否升级到%s版本?", updateEntity.getVersionName())) .setMessage(updateInfo) .setPositiveButton("升级", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { updateProxy.startDownload(updateEntity, new OnFileDownloadListener() { @Override public void onStart() { HProgressDialogUtils.showHorizontalProgressDialog(mContext, "下载进度", false); } @Override public void onProgress(float progress, long total) { HProgressDialogUtils.setProgress(Math.round(progress * 100)); } @Override public boolean onCompleted(File file) { HProgressDialogUtils.cancel(); return true; } @Override public void onError(Throwable throwable) { HProgressDialogUtils.cancel(); } }); } }) .setNegativeButton("暂不升级", null) .setCancelable(false) .create() .show(); }3.8、只使用XUpdate的下载器功能进行apk的下载XUpdate.newBuild(getActivity()) .apkCacheDir(PathUtils.getExtDownloadsPath()) //设置下载缓存的根目录 .build() .download(mDownloadUrl, new OnFileDownloadListener() { //设置下载的地址和下载的监听 @Override public void onStart() { HProgressDialogUtils.showHorizontalProgressDialog(getContext(), "下载进度", false); } @Override public void onProgress(float progress, long total) { HProgressDialogUtils.setProgress(Math.round(progress * 100)); } @Override public boolean onCompleted(File file) { HProgressDialogUtils.cancel(); ToastUtils.toast("apk下载完毕,文件路径:" + file.getPath()); return false; } @Override public void onError(Throwable throwable) { HProgressDialogUtils.cancel(); } });3.9、只使用XUpdate的APK安装的功能_XUpdate.startInstallApk(getContext(), FileUtils.getFileByPath(PathUtils.getFilePathByUri(getContext(), data.getData()))); //填写文件所在的路径如果你的apk安装与众不同,你可以实现自己的apk安装器。你只需要实现OnInstallListener接口,并通过XUpdate.setOnInstallListener进行设置即可生效。混淆配置-keep class com.xuexiang.xupdate.entity.** { *; } //注意,如果你使用的是自定义Api解析器解析,还需要给你自定义Api实体配上混淆,如下是本demo中配置的自定义Api实体混淆规则: -keep class com.xuexiang.xupdatedemo.entity.** { *; } 相关链接XUpdate 文档XUpdate 管理服务XUpdate 后台管理系统XUpdate Flutter插件XUpdate React-Native插件Flutter版本更新弹窗组件特别感谢https://github.com/WVector/AppUpdate
2020年12月14日
1,766 阅读
0 评论
1 点赞
2020-12-13
解决无法访问raw.githubusercontent.com问题(dns污染)
此文章截至2020.12.13日,验证仍然有效,具体啥时候失效,不得而知,大家如果发现不能用了,也可以留言反馈,我们及时更新文章。{mtitle title="需要替换的内容"/}#*********************github 2021-04-23 update******************** 151.101.129.194 github.global.ssl.fastly.net 185.199.111.153 assets-cdn.github.com 185.199.108.153 documentcloud.github.com 192.30.255.112 gist.github.com 185.199.110.133 gist.githubusercontent.com 185.199.110.154 github.githubassets.com 185.199.110.154 help.github.com 192.30.255.121 nodeload.github.com 185.199.111.133 raw.github.com 140.82.112.18 status.github.com 185.199.109.153 training.github.com 185.199.111.133 avatars.githubusercontent.com 185.199.108.133 avatars0.githubusercontent.com 185.199.111.133 avatars1.githubusercontent.com 185.199.111.133 avatars2.githubusercontent.com 185.199.111.133 avatars3.githubusercontent.com 185.199.109.133 avatars4.githubusercontent.com 185.199.111.133 avatars5.githubusercontent.com 185.199.109.133 avatars6.githubusercontent.com 185.199.108.133 avatars7.githubusercontent.com 185.199.110.133 avatars8.githubusercontent.com 185.199.111.133 favicons.githubusercontent.com 192.30.255.121 codeload.github.com 52.216.136.148 github-cloud.s3.amazonaws.com 52.217.99.44 github-com.s3.amazonaws.com 52.216.168.235 github-production-release-asset-2e65be.s3.amazonaws.com 52.217.104.172 github-production-user-asset-6210df.s3.amazonaws.com 52.216.25.108 github-production-repository-file-5c1aeb.s3.amazonaws.com 185.199.108.153 githubstatus.com 64.71.168.201 github.community 185.199.108.133 media.githubusercontent.com 185.199.110.133 camo.githubusercontent.com 185.199.111.133 raw.githubusercontent.com 185.199.111.133 cloud.githubusercontent.com 185.199.111.133 user-images.githubusercontent.com 185.199.110.153 customer-stories-feed.github.com 185.199.110.153 pages.github.com 192.30.255.117 api.github.com 140.82.114.25 live.github.com 140.82.113.30 githubapp.com 192.30.255.113 github.comWindows篇hosts文件位置:C:/windows/system32/drivers/etc/hosts将前文内容追加到hosts,然后刷新DNS缓存:ipconfig /flushdnsMac、Linux篇执行sudo vi /etc/hosts打开hosts文件,复制内容并保存。最后刷新下缓存:sudo killall -HUP mDNSResponder验证最后验证一下,能愉快的打开了。
2020年12月13日
2,720 阅读
5 评论
5 点赞
2020-12-13
Lint found errors in the project; aborting build导致打包停止错误解决
今天在打包时的时候出现了这个错导致打包不成功,具体原因可以从报错日志中看到是因为studio检测到了lint错误,从而停止了打包。解决办法是在app下的build.gradle 文件的android节点下添加lintOptions{ abortOnError false }即可,即在检测到lint错误时还接续进行打包。7:00:55 :app:lint FAILED 17:00:55 17:00:55 FAILURE: Build failed with an exception. 17:00:55 17:00:55 * What went wrong: 17:00:55 Execution failed for task ':app:lint'. 17:00:55 > Lint found errors in the project; aborting build. 17:00:55 17:00:55 Fix the issues identified by lint, or add the following to your build script to proceed with errors: 17:00:55 ... 17:00:55 android { 17:00:55 lintOptions { 17:00:55 abortOnError false 17:00:55 } 17:00:55 } 17:00:55 ... 17:00:55 17:00:55 The first 3 errors (out of 6) were: 17:00:55 /root/.gradle/caches/modules-2/files-2.1/com.alibaba/fastjson/1.2.35/d0b54f814af4652f0893d560d6a785917abdeae1/fastjson-1.2.35.jar: Error: Invalid package reference in library; not included in Android: java.awt. Referenced from com.alibaba.fastjson.serializer.AwtCodec. [InvalidPackage] 17:00:55 /root/.gradle/caches/modules-2/files-2.1/com.alibaba/fastjson/1.2.35/d0b54f814af4652f0893d560d6a785917abdeae1/fastjson-1.2.35.jar: Error: Invalid package reference in library; not included in Android: javax.servlet.http. Referenced from com.alibaba.fastjson.support.spring.FastJsonJsonView. [InvalidPackage] 17:00:55 /root/.gradle/caches/modules-2/files-2.1/com.alibaba/fastjson/1.2.35/d0b54f814af4652f0893d560d6a785917abdeae1/fastjson-1.2.35.jar: Error: Invalid package reference in library; not included in Android: javax.servlet. Referenced from com.alibaba.fastjson.support.spring.FastJsonJsonView. [InvalidPackage]
2020年12月13日
2,633 阅读
0 评论
3 点赞
2020-12-12
getResources().getDrawable()过时问题解决
Android开发时,我们经常会动态指定按钮的背景图。如果我们使用shareItem.setBackground(getResources().getDrawable(R.color.teal_200));设置时,会收到Ide的提示,我们有三种方式解决此问题:1)使用drawable资源但不为其设置theme主题ResourcesCompat.getDrawable(getResources(), R.drawable.name, null); //null就是null,不设主题如:myexample.setIcon(ResourcesCompat.getDrawable(getResources(), R.mipmap.ic_launcher, null));2)使用默认的activity主题ContextCompat.getDrawable(getActivity(), R.drawable.name); //getActivity(),如果是在activity里就直接用this如:myexample.setIcon(ContextCompat.getDrawable(this,R.drawable.ic_favorite_black_18dp)); 3)使用自定义主题ResourcesCompat.getDrawable(getResources(), R.drawable.name, anotherTheme);
2020年12月12日
2,038 阅读
0 评论
1 点赞
2020-12-10
非常简单的Android Studio中第三方源码导入
Android开发时,我们经常需要导入第三方的源码。之前看看其他人分享的,感觉都看的稀里糊涂的,作为一个Android开发新人一脸懵逼。这里给大家介绍一种非常简单的导入方法。这里以一个动态权限的源码导入为例子进行说明。github地址:https://github.com/forJrking/HeiPermission下载源码这个不多介绍,去上面地址下载就行了。解压代码解压代码,我们会得到permlib文件夹,如下拷贝代码将permlib整个文件夹拷贝到我们的工程中修改settings.gradle找到我们工程的settings.gradle文件,修改如下添加依赖找到我们模块的build.gradle。修改项目结构打开项目结构,修改模块的jdk版本最后引入完成后Android studio会自动构建成功,如果有报错,修改错误即可。
2020年12月10日
1,364 阅读
0 评论
1 点赞
2020-12-06
SwipeMenuListView(仿IOS滑动菜单)
使用添加引用dependencies { compile 'com.baoyz.swipemenulistview:library:1.3.0' }1. 在layout xml中替换ListView<com.baoyz.swipemenulistview.SwipeMenuListView android:id="@+id/listView" android:layout_width="match_parent" android:layout_height="match_parent" />2. SwipeMenuCreator创建SwipeMenuCreator creator = new SwipeMenuCreator() { @Override public void create(SwipeMenu menu) { // create "open" item SwipeMenuItem openItem = new SwipeMenuItem( getApplicationContext()); // set item background openItem.setBackground(new ColorDrawable(Color.rgb(0xC9, 0xC9, 0xCE))); // set item width openItem.setWidth(dp2px(90)); // set item title openItem.setTitle("Open"); // set item title fontsize openItem.setTitleSize(18); // set item title font color openItem.setTitleColor(Color.WHITE); // add to menu menu.addMenuItem(openItem); // create "delete" item SwipeMenuItem deleteItem = new SwipeMenuItem( getApplicationContext()); // set item background deleteItem.setBackground(new ColorDrawable(Color.rgb(0xF9, 0x3F, 0x25))); // set item width deleteItem.setWidth(dp2px(90)); // set a icon deleteItem.setIcon(R.drawable.ic_delete); // add to menu menu.addMenuItem(deleteItem); } }; // set creator listView.setMenuCreator(creator);3. 添加点击事件listView.setOnMenuItemClickListener(new OnMenuItemClickListener() { @Override public boolean onMenuItemClick(int position, SwipeMenu menu, int index) { switch (index) { case 0: // open break; case 1: // delete break; } // false : close the menu; true : not close the menu return false; } });源码https://github.com/baoyongzhang/SwipeMenuListView
2020年12月06日
1,394 阅读
0 评论
1 点赞
2020-12-06
android 自定义网络变化时全局提醒(转)
实现思路定时获取当前网络状态利用广播发送当前网络状态,并且触发网络状态改变的监听在baseActivity中实现网络状态改变的监听,并作出相应的响应(例如显示没有网络的布局)代码实现定义网络状态变化监听接口public interface CheckNetworkStatusChangeListener { /* 网络变化会调用 */ void onEvent(Status status); /** * 网络状态 * TYPE_UN_NETWORK 沒有网络 * TYPE_WIFI WiFi连接 * TYPE_MOBILE 移动数据 */ enum Status { TYPE_UN_NETWORK, TYPE_WIFI, TYPE_MOBILE, } }定义接收网络变化的广播public class CheckNetworkStatusChangeReceiver extends BroadcastReceiver { public static final String EVENT = "event"; public static final String ACTION="action"; private CheckNetworkStatusChangeListener mCheckNetworkStatusChangeListener; public CheckNetworkStatusChangeReceiver() { } public void setCheckNetworkStatusChangeListener(CheckNetworkStatusChangeListener mCheckNetworkStatusChangeListener) { this.mCheckNetworkStatusChangeListener = mCheckNetworkStatusChangeListener; } @Override public void onReceive(Context context, Intent intent) { CheckNetworkStatusChangeListener.Status mStatus = (CheckNetworkStatusChangeListener.Status) intent.getSerializableExtra(EVENT); mCheckNetworkStatusChangeListener.onEvent(mStatus); } }检测当前网络状态工具类public class NetworkUtil { /** * 获取当前网络类型 CheckNetworkStatusChangeListener.Status * * @return 返回网络类型 CheckNetworkStatusChangeListener.Status */ public static CheckNetworkStatusChangeListener.Status getNetworkConnectionType(Context context) { //获取连接管理器 ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); if (connectivityManager == null) return CheckNetworkStatusChangeListener.Status.TYPE_UN_NETWORK; //获取网络连接信息 NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo(); if (networkInfo != null && networkInfo.isAvailable()) { if (networkInfo.getType() == ConnectivityManager.TYPE_WIFI) { return CheckNetworkStatusChangeListener.Status.TYPE_WIFI; } if (networkInfo.getType() == ConnectivityManager.TYPE_MOBILE) { return CheckNetworkStatusChangeListener.Status.TYPE_MOBILE; } } return CheckNetworkStatusChangeListener.Status.TYPE_UN_NETWORK; } }自定义Handler,发送广播public class SimpleHandler<T extends Activity> extends Handler { WeakReference<T> weakReference; public SimpleHandler(T t) { this.weakReference = new WeakReference<>(t); } @Override public void handleMessage(Message msg) { super.handleMessage(msg); if (weakReference.get() != null) { //发送广播 Intent mCheckNetworkIntent = new Intent(); mCheckNetworkIntent.setAction(CheckNetworkStatusChangeReceiver.ACTION); CheckNetworkStatusChangeListener.Status status= (CheckNetworkStatusChangeListener.Status) msg.obj; mCheckNetworkIntent.putExtra(CheckNetworkStatusChangeReceiver.EVENT,status); weakReference.get().sendBroadcast(mCheckNetworkIntent); } } }实现每秒检测1次网络状态,因为是耗时操作所有在子线程中去获取当前网络状态@Override protected void onResume() { super.onResume(); new Thread(mRunnable).start(); } Runnable mRunnable = new Runnable() { @Override public void run() { //实现每隔一秒检测一次网络 while (true){ try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } CheckNetworkStatusChangeListener.Status status = NetworkUtil.getNetworkConnectionType(BaseActivity.this); Message message = new Message(); message.obj = status; simpleHandler.sendMessage(message); } } };检测网络状态后发送Message到handle,handle去发送广播,这注意handle内存泄漏public class SimpleHandler<T extends Activity> extends Handler { WeakReference<T> weakReference; public SimpleHandler(T t) { this.weakReference = new WeakReference<>(t); } @Override public void handleMessage(Message msg) { super.handleMessage(msg); if (weakReference.get() != null) { //发送广播 Intent mCheckNetworkIntent = new Intent(); mCheckNetworkIntent.setAction(CheckNetworkStatusChangeReceiver.ACTION); CheckNetworkStatusChangeListener.Status status= (CheckNetworkStatusChangeListener.Status) msg.obj; mCheckNetworkIntent.putExtra(CheckNetworkStatusChangeReceiver.EVENT,status); weakReference.get().sendBroadcast(mCheckNetworkIntent); } } } BaseActivity完整代码public class BaseActivity extends AppCompatActivity implements CheckNetworkStatusChangeListener { private CheckNetworkStatusChangeReceiver mCheckNetworkStatusChangeReceiver; private String LOG = BaseActivity.class.getSimpleName(); private SimpleHandler<BaseActivity> simpleHandler; private NetworkStatusLayout mNetworkStatusLayout; private boolean checkNetworkStatusChangeListenerEnable=true; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); super.setContentView(R.layout.activity_base); init(); new Thread(mRunnable).start(); } @Override public void setContentView(int layoutResID) { LinearLayout mRootLayout = findViewById(R.id.root_linear_layout); //将网络状态view添加到根视图 mNetworkStatusLayout = new NetworkStatusLayout(this); //默认隐藏状态 mNetworkStatusLayout.setVisibility(View.GONE); mRootLayout.addView(mNetworkStatusLayout, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); //将子类的layout,添加到根目录 View mContentView = LayoutInflater.from(this).inflate(layoutResID, null); mRootLayout.addView(mContentView, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); } private void init() { mCheckNetworkStatusChangeReceiver = new CheckNetworkStatusChangeReceiver(); mCheckNetworkStatusChangeReceiver.setCheckNetworkStatusChangeListener(this); IntentFilter mIntentFilter = new IntentFilter(); mIntentFilter.addAction(CheckNetworkStatusChangeReceiver.ACTION); registerReceiver(mCheckNetworkStatusChangeReceiver, mIntentFilter); simpleHandler = new SimpleHandler<BaseActivity>(this); } public void setCheckNetworkStatusChangeListenerEnable(boolean checkNetworkStatusChangeListener) { this.checkNetworkStatusChangeListenerEnable = checkNetworkStatusChangeListener; } @Override protected void onResume() { super.onResume(); } Runnable mRunnable = new Runnable() { @Override public void run() { //实现每隔一秒检测一次网络 while (true) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } CheckNetworkStatusChangeListener.Status status = NetworkUtil.getNetworkConnectionType(BaseActivity.this); Message message = new Message(); message.obj = status; simpleHandler.sendMessage(message); } } }; @Override public void onEvent(Status status) { Log.w(LOG, "status: " + status.name()); if (!checkNetworkStatusChangeListenerEnable) return; if (status == Status.TYPE_UN_NETWORK) { if (mNetworkStatusLayout.getVisibility() == View.GONE) mNetworkStatusLayout.setVisibility(View.VISIBLE); } else { if (mNetworkStatusLayout.getVisibility() == View.VISIBLE) mNetworkStatusLayout.setVisibility(View.GONE); } } @Override protected void onDestroy() { super.onDestroy(); unregisterReceiver(mCheckNetworkStatusChangeReceiver); simpleHandler.removeCallbacks(mRunnable); } } 那么下一步就是在onEvent()判断网络状态,没有网络时的页面提示<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:background="@color/gray" android:layout_height="50dp"> <TextView android:id="@+id/tv_network_status" android:layout_centerInParent="true" android:text="@string/not_network" android:textColor="@color/red" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </RelativeLayout>使用activity继承自BaseActivitypublic class MainActivity extends BaseActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); setTitle("我是首页"); } }源码下载链接: https://pan.baidu.com/s/1G0A1Irlk0Iw_DjtKPhrWUA 密码: jmfh
2020年12月06日
1,456 阅读
0 评论
23 点赞
2020-12-06
android Button动态修改背景图
我们在布局文件中,设置Button的背景图片时,一般是通过如下方式<ImageButton android:id="@+id/buttonListTopMenuSave" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/detail_save" android:layout_centerVertical="true" android:layout_alignParentRight="true" />如果我们需要动态设置图片,可以通过如下方式buttonListTopMenuSave = findViewById(R.id.buttonListTopMenuSave); buttonListTopMenuSave.setBackgroundResource(R.drawable.detail_ok); buttonListTopMenuSave.setOnClickListener(this);
2020年12月06日
2,248 阅读
0 评论
1 点赞
2020-12-05
android Button修改背景色
问题描述在修改Button的背景颜色时,始终无法修改颜色为设置的颜色,且颜色始终为默认的蓝紫色。比如如下定义一个椭圆形的按钮。样式btn_bg_red.xml<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android"> <solid android:color="@color/teal_200"/> <corners android:topLeftRadius="10dip" android:topRightRadius="10dip" android:bottomRightRadius="10dip" android:bottomLeftRadius="10dip" /> <!--圆角矩形白色背景--> </shape>MainActivity.xml<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="5dip" android:layout_weight="1" android:background="@drawable/btn_bg_red" android:textColor="@color/purple_200" android:gravity="center" android:text="圆角Button" /> </androidx.constraintlayout.widget.ConstraintLayout>可以看到,虽然修改了背景色,但是根本没起作用。解决默认的颜色设置来自于res/values/themes.xml与夜间模式(应该是)下的res/values-night/themes.xml修改为(或其它能够实现非默认颜色的主题)
2020年12月05日
1,656 阅读
0 评论
0 点赞
2020-12-03
Android LinearLayout权重布局
Android开发时,我们经常使用ListView展示一些附属信息,比如文章标题下,可能显示作者、发布日期等信息。像人名可能比较短,而对于年月日时分秒的这种日期格式,显示就比较长,所以我们可以通过控制LinearLayout里面的权重,分配不同控件的宽度。<!-- 单据附属信息--> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center_vertical"> <!--收集人--> <LinearLayout android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="3" android:gravity="center_vertical"> <ImageView android:layout_width="16sp" android:layout_height="16sp" android:background="@drawable/list_item_user" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/textViewCollectedByName" android:text="@string/str_const_collected_by" android:textSize="@dimen/font_16" android:ellipsize="end"/> </LinearLayout> <!-- 收集时间--> <LinearLayout android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="8" android:gravity="center_vertical"> <ImageView android:layout_width="16sp" android:layout_height="16sp" android:background="@drawable/list_item_time" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/str_const_collect_time" android:id="@+id/textViewCollectedTime" android:textSize="@dimen/font_16" android:ellipsize="end"/> </LinearLayout> <!--科室--> <LinearLayout android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="4" android:gravity="center_vertical"> <ImageView android:layout_width="16sp" android:layout_height="16sp" android:background="@drawable/list_item_department" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/str_const_depart" android:id="@+id/textViewDepartmentName" android:textSize="@dimen/font_16" android:ellipsize="end" android:maxLines="1"/> </LinearLayout> </LinearLayout>实现权重,主要注意两个参数android:layout_width="0dp"和 android:layout_weight="3"控件1宽度 = 控件1权重/(控件1权重+控件2权重+...控件n权重)每个控件的占比,等于控件的权重/所有控件权重的和。
2020年12月03日
1,454 阅读
0 评论
24 点赞
2020-12-03
2020.2 IntelliJ IDEA激活-已解决11月26号过期问题
在最新idea202.02激活教程有效期到2089中,我们介绍了jetbrains家族的2020.2版本的激活方法。但是本月26号(2020年11月26日),激活突然失效了。这篇文章我们介绍的是最新的激活方式,可以解决27号过期的问题。激活方法不变,只需要下载新的破解文件并替换安装参数即可。获取破解文件https://pan.baidu.com/s/1j1H9HVxUyxRlphDNWHWbZA 提取码:vnvp使用方法先下载压缩包解压后得到jetbrains-agent-latest.zip,把它放到你认为合适的文件夹内。启动你的IDE,如果上来就需要注册,选择:试用(Evaluate for free)进入IDE拖动jetbrains-agent-latest.zip到编辑器里面选择resart输入安装参数激活成功安装参数f9fF1I/ygZI7Ff14sigGMZmZ7KJkhsM364o6exiukAqGORVXN1e4Fk4B8+hGSl5B+iLp9nIA2pSNhNGlxnDgSV3xC85CGVvWY9SWa+ECeWhJZ1+hitDPCNw5lKaRBnxIKhAfQ3aJl4S5WmrOkfKoIuz3UXVoX7hZGxofqQtzfuc
2020年12月03日
2,061 阅读
3 评论
2 点赞
2020-11-22
ElementUI中的el-table中实现动态添加一行、删除一行、清空所有行
实现首先页面添加一个el-table,然后绑定其数据源为bcglXiangXiList,并且通过<el-table-column type="selection" width="30" align="center" />添加了勾选框。然后通过@selection-change="handleDetailSelectionChange设置其勾选框改变事件。这里的数据源bcglXiangXiList要提前声明 data() { return { //详细list bcglXiangXiList: [],这里的每一列是不同的控件,但是最终都要有v-mode进行动态数据绑定。 <el-table v-loading="loading" :data="bcglXiangXiList" :row-class-name="rowClassName" @selection-change="handleDetailSelectionChange" ref="tb" > <el-table-column type="selection" width="30" align="center" /> <el-table-column label="序号" align="center" prop="xh" width="50"></el-table-column> <el-table-column label="开始时间/最早时间-结束时间/最晚时间" width="250" prop="sjfw"> <template slot-scope="scope"> <el-time-picker is-range format="HH:mm" value-format="HH:mm" :style="{width: '100%'}" start-placeholder="开始时间" end-placeholder="结束时间" range-separator="至" clearable @change="changesjfw(scope.row)" v-model="bcglXiangXiList[scope.row.xh-1].sjfw" ></el-time-picker> </template> </el-table-column> <el-table-column label="指定天数" align="center" prop="ts" width="150"> <template slot-scope="scope"> <el-select clearable @change="changezdts(scope.row)" v-model="bcglXiangXiList[scope.row.xh-1].ts" > <el-option v-for="dict in zdtsOptions" :key="dict.dictValue" :label="dict.dictLabel" :value="dict.dictValue" /> </el-select> </template> </el-table-column> <el-table-column label="打卡地点" align="center" prop="dkdd" width="150"> <template slot-scope="scope"> <el-select clearable @change="changedkdd(scope.row)" v-model="bcglXiangXiList[scope.row.xh-1].dkdd" > <el-option v-for="dict in dkddOptions" :key="dict.dictValue" :label="dict.dictLabel" :value="dict.dictValue" /> </el-select> </template> </el-table-column> <el-table-column label="最小井下累计时间-最大井下累计时间" width="250" prop="jxsjfw"> <template slot-scope="scope"> <el-time-picker is-range format="HH:mm" value-format="HH:mm" :style="{width: '100%'}" start-placeholder="开始时间" end-placeholder="结束时间" range-separator="至" clearable @change="changejxsjfw(scope.row)" v-model="bcglXiangXiList[scope.row.xh-1].jxsjfw" ></el-time-picker> </template> </el-table-column> </el-table>这里的数据源是个数组,所以绑定的每一行都是一个对象,怎样将每行与数据库源对应起来?首先怎样实现第一列的序号字段。这里通过设置el-table的:row-class-name="rowClassName"来实现,其中rowClassName是回调函数。所以需要在函数中实现rowClassName rowClassName({ row, rowIndex }) { row.xh = rowIndex + 1; },其中row是行对象,rowindex是行号,从0开始。所以这样就能实现了序号(xh属性)递增并且取值为行号加1。然后怎样实现勾选框单选?通过设置el-table的@selection-change="handleDetailSelectionChange"来实现对应的实现方法handleDetailSelectionChange中 //单选框选中数据 handleDetailSelectionChange(selection) { if (selection.length > 1) { this.$refs.tb.clearSelection(); this.$refs.tb.toggleRowSelection(selection.pop()); } else { this.checkedDetail = selection; } },这里的section本来是多选时选中项的数组,这里通过 this.$refs.tb获取到这个el-table,但是要提前给这个el-table设置ref="tb"然后判断所选的数组的长度大于1就清空并选中当前行,否则就将当前选中的赋值给checkedDetail,所以需要提前声明checkedDetail//选中的从表数据 checkedDetail: [],这样在上面对这个el-table绑定了数据源之后就可以通过类似v-model="bcglXiangXiList[scope.row.xh-1].ts"这种来进行动态数据绑定。实现新增一行新增按钮<el-button type="primary" icon="el-icon-plus" size="mini" @click="handleAddDetails">添加</el-button>在新增按钮对应的点击事件中 handleAddDetails() { if (this.bcglXiangXiList == undefined) { this.bcglXiangXiList = new Array(); } let obj = {}; obj.ts = "1"; obj.dkdd = "1"; obj.sjfw = ["07:00","07:30"]; obj.jxsjfw = ["06:00","12:00"]; this.bcglXiangXiList.push(obj); },前面先对数据源进行判断是不是undefined,因为在清空时会将其设置为undefined,所以需要重新新建。然后构建一个对象并赋值。将此对象添加进数据源bcglXiangXiList即可。实现删除一行前面已经对其勾选事件进行了重写,在勾选后将勾选的内容存储到了checkedDetail所以在删除前判断是否选中了一行就可以通过判断其长度即可。删除一行按钮<el-button type="success" icon="el-icon-delete" size="mini" @click="handleDeleteDetails" >删除</el-button>然后在删除按钮对应的事件中handleDeleteDetails() { if (this.checkedDetail.length == 0) { this.$alert("请先选择要删除的数据", "提示", { confirmButtonText: "确定", }); } else { this.bcglXiangXiList.splice(this.checkedDetail[0].xh - 1, 1); } },这里首先判断是否已经选择了一行,如果选择了一行之后,就可以通过存储的选中项的this.checkedDetail[0].xh -1获取当前行的index,而这个index正好与数据源中的index是想对应的。然后将此条数据在数据源中去掉即可实现删除一行。其中splice方法是表示从第一个索引参数开始,删除第二个参数个元素。清空所有行清空按钮< el - button type = "danger" icon = "el-icon-delete" size = "mini" @click = "handleDeleteAllDetails" > 清空 < /el-button>清空按钮对应的事件中handleDeleteAllDetails() { this.bcglXiangXiList = undefined; },将数据源设置为undefined即可。
2020年11月22日
1,393 阅读
0 评论
1 点赞
1
...
31
32
33
...
53