手写Service后台下载app——跳出DownloadManager系统7.0之坑

本文主要是介绍手写Service后台下载app——跳出DownloadManager系统7.0之坑,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言

之前项目中有关app的现在和更新相关工具类一直用的是Android系统下载管理DownloadManager功能。如果随着Android系统的不断提升再加上Android开源性 手机厂家
对此作恶部分改动。导致一些系统自带的工具类出现异常情况。

华为P9

华为P9/P9 Plus上线,你的APP准备好了吗?

新机入手后,MTC率先从应用市场随机下载部分APP做基于P9/P9 Plus的兼容性测试,在Monkey脚本跑完之后,我们发现部分App会出现Crash、ANR的问题。在此跟开发小伙伴们分享下产生此类问题的原因,开发小伙伴们在App开发过程中多加注意,避免此类问题的产生。

华为P9使用该 华为P9在7.1的时候,利用系统DownloadManager工具类下载时就出现异常——在下载过程中竟突然自动消失!

怀疑这个应该是Android系统和华为P9不兼容导致的一个的bug。

大家都知道,老板不懂代码,有时候出现的问题还不属于你的问题。在其他手机上好使,部分手机就出现问题。 只要有一款手机出现一个问题就认为你的程序有问题。

这是最蛋疼的。so,问题来了,谁让你是安卓程序员呢

哈哈,抱怨是没有用的。有问题还是要解决的。

1.首先是要判断是6.0权限

 /** * 请求运行时权限 * eg: */  public void requestRuntimePermission(QuestPermissionListener questPermissionListener, String... permissions){  BasePermisitionActivity.requestRuntimePermission(permissions,questPermissionListener);  }  .......

6.0运行权限请参考: android6.0运行时权限完美封装

下载service工具类:


/*** 类功能描述:</br>* 自定义Service后台下载app——跳出DownloadManager系统下载之坑 </br>* 修改人:   yuyahao* @version 1.0 </p> 修改时间:</br> 修改备注:</br>*/
public class UpdateService extends Service {public static final String TAG =  "ServiceDownLoadApp";public static final String ACTION = "me.shenfan.UPDATE_APP";public static final String STATUS = "status";public static final String PROGRESS = "progress";public static boolean DEBUG = true;//下载大小通知频率public static final int UPDATE_NUMBER_SIZE = 1;public static final int DEFAULT_RES_ID = -1;public static final int UPDATE_PROGRESS_STATUS = 0;public static final int UPDATE_ERROR_STATUS = -1;public static final int UPDATE_SUCCESS_STATUS = 1;//paramsprivate static final String URL = "downloadUrl";private static final String ICO_RES_ID = "icoResId";private static final String ICO_SMALL_RES_ID = "icoSmallResId";private static final String UPDATE_PROGRESS = "updateProgress";private static final String STORE_DIR = "storeDir";private static final String DOWNLOAD_NOTIFICATION_FLAG = "downloadNotificationFlag";private static final String DOWNLOAD_SUCCESS_NOTIFICATION_FLAG = "downloadSuccessNotificationFlag";private static final String DOWNLOAD_ERROR_NOTIFICATION_FLAG = "downloadErrorNotificationFlag";private static final String IS_SEND_BROADCAST = "isSendBroadcast";private String downloadUrl;private int icoResId;             //default app icoprivate int icoSmallResId;private int updateProgress;   //update notification progress when it add numberprivate static  String storeDir;          //default sdcard/Android/package/updateprivate int downloadNotificationFlag;private int downloadSuccessNotificationFlag;private int downloadErrorNotificationFlag;private boolean isSendBroadcast;private UpdateProgressListener updateProgressListener;private LocalBinder localBinder = new LocalBinder();/*** Class used for the client Binder.*/public class LocalBinder extends Binder{/*** set update progress call back* @param listener*/public void setUpdateProgressListener(UpdateProgressListener listener){UpdateService.this.setUpdateProgressListener(listener);}}private boolean startDownload;//开始下载private int lastProgressNumber;private NotificationCompat.Builder builder;private NotificationManager manager;private int notifyId;private String appName;private LocalBroadcastManager localBroadcastManager;private Intent localIntent;private DownloadApk downloadApkTask;/*** whether debug*/public static void debug(){DEBUG = true;}/*** 点击通知栏去进行安装* @param path* @return*/private static Intent installIntent(String path){Uri uri = Uri.fromFile(new File(path));Intent installIntent = new Intent(Intent.ACTION_VIEW);installIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);installIntent.setDataAndType(uri, "application/vnd.android.package-archive");return installIntent;}/*** 通过浏览器进行下载* @param downloadUrl* @return*/private static Intent webLauncher(String downloadUrl){Uri download = Uri.parse(downloadUrl);Intent intent = new Intent(Intent.ACTION_VIEW, download);intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);return intent;}/*** 通过URL获取要下载的apk的前缀没弄过* @param downloadUrl* @return*/private static String getSaveFileName(String downloadUrl) {if (downloadUrl == null || TextUtils.isEmpty(downloadUrl)) {return "noName.apk";}return downloadUrl.substring(downloadUrl.lastIndexOf("/"));}/*** 来设置要下载apk储存的文件夹* @param service* @return*/private static File getDownloadDir(UpdateService service){File downloadDir = null;if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {if (service.storeDir != null){downloadDir = new File(Environment.getExternalStorageDirectory(), service.storeDir);}else {downloadDir = new File(service.getExternalCacheDir(), "update");}} else {downloadDir = new File(service.getCacheDir(), "update");}if (!downloadDir.exists()) {downloadDir.mkdirs();}return downloadDir;}@Overridepublic void onCreate() {super.onCreate();appName = getApplicationName();}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {if (!startDownload && intent != null){startDownload = true;downloadUrl = intent.getStringExtra(URL);icoResId = intent.getIntExtra(ICO_RES_ID, DEFAULT_RES_ID);icoSmallResId = intent.getIntExtra(ICO_SMALL_RES_ID, DEFAULT_RES_ID);storeDir = intent.getStringExtra(STORE_DIR);updateProgress = intent.getIntExtra(UPDATE_PROGRESS, UPDATE_NUMBER_SIZE);downloadNotificationFlag = intent.getIntExtra(DOWNLOAD_NOTIFICATION_FLAG, 0);downloadErrorNotificationFlag = intent.getIntExtra(DOWNLOAD_ERROR_NOTIFICATION_FLAG, 0);downloadSuccessNotificationFlag = intent.getIntExtra(DOWNLOAD_SUCCESS_NOTIFICATION_FLAG, 0);isSendBroadcast = intent.getBooleanExtra(IS_SEND_BROADCAST, false);if (DEBUG){LogUtil.e(TAG, "downloadUrl: " + downloadUrl);LogUtil.e(TAG, "icoResId: " + icoResId);LogUtil.e(TAG, "icoSmallResId: " + icoSmallResId);LogUtil.e(TAG, "storeDir: " + storeDir);LogUtil.e(TAG, "updateProgress: " + updateProgress);LogUtil.e(TAG, "downloadNotificationFlag: " + downloadNotificationFlag);LogUtil.e(TAG, "downloadErrorNotificationFlag: " + downloadErrorNotificationFlag);LogUtil.e(TAG, "downloadSuccessNotificationFlag: " + downloadSuccessNotificationFlag);LogUtil.e(TAG, "isSendBroadcast: " + isSendBroadcast);}notifyId = startId;buildNotification();buildBroadcast();downloadApkTask = new DownloadApk(this);downloadApkTask.execute(downloadUrl);}return super.onStartCommand(intent, flags, startId);}@Nullable@Overridepublic IBinder onBind(Intent intent) {return localBinder;}@Overridepublic boolean onUnbind(Intent intent) {return true;}public void setUpdateProgressListener(UpdateProgressListener updateProgressListener) {this.updateProgressListener = updateProgressListener;}@Overridepublic void onDestroy() {if (downloadApkTask != null){downloadApkTask.cancel(true);}if (updateProgressListener != null){updateProgressListener = null;}localIntent = null;builder = null;super.onDestroy();}/*** 获取当前的应用名* @return*/public String getApplicationName() {PackageManager packageManager = null;ApplicationInfo applicationInfo = null;try {packageManager = getApplicationContext().getPackageManager();applicationInfo = packageManager.getApplicationInfo(getPackageName(), 0);} catch (PackageManager.NameNotFoundException e) {applicationInfo = null;}String applicationName =(String) packageManager.getApplicationLabel(applicationInfo);return applicationName;}private void buildBroadcast(){if (!isSendBroadcast){return;}localBroadcastManager = LocalBroadcastManager.getInstance(this);localIntent = new Intent(ACTION);}/*** 发送广播* @param status* @param progress*/private void sendLocalBroadcast(int status, int progress){if (!isSendBroadcast || localIntent == null){return;}localIntent.putExtra(STATUS, status);localIntent.putExtra(PROGRESS, progress);localBroadcastManager.sendBroadcast(localIntent);}/*** 环形通知安*/private void buildNotification(){manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);builder = new NotificationCompat.Builder(this);builder.setContentTitle(getString(R.string.update_app_model_prepare, appName)).setWhen(System.currentTimeMillis()).setProgress(100, 1, false).setSmallIcon(icoSmallResId).setLargeIcon(BitmapFactory.decodeResource(getResources(), icoResId)).setDefaults(downloadNotificationFlag);manager.notify(notifyId, builder.build());}/*** 开始 下载*/private void start(){builder.setContentTitle(appName);builder.setContentText(getString(R.string.update_app_model_prepare, 1));manager.notify(notifyId, builder.build());sendLocalBroadcast(UPDATE_PROGRESS_STATUS, 1);if (updateProgressListener != null){updateProgressListener.start();}}/**** 通知进度条,进度条* 大小范围(1~100)*/private void update(int progress){if (progress - lastProgressNumber > updateProgress){lastProgressNumber = progress;builder.setProgress(100, progress, false);builder.setContentText(getString(R.string.update_app_model_progress, progress, "%"));manager.notify(notifyId, builder.build());sendLocalBroadcast(UPDATE_PROGRESS_STATUS, progress);if (updateProgressListener != null){updateProgressListener.update(progress);}}}/*** 下载成功的回调* @param path*/private void success(String path) {builder.setProgress(0, 0, false);builder.setContentText(getString(R.string.update_app_model_success));GetToast.useString(this,"asdfasdf");manager.cancel(0);if(FileHelper.checkFileIsExists(path)){Intent i = installIntent(path);PendingIntent intent = PendingIntent.getActivity(this, 0, i, PendingIntent.FLAG_UPDATE_CURRENT);builder.setContentIntent(intent).setAutoCancel(true)//用户点击就自动消失.setDefaults(downloadSuccessNotificationFlag);Notification n = builder.build();n.contentIntent = intent;manager.notify(notifyId, n);if (updateProgressListener != null){updateProgressListener.success();}startActivity(i);IntentFilter filter = new IntentFilter();}else{DataCleanManager.deleteFilesByDirectory2(storeDir);}stopSelf();}/*** 清除本地文件*/public static void deleteFilesByDirectory(){DataCleanManager.deleteFilesByDirectory2(storeDir);}/*** 下载失败通知浏览器下载回调*/private void error(){Intent i = webLauncher(downloadUrl);PendingIntent intent = PendingIntent.getActivity(this, 0, i,PendingIntent.FLAG_UPDATE_CURRENT);builder.setContentText(getString(R.string.update_app_model_error));builder.setContentIntent(intent);builder.setProgress(0, 0, false);builder.setDefaults(downloadErrorNotificationFlag);Notification n = builder.build();n.contentIntent = intent;manager.notify(notifyId, n);sendLocalBroadcast(UPDATE_ERROR_STATUS, -1);if (updateProgressListener != null){updateProgressListener.error();}stopSelf();}/*** 下载异步任务*/private static class DownloadApk extends AsyncTask<String, Integer, String>{private WeakReference<UpdateService> updateServiceWeakReference;public DownloadApk(UpdateService service){updateServiceWeakReference = new WeakReference<>(service);}@Overrideprotected void onPreExecute() {super.onPreExecute();UpdateService service = updateServiceWeakReference.get();if (service != null){service.start();}}@Overrideprotected String doInBackground(String... params) {//注意,这里现在之前先进行清空文件,防止因检查到已经有存在的文件而无法 进行下载DataCleanManager.deleteFilesByDirectory2(""+  UpdateService.getDownloadDir(updateServiceWeakReference.get()) .getAbsolutePath());final String downloadUrl = params[0];final File file = new File(UpdateService.getDownloadDir(updateServiceWeakReference.get()),UpdateService.getSaveFileName(downloadUrl));if (DEBUG){LogUtil.e(TAG, "download url is " + downloadUrl);LogUtil.e(TAG, "download apk cache at " + file.getAbsolutePath());}File dir = file.getParentFile();if (!dir.exists()){dir.mkdirs();}HttpURLConnection httpConnection = null;InputStream is = null;FileOutputStream fos = null;int updateTotalSize = 0;URL url;try {url = new URL(downloadUrl);httpConnection = (HttpURLConnection) url.openConnection();httpConnection.setConnectTimeout(5000);httpConnection.setReadTimeout(5000);if (DEBUG){LogUtil.e(TAG, "download status code: " + httpConnection.getResponseCode());}if (httpConnection.getResponseCode() != 200) {return null;}updateTotalSize = httpConnection.getContentLength();if (file.exists()) {if (updateTotalSize == file.length()) {// 下载完成return file.getAbsolutePath();} else {file.delete();}}file.createNewFile();is = httpConnection.getInputStream();fos = new FileOutputStream(file, false);byte buffer[] = new byte[4096];int readSize = 0;int currentSize = 0;while ((readSize = is.read(buffer)) > 0) {fos.write(buffer, 0, readSize);currentSize += readSize;publishProgress((currentSize * 100 / updateTotalSize));}// download success} catch (Exception e) {e.printStackTrace();return null;} finally {if (httpConnection != null) {httpConnection.disconnect();}if (is != null) {try {is.close();} catch (IOException e) {e.printStackTrace();}}if (fos != null) {try {fos.close();} catch (IOException e) {e.printStackTrace();}}}return file.getAbsolutePath();}@Overrideprotected void onProgressUpdate(Integer... values) {super.onProgressUpdate(values);if (DEBUG){LogUtil.e(TAG, "current progress is " + values[0]);}UpdateService service = updateServiceWeakReference.get();if (service != null){service.update(values[0]);}}@Overrideprotected void onPostExecute(String s) {super.onPostExecute(s);UpdateService service = updateServiceWeakReference.get();if (service != null){if (s != null){service.success(s);}else {service.error();}}}}/*** a builder class helper use UpdateService* 仿AlertDialogUpdateService的构造器*/public static class Builder{private String downloadUrl;private int icoResId = DEFAULT_RES_ID;             //default app icoprivate int icoSmallResId = DEFAULT_RES_ID;private int updateProgress = UPDATE_NUMBER_SIZE;   //update notification progress when it add numberprivate String storeDir;          //default sdcard/Android/package/updateprivate int downloadNotificationFlag;private int downloadSuccessNotificationFlag;private int downloadErrorNotificationFlag;private boolean isSendBroadcast;protected Builder(String downloadUrl){this.downloadUrl = downloadUrl;}public static Builder create(String downloadUrl){if (downloadUrl == null) {throw new NullPointerException("downloadUrl == null");}return new Builder(downloadUrl);}public String getDownloadUrl() {return downloadUrl;}public int getIcoResId() {return icoResId;}public Builder setIcoResId(int icoResId) {this.icoResId = icoResId;return this;}public int getIcoSmallResId() {return icoSmallResId;}public Builder setIcoSmallResId(int icoSmallResId) {this.icoSmallResId = icoSmallResId;return this;}public int getUpdateProgress() {return updateProgress;}public Builder setUpdateProgress(int updateProgress) {if (updateProgress < 1){throw new IllegalArgumentException("updateProgress < 1");}this.updateProgress = updateProgress;return this;}public String getStoreDir() {return storeDir;}public Builder setStoreDir(String storeDir) {this.storeDir = storeDir;return this;}public int getDownloadNotificationFlag() {return downloadNotificationFlag;}public Builder setDownloadNotificationFlag(int downloadNotificationFlag) {this.downloadNotificationFlag = downloadNotificationFlag;return this;}public int getDownloadSuccessNotificationFlag() {return downloadSuccessNotificationFlag;}public Builder setDownloadSuccessNotificationFlag(int downloadSuccessNotificationFlag) {this.downloadSuccessNotificationFlag = downloadSuccessNotificationFlag;return this;}public int getDownloadErrorNotificationFlag() {return downloadErrorNotificationFlag;}public Builder setDownloadErrorNotificationFlag(int downloadErrorNotificationFlag) {this.downloadErrorNotificationFlag = downloadErrorNotificationFlag;return this;}public boolean isSendBroadcast() {return isSendBroadcast;}public Builder setIsSendBroadcast(boolean isSendBroadcast) {this.isSendBroadcast = isSendBroadcast;return this;}public Builder build(Context context){if (context == null){throw new NullPointerException("context == null");}Intent intent = new Intent();intent.setClass(context, UpdateService.class);intent.putExtra(URL, downloadUrl);if (icoResId == DEFAULT_RES_ID){icoResId = getIcon(context);}if (icoSmallResId == DEFAULT_RES_ID){icoSmallResId = icoResId;}intent.putExtra(ICO_RES_ID, icoResId);intent.putExtra(STORE_DIR, storeDir);intent.putExtra(ICO_SMALL_RES_ID, icoSmallResId);intent.putExtra(UPDATE_PROGRESS, updateProgress);intent.putExtra(DOWNLOAD_NOTIFICATION_FLAG, downloadNotificationFlag);intent.putExtra(DOWNLOAD_SUCCESS_NOTIFICATION_FLAG, downloadSuccessNotificationFlag);intent.putExtra(DOWNLOAD_ERROR_NOTIFICATION_FLAG, downloadErrorNotificationFlag);intent.putExtra(IS_SEND_BROADCAST, isSendBroadcast);context.startService(intent);return this;}/*** 得到系当前应用的相对应的图标* @param context* @return*/private int getIcon(Context context){final PackageManager packageManager = context.getPackageManager();ApplicationInfo appInfo = null;try {appInfo = packageManager.getApplicationInfo(context.getPackageName(), PackageManager.GET_META_DATA);} catch (PackageManager.NameNotFoundException e) {e.printStackTrace();}if (appInfo != null){return appInfo.icon;}return 0;}}}

注意这里的LocalBroadcastManager

LocalBroadcastManager基本介绍 这个类是在v4包中的,谷歌官方的介绍是:

Helper to register for and send broadcasts of Intents to local objects within your process. This is has a number of advantages over sending global broadcasts with sendBroadcast(Intent):
You know that the data you are broadcasting won’t leave your app, so don’t need to worry about leaking private data. It is not possible for other applications to send these broadcasts to your app, so you don’t need to worry about having security holes they can exploit. It is more efficient than sending a global broadcast through the system.

大致意思是:
帮助程序注册和发送Intents的广播到您的进程中的本地对象。 这是一个有趣的发送全局广播与sendBroadcast(Intent):
你知道你收音机的数据不会离开你的应用程序,所以不需要担心泄露的私人数据。 其他应用程序不可能将这些广播发送到您的应用程序,因此您不需要担心它们可以利用的安全漏洞。 它比通过系统发送全局广播更有效。

优点:

  • 能够完成在应用内的广播发送,而且比全局广播更具优势:
  • 广播只会在你的应用内发送,所以无需担心数据泄露,更加安全。
  • 其他应用无法发广播给你的应用,所以也不用担心你的应用有别人可以利用的安全漏洞
  • 相比较全局广播,它不需要发送给整个系统,所以更加高效。

使用方式

  • 广播注册:
LocalBroadcastManager localBroadcastManager = LocalBroadcastManager.getInstance(getActivity());IntentFilter filter = new IntentFilter();filter.addAction(ACTION);myBroadcastReciver = new MyBroadcastReciver();localBroadcastManager.registerReceiver(myBroadcastReciver, filter);
  • 广播发送
 Intent intent = new Intent();intent.setAction(SaleLeftFragment.ACTION);intent.putExtra(TAG, data);LocalBroadcastManager.getInstance(getActivity()).sendBroadcast(intent);
  • 使用注意

在使用的时候,请关注以下几点:

  • 1).LocalBroadcastManager注册广播只能通过代码注册的方式。
  • 2).LocalBroadcastManager注册广播后,一定要记得取消监听。
  • 3).重点的重点,使用LocalBroadcastManager注册的广播,您在发送广播的时候务必使用LocalBroadcastManager.sendBroadcast(intent);否则您接收不到广播

主Activity中的代码:


public class MainActivity extends AppCompatActivity {/*** 下载地址的URL*/private static final String URL = "http://192.168.1.11/mydoctor.apk";@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);ButterKnife.inject(this);}public void update(View view){UpdateService.Builder.create(URL).build(this);}@OnClick(R.id.btn_downLoad)public void onClick(View view){UpdateService.Builder.create(URL).setStoreDir("update/flag").setDownloadSuccessNotificationFlag(Notification.DEFAULT_ALL).setDownloadErrorNotificationFlag(Notification.DEFAULT_ALL).build(this);}
}

项目下载地址:
https://github.com/androidstarjack/ServiceDownLoadApp-master

如果你觉得此文对您有所帮助,欢迎入群 QQ交流群 :232203809   
微信公众号:终端研发部

Markdown

(欢迎关注学习和交流)

这篇关于手写Service后台下载app——跳出DownloadManager系统7.0之坑的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/212279

相关文章

不懂推荐算法也能设计推荐系统

本文以商业化应用推荐为例,告诉我们不懂推荐算法的产品,也能从产品侧出发, 设计出一款不错的推荐系统。 相信很多新手产品,看到算法二字,多是懵圈的。 什么排序算法、最短路径等都是相对传统的算法(注:传统是指科班出身的产品都会接触过)。但对于推荐算法,多数产品对着网上搜到的资源,都会无从下手。特别当某些推荐算法 和 “AI”扯上关系后,更是加大了理解的难度。 但,不了解推荐算法,就无法做推荐系

基于人工智能的图像分类系统

目录 引言项目背景环境准备 硬件要求软件安装与配置系统设计 系统架构关键技术代码示例 数据预处理模型训练模型预测应用场景结论 1. 引言 图像分类是计算机视觉中的一个重要任务,目标是自动识别图像中的对象类别。通过卷积神经网络(CNN)等深度学习技术,我们可以构建高效的图像分类系统,广泛应用于自动驾驶、医疗影像诊断、监控分析等领域。本文将介绍如何构建一个基于人工智能的图像分类系统,包括环境

水位雨量在线监测系统概述及应用介绍

在当今社会,随着科技的飞速发展,各种智能监测系统已成为保障公共安全、促进资源管理和环境保护的重要工具。其中,水位雨量在线监测系统作为自然灾害预警、水资源管理及水利工程运行的关键技术,其重要性不言而喻。 一、水位雨量在线监测系统的基本原理 水位雨量在线监测系统主要由数据采集单元、数据传输网络、数据处理中心及用户终端四大部分构成,形成了一个完整的闭环系统。 数据采集单元:这是系统的“眼睛”,

嵌入式QT开发:构建高效智能的嵌入式系统

摘要: 本文深入探讨了嵌入式 QT 相关的各个方面。从 QT 框架的基础架构和核心概念出发,详细阐述了其在嵌入式环境中的优势与特点。文中分析了嵌入式 QT 的开发环境搭建过程,包括交叉编译工具链的配置等关键步骤。进一步探讨了嵌入式 QT 的界面设计与开发,涵盖了从基本控件的使用到复杂界面布局的构建。同时也深入研究了信号与槽机制在嵌入式系统中的应用,以及嵌入式 QT 与硬件设备的交互,包括输入输出设

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟&nbsp;开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚&nbsp;第一站:海量资源,应有尽有 走进“智听

常用的jdk下载地址

jdk下载地址 安装方式可以看之前的博客: mac安装jdk oracle 版本:https://www.oracle.com/java/technologies/downloads/ Eclipse Temurin版本:https://adoptium.net/zh-CN/temurin/releases/ 阿里版本: github:https://github.com/

【区块链 + 人才服务】可信教育区块链治理系统 | FISCO BCOS应用案例

伴随着区块链技术的不断完善,其在教育信息化中的应用也在持续发展。利用区块链数据共识、不可篡改的特性, 将与教育相关的数据要素在区块链上进行存证确权,在确保数据可信的前提下,促进教育的公平、透明、开放,为教育教学质量提升赋能,实现教育数据的安全共享、高等教育体系的智慧治理。 可信教育区块链治理系统的顶层治理架构由教育部、高校、企业、学生等多方角色共同参与建设、维护,支撑教育资源共享、教学质量评估、

软考系统规划与管理师考试证书含金量高吗?

2024年软考系统规划与管理师考试报名时间节点: 报名时间:2024年上半年软考将于3月中旬陆续开始报名 考试时间:上半年5月25日到28日,下半年11月9日到12日 分数线:所有科目成绩均须达到45分以上(包括45分)方可通过考试 成绩查询:可在“中国计算机技术职业资格网”上查询软考成绩 出成绩时间:预计在11月左右 证书领取时间:一般在考试成绩公布后3~4个月,各地领取时间有所不同

系统架构师考试学习笔记第三篇——架构设计高级知识(20)通信系统架构设计理论与实践

本章知识考点:         第20课时主要学习通信系统架构设计的理论和工作中的实践。根据新版考试大纲,本课时知识点会涉及案例分析题(25分),而在历年考试中,案例题对该部分内容的考查并不多,虽在综合知识选择题目中经常考查,但分值也不高。本课时内容侧重于对知识点的记忆和理解,按照以往的出题规律,通信系统架构设计基础知识点多来源于教材内的基础网络设备、网络架构和教材外最新时事热点技术。本课时知识

计算机毕业设计 大学志愿填报系统 Java+SpringBoot+Vue 前后端分离 文档报告 代码讲解 安装调试

🍊作者:计算机编程-吉哥 🍊简介:专业从事JavaWeb程序开发,微信小程序开发,定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事,生活就是快乐的。 🍊心愿:点赞 👍 收藏 ⭐评论 📝 🍅 文末获取源码联系 👇🏻 精彩专栏推荐订阅 👇🏻 不然下次找不到哟~Java毕业设计项目~热门选题推荐《1000套》 目录 1.技术选型 2.开发工具 3.功能