Android实战之app版本更新升级全文章(一),2024年最新一线互联网架构师Android框架体系架构

DownloadManager.Request request = new DownloadManager.Request(Uri.parse(apkurl)); //设置在什么网络情况下进行下载 request.setAllowedNetworkTypes(Request.NETWORK_WIFI); //设置通知栏标题 request.setNotificationVisibility(Request.VISIBILITY_VISIBLE); request.setTitle("下载"); request.setDescription("apk正在下载"); request.setAllowedOverRoaming(false); //设置文件存放目录 request.setDestinationInExternalFilesDir(this, Environment.DIRECTORY_DOWNLOADS, "mydown");

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

取得系统服务后,调用downloadmanager对象的enqueue方法进行下载,此方法返回一个编号用于标示此下载任务:

downManager = (DownloadManager)getSystemService(Context.DOWNLOAD_SERVICE); id= downManager.enqueue(request);

  • 1

  • 2

  • 1

  • 2

这里我们可以看下request的一些属性:

addRequestHeader(String header,String value):添加网络下载请求的http头信息 allowScanningByMediaScanner():用于设置是否允许本MediaScanner扫描。 setAllowedNetworkTypes(int flags):设置用于下载时的网络类型,默认任何网络都可以下载,提供的网络常量有:NETWORK_BLUETOOTH、NETWORK_MOBILE、NETWORK_WIFI。 setAllowedOverRoaming(Boolean allowed):用于设置漫游状态下是否可以下载 setNotificationVisibility(int visibility):用于设置下载时时候在状态栏显示通知信息 setTitle(CharSequence):设置Notification的title信息 setDescription(CharSequence):设置Notification的message信息 setDestinationInExternalFilesDir、setDestinationInExternalPublicDir、 setDestinationUri等方法用于设置下载文件的存放路径,注意如果将下载文件存放在默认路径,那么在空间不足的情况下系统会将文件删除,所 以使用上述方法设置文件存放目录是十分必要的。

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

具体实现思路:

  1. 我们通过downloaderManager来下载apk,并且本地保存downManager.enqueue(request)返回的id值,并且通过这个id获取apk的下载文件路径和下载的状态,并且通过状态来更新通知栏的显示。
  1. 第一次下载成功,弹出安装界面
如果用户没有点击安装,而是按了返回键,在某个时候,又再次使用了我们的APP
如果下载成功,则判断本地的apk的包名是否和当前程序是相同的,并且本地apk的版本号大于当前程序的版本,如果都满足则直接启动安装程序。

具体代码实现:

文件下载管理的实现,包括创建request和加入队列下载,通过返回的id来获取下载路径和下载状态。

public class FileDownloadManager { private DownloadManager downloadManager; private Context context; private static FileDownloadManager instance; private FileDownloadManager(Context context) { downloadManager = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE); this.context = context.getApplicationContext(); } public static FileDownloadManager getInstance(Context context) { if (instance == null) { instance = new FileDownloadManager(context); } return instance; } /** * @param uri * @param title * @param description * @return download id */ public long startDownload(String uri, String title, String description,String appName) { DownloadManager.Request req = new DownloadManager.Request(Uri.parse(uri)); req.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI); //req.setAllowedOverRoaming(false); req.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); //设置文件的保存的位置[三种方式] //第一种 //file:///storage/emulated/0/Android/data/your-package/files/Download/update.apk req.setDestinationInExternalFilesDir(context, Environment.DIRECTORY_DOWNLOADS, appName+".apk"); //第二种 //file:///storage/emulated/0/Download/update.apk //req.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "update.apk"); //第三种 自定义文件路径 //req.setDestinationUri() // 设置一些基本显示信息 req.setTitle(title); req.setDescription(description); //req.setMimeType("application/vnd.android.package-archive"); return downloadManager.enqueue(req);//异步 //dm.openDownloadedFile() } /** * 获取文件保存的路径 * * @param downloadId an ID for the download, unique across the system. * This ID is used to make future calls related to this download. * @return file path * @see FileDownloadManager#getDownloadUri(long) */ public String getDownloadPath(long downloadId) { DownloadManager.Query query = new DownloadManager.Query().setFilterById(downloadId); Cursor c = downloadManager.query(query); if (c != null) { try { if (c.moveToFirst()) { return c.getString(c.getColumnIndexOrThrow(DownloadManager.COLUMN_LOCAL_URI)); } } finally { c.close(); } } return null; } /** * 获取保存文件的地址 * * @param downloadId an ID for the download, unique across the system. * This ID is used to make future calls related to this download. * @see FileDownloadManager#getDownloadPath(long) */ public Uri getDownloadUri(long downloadId) { return downloadManager.getUriForDownloadedFile(downloadId); } public DownloadManager getDownloadManager() { return downloadManager; } /** * 获取下载状态 * * @param downloadId an ID for the download, unique across the system. * This ID is used to make future calls related to this download. * @return int * @see DownloadManager#STATUS_PENDING * @see DownloadManager#STATUS_PAUSED * @see DownloadManager#STATUS_RUNNING * @see DownloadManager#STATUS_SUCCESSFUL * @see DownloadManager#STATUS_FAILED */ public int getDownloadStatus(long downloadId) { DownloadManager.Query query = new DownloadManager.Query().setFilterById(downloadId); Cursor c = downloadManager.query(query); if (c != null) { try { if (c.moveToFirst()) { return c.getInt(c.getColumnIndexOrThrow(DownloadManager.COLUMN_STATUS)); } } finally { c.close(); } } return -1; } }

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

  • 12

  • 13

  • 14

  • 15

  • 16

  • 17

  • 18

  • 19

  • 20

  • 21

  • 22

  • 23

  • 24

  • 25

  • 26

  • 27

  • 28

  • 29

  • 30

  • 31

  • 32

  • 33

  • 34

  • 35

  • 36

  • 37

  • 38

  • 39

  • 40

  • 41

  • 42

  • 43

  • 44

  • 45

  • 46

  • 47

  • 48

  • 49

  • 50

  • 51

  • 52

  • 53

  • 54

  • 55

  • 56

  • 57

  • 58

  • 59

  • 60

  • 61

  • 62

  • 63

  • 64

  • 65

  • 66

  • 67

  • 68

  • 69

  • 70

  • 71

  • 72

  • 73

  • 74

  • 75

  • 76

  • 77

  • 78

  • 79

  • 80

  • 81

  • 82

  • 83

  • 84

  • 85

  • 86

  • 87

  • 88

  • 89

  • 90

  • 91

  • 92

  • 93

  • 94

  • 95

  • 96

  • 97

  • 98

  • 99

  • 100

  • 101

  • 102

  • 103

  • 104

  • 105

  • 106

  • 107

  • 108

  • 109

  • 110

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

  • 12

  • 13

  • 14

  • 15

  • 16

  • 17

  • 18

  • 19

  • 20

  • 21

  • 22

  • 23

  • 24

  • 25

  • 26

  • 27

  • 28

  • 29

  • 30

  • 31

  • 32

  • 33

  • 34

  • 35

  • 36

  • 37

  • 38

  • 39

  • 40

  • 41

  • 42

  • 43

  • 44

  • 45

  • 46

  • 47

  • 48

  • 49

  • 50

  • 51

  • 52

  • 53

  • 54

  • 55

  • 56

  • 57

  • 58

  • 59

  • 60

  • 61

  • 62

  • 63

  • 64

  • 65

  • 66

  • 67

  • 68

  • 69

  • 70

  • 71

  • 72

  • 73

  • 74

  • 75

  • 76

  • 77

  • 78

  • 79

  • 80

  • 81

  • 82

  • 83

  • 84

  • 85

  • 86

  • 87

  • 88

  • 89

  • 90

  • 91

  • 92

  • 93

  • 94

  • 95

  • 96

  • 97

  • 98

  • 99

  • 100

  • 101

  • 102

  • 103

  • 104

  • 105

  • 106

  • 107

  • 108

  • 109

  • 110

app的检测安装的实现:

public class DownLoadApk { public static final String TAG = DownLoadApk.class.getSimpleName(); public static void download(Context context, String url, String title,final String appName) { // 获取存储ID SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context); long downloadId =sp.getLong(DownloadManager.EXTRA_DOWNLOAD_ID,-1L); if (downloadId != -1L) { FileDownloadManager fdm = FileDownloadManager.getInstance(context); int status = fdm.getDownloadStatus(downloadId); if (status == DownloadManager.STATUS_SUCCESSFUL) { //启动更新界面 Uri uri = fdm.getDownloadUri(downloadId); if (uri != null) { if (compare(getApkInfo(context, uri.getPath()), context)) { startInstall(context, uri); return; } else { fdm.getDownloadManager().remove(downloadId); } } start(context, url, title,appName); } else if (status == DownloadManager.STATUS_FAILED) { start(context, url, title,appName); } else { Log.d(TAG, "apk is already downloading"); } } else { start(context, url, title,appName); } } private static void start(Context context, String url, String title,String appName) { long id = FileDownloadManager.getInstance(context).startDownload(url, title, "下载完成后点击打开",appName); SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context); sp.edit().putLong(DownloadManager.EXTRA_DOWNLOAD_ID,id).commit(); Log.d(TAG, "apk start download " + id); } public static void startInstall(Context context, Uri uri) { Intent install = new Intent(Intent.ACTION_VIEW); install.setDataAndType(uri, "application/vnd.android.package-archive"); install.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(install); } /** * 获取apk程序信息[packageName,versionName...] * * @param context Context * @param path apk path */ private static PackageInfo getApkInfo(Context context, String path) { PackageManager pm = context.getPackageManager(); PackageInfo info = pm.getPackageArchiveInfo(path, PackageManager.GET_ACTIVITIES); if (info != null) { return info; } return null; } /** * 下载的apk和当前程序版本比较 * * @param apkInfo apk file's packageInfo * @param context Context * @return 如果当前应用版本小于apk的版本则返回true */ private static boolean compare(PackageInfo apkInfo, Context context) { if (apkInfo == null) { return false; } String localPackage = context.getPackageName(); if (apkInfo.packageName.equals(localPackage)) { try { PackageInfo packageInfo = context.getPackageManager().getPackageInfo(localPackage, 0); if (apkInfo.versionCode > packageInfo.versionCode) { return true; } } catch (PackageManager.NameNotFoundException e) { e.printStackTrace(); } } return false; } }

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

  • 12

  • 13

  • 14

  • 15

  • 16

  • 17

  • 18

  • 19

  • 20

  • 21

  • 22

  • 23

  • 24

  • 25

  • 26

  • 27

  • 28

  • 29

  • 30

  • 31

  • 32

  • 33

  • 34

  • 35

  • 36

  • 37

  • 38

  • 39

  • 40

  • 41

  • 42

  • 43

  • 44

  • 45

  • 46

  • 47

  • 48

  • 49

  • 50

  • 51

  • 52

  • 53

  • 54

  • 55

  • 56

  • 57

  • 58

  • 59

  • 60

  • 61

  • 62

  • 63

  • 64

  • 65

  • 66

  • 67

  • 68

  • 69

  • 70

  • 71

  • 72

  • 73

  • 74

  • 75

  • 76

  • 77

  • 78

  • 79

  • 80

  • 81

  • 82

  • 83

  • 84

  • 85

  • 86

  • 87

  • 88

  • 89

  • 90

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

  • 12

  • 13

  • 14

  • 15

  • 16

  • 17

  • 18

  • 19

  • 20

  • 21

  • 22

  • 23

  • 24

  • 25

  • 26

  • 27

  • 28

  • 29

  • 30

  • 31

  • 32

  • 33

  • 34

  • 35

  • 36

  • 37

  • 38

  • 39

  • 40

  • 41

  • 42

  • 43

  • 44

  • 45

  • 46

  • 47

  • 48

  • 49

  • 50

  • 51

  • 52

  • 53

  • 54

  • 55

  • 56

  • 57

  • 58

  • 59

  • 60

  • 61

  • 62

  • 63

  • 64

  • 65

  • 66

  • 67

  • 68

  • 69

  • 70

  • 71

  • 72

  • 73

  • 74

  • 75

  • 76

  • 77

  • 78

  • 79

  • 80

  • 81

  • 82

  • 83

  • 84

  • 85

  • 86

  • 87

  • 88

  • 89

  • 90

上面的代码可知:我们通过获取当前app的信息来比较是否需要下载和是否立即安装。第一次下载把downloadId保存到本地,用户下次进来的时候,取出保存的downloadId,然后通过downloadId来获取下载的状态信息。如果下载失败,则重新下载并且把downloadId存起来。如果下载成功,则判断本地的apk的包名是否和当前程序是相同的,并且本地apk的版本号大于当前程序的版本,如果都满足则直接启动安装程序。

监听app是否安装完成

public class ApkInstallReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { if(intent.getAction().equals(DownloadManager.ACTION_DOWNLOAD_COMPLETE)){ long downloadApkId =intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1); installApk(context, downloadApkId); } } /** * 安装apk */ private void installApk(Context context,long downloadApkId) { // 获取存储ID SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context); long downId =sp.getLong(DownloadManager.EXTRA_DOWNLOAD_ID,-1L); if(downloadApkId == downId){ DownloadManager downManager= (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE); Uri downloadFileUri = downManager.getUriForDownloadedFile(downloadApkId); if (downloadFileUri != null) { Intent install= new Intent(Intent.ACTION_VIEW); install.setDataAndType(downloadFileUri, "application/vnd.android.package-archive"); install.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(install); }else{ Toast.makeText(context, "下载失败", Toast.LENGTH_SHORT).show(); } } } }

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

  • 12

  • 13

  • 14

  • 15

  • 16

  • 17

  • 18

  • 19

  • 20

  • 21

  • 22

  • 23

  • 24

  • 25

  • 26

  • 27

  • 28

  • 29

  • 30

  • 31

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

  • 12

  • 13

  • 14

  • 15

  • 16

  • 17

  • 18

  • 19

  • 20

  • 21

  • 22

  • 23

  • 24

  • 25

  • 26

  • 27

  • 28

  • 29

  • 30

  • 31

DownloadManager下载完成后会发出一个广播 android.intent.action.DOWNLOAD_COMPLETE 新建一个广播接收者即可:

清单配置:

先添加网络下载的权限:

<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

  • 1

  • 2

  • 1

  • 2

再添加静态广播:

<receiver android:name=".ApkInstallReceiver"> <intent-filter> <action android:name="android.intent.action.DOWNLOAD_COMPLETE" /> </intent-filter> </receiver>

  • 1

  • 2

  • 3

  • 4

  • 5

  • 1

  • 2

  • 3

  • 4

  • 5

使用HttpUrlConnection下载

这种情况下载的话我们就不需要考虑id的问题,因为是直接在项目中下载,所以我们就是一个网络下载的过程,并且使用ProgressDialog显示下载信息及进度更新就ok了。

public class AppInnerDownLoder { public final static String SD_FOLDER = Environment.getExternalStorageDirectory()+ "/VersionChecker/"; private static final String TAG = AppInnerDownLoder.class.getSimpleName(); /** * 从服务器中下载APK */ @SuppressWarnings("unused") public static void downLoadApk(final Context mContext,final String downURL,final String appName ) { final ProgressDialog pd; // 进度条对话框 pd = new ProgressDialog(mContext); pd.setCancelable(false);// 必须一直下载完,不可取消 pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); pd.setMessage("正在下载安装包,请稍后"); pd.setTitle("版本升级"); pd.show(); new Thread() { @Override public void run() { try { File file = downloadFile(downURL,appName, pd); sleep(3000); installApk(mContext, file); // 结束掉进度条对话框 pd.dismiss(); } catch (Exception e) { pd.dismiss(); } } }.start(); } /** * 从服务器下载最新更新文件 * * @param path * 下载路径 * @param pd * 进度条 * @return * @throws Exception */ private static File downloadFile(String path,String appName ,ProgressDialog pd) throws Exception { // 如果相等的话表示当前的sdcard挂载在手机上并且是可用的 if (Environment.MEDIA_MOUNTED.equals(Environment .getExternalStorageState())) { URL url = new URL(path); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setConnectTimeout(5000); // 获取到文件的大小 pd.setMax(conn.getContentLength()); InputStream is = conn.getInputStream(); String fileName = SD_FOLDER + appName+".apk"; File file = new File(fileName); // 目录不存在创建目录 if (!file.getParentFile().exists()) file.getParentFile().mkdirs(); FileOutputStream fos = new FileOutputStream(file); BufferedInputStream bis = new BufferedInputStream(is); byte[] buffer = new byte[1024]; int len; int total = 0; while ((len = bis.read(buffer)) != -1) { fos.write(buffer, 0, len); total += len; // 获取当前下载量 pd.setProgress(total); } fos.close(); bis.close(); is.close(); return file; } else { throw new IOException("未发现有SD卡"); } } /** * 安装apk */ private static void installApk(Context mContext, File file) { Uri fileUri = Uri.fromFile(file); Intent it = new Intent(); it.setAction(Intent.ACTION_VIEW); it.setDataAndType(fileUri, "application/vnd.android.package-archive"); it.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);// 防止打不开应用 mContext.startActivity(it); } /** * 获取应用程序版本(versionName) * * @return 当前应用的版本号 */ private static double getLocalVersion(Context context) { PackageManager manager = context.getPackageManager(); PackageInfo info = null; try { info = manager.getPackageInfo(context.getPackageName(), 0); } catch (NameNotFoundException e) { Log.e(TAG, "获取应用程序版本失败,原因:" + e.getMessage()); return 0.0; } return Double.valueOf(info.versionName); } /** * byte(字节)根据长度转成kb(千字节)和mb(兆字节) * * @param bytes * @return */ public static String bytes2kb(long bytes) { BigDecimal filesize = new BigDecimal(bytes); BigDecimal megabyte = new BigDecimal(1024 * 1024); float returnValue = filesize.divide(megabyte, 2, BigDecimal.ROUND_UP) .floatValue(); if (returnValue > 1) return (returnValue + "MB"); BigDecimal kilobyte = new BigDecimal(1024); returnValue = filesize.divide(kilobyte, 2, BigDecimal.ROUND_UP) .floatValue(); return (returnValue + "KB"); } }

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

  • 12

  • 13

  • 14

  • 15

  • 16

  • 17

  • 18

  • 19

  • 20

  • 21

  • 22

  • 23

  • 24

  • 25

  • 26

  • 27

  • 28

  • 29

  • 30

  • 31

  • 32

  • 33

  • 34

  • 35

  • 36

  • 37

  • 38

  • 39

  • 40

  • 41

  • 42

  • 43

  • 44

  • 45

  • 46

  • 47

  • 48

  • 49

  • 50

  • 51

  • 52

  • 53

  • 54

  • 55

  • 56

  • 57

  • 58

  • 59

  • 60

  • 61

  • 62

  • 63

  • 64

  • 65

  • 66

  • 67

  • 68

  • 69

  • 70

  • 71

  • 72

  • 73

  • 74

  • 75

  • 76

  • 77

  • 78

  • 79

  • 80

  • 81

  • 82

  • 83

  • 84

  • 85

  • 86

  • 87

  • 88

  • 89

  • 90

  • 91

  • 92

  • 93

  • 94

  • 95

  • 96

  • 97

  • 98

  • 99

  • 100

  • 101

  • 102

  • 103

  • 104

  • 105

  • 106

  • 107

  • 108

  • 109

  • 110

  • 111

  • 112

  • 113

  • 114

  • 115

  • 116

  • 117

  • 118

  • 119

  • 120

  • 121

  • 122

  • 123

  • 124

  • 125

  • 126

  • 127

  • 128

  • 129

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

  • 12

  • 13

  • 14

  • 15

  • 16

  • 17

  • 18

  • 19

  • 20

  • 21

  • 22

  • 23

  • 24

  • 25

  • 26

  • 27

  • 28

  • 29

  • 30

  • 31

  • 32

  • 33

  • 34

  • 35

  • 36

  • 37

  • 38

  • 39

  • 40

  • 41

  • 42

  • 43

  • 44

  • 45

  • 46

  • 47

  • 48

  • 49

  • 50

  • 51

  • 52

  • 53

  • 54

  • 55

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
img

最后

简历首选内推方式,速度快,效率高啊!然后可以在拉钩,boss,脉脉,大街上看看。简历上写道熟悉什么技术就一定要去熟悉它,不然被问到不会很尴尬!做过什么项目,即使项目体量不大,但也一定要熟悉实现原理!不是你负责的部分,也可以看看同事是怎么实现的,换你来做你会怎么做?做过什么,会什么是广度问题,取决于项目内容。但做过什么,达到怎样一个境界,这是深度问题,和个人学习能力和解决问题的态度有关了。大公司看深度,小公司看广度。大公司面试你会的,小公司面试他们用到的你会不会,也就是岗位匹配度。

面试过程一定要有礼貌!即使你觉得面试官不尊重你,经常打断你的讲解,或者你觉得他不如你,问的问题缺乏专业水平,你也一定要尊重他,谁叫现在是他选择你,等你拿到offer后就是你选择他了。

另外,描述问题一定要慢!不要一下子讲一大堆,慢显得你沉稳、自信,而且你还有时间反应思路接下来怎么讲更好。现在开发过多依赖ide,所以会有个弊端,当我们在面试讲解很容易不知道某个方法怎么读,这是一个硬伤…所以一定要对常见的关键性的类名、方法名、关键字读准,有些面试官不耐烦会说“你到底说的是哪个?”这时我们会容易乱了阵脚。正确的发音+沉稳的描述+好听的嗓音决对是一个加分项!

最重要的是心态!心态!心态!重要事情说三遍!面试时间很短,在短时间内对方要摸清你的底子还是比较不现实的,所以,有时也是看眼缘,这还是个看脸的时代。

希望大家都能找到合适自己满意的工作!

进阶学习视频

附上:我们之前因为秋招收集的二十套一二线互联网公司Android面试真题 (含BAT、小米、华为、美团、滴滴)和我自己整理Android复习笔记(包含Android基础知识点、Android扩展知识点、Android源码解析、设计模式汇总、Gradle知识点、常见算法题汇总。)

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
img

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
[外链图片转存中…(img-30113XyW-1712614628952)]
[外链图片转存中…(img-GvSsiuLY-1712614628953)]
[外链图片转存中…(img-5Lkt5obJ-1712614628954)]
[外链图片转存中…(img-iBVmLokp-1712614628954)]
[外链图片转存中…(img-ng9hvaOm-1712614628954)]
[外链图片转存中…(img-mXBOdMnI-1712614628955)]
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
[外链图片转存中…(img-9FZiDAer-1712614628955)]

最后

简历首选内推方式,速度快,效率高啊!然后可以在拉钩,boss,脉脉,大街上看看。简历上写道熟悉什么技术就一定要去熟悉它,不然被问到不会很尴尬!做过什么项目,即使项目体量不大,但也一定要熟悉实现原理!不是你负责的部分,也可以看看同事是怎么实现的,换你来做你会怎么做?做过什么,会什么是广度问题,取决于项目内容。但做过什么,达到怎样一个境界,这是深度问题,和个人学习能力和解决问题的态度有关了。大公司看深度,小公司看广度。大公司面试你会的,小公司面试他们用到的你会不会,也就是岗位匹配度。

面试过程一定要有礼貌!即使你觉得面试官不尊重你,经常打断你的讲解,或者你觉得他不如你,问的问题缺乏专业水平,你也一定要尊重他,谁叫现在是他选择你,等你拿到offer后就是你选择他了。

另外,描述问题一定要慢!不要一下子讲一大堆,慢显得你沉稳、自信,而且你还有时间反应思路接下来怎么讲更好。现在开发过多依赖ide,所以会有个弊端,当我们在面试讲解很容易不知道某个方法怎么读,这是一个硬伤…所以一定要对常见的关键性的类名、方法名、关键字读准,有些面试官不耐烦会说“你到底说的是哪个?”这时我们会容易乱了阵脚。正确的发音+沉稳的描述+好听的嗓音决对是一个加分项!

最重要的是心态!心态!心态!重要事情说三遍!面试时间很短,在短时间内对方要摸清你的底子还是比较不现实的,所以,有时也是看眼缘,这还是个看脸的时代。

希望大家都能找到合适自己满意的工作!

进阶学习视频

[外链图片转存中…(img-ArMo4AiL-1712614628955)]

附上:我们之前因为秋招收集的二十套一二线互联网公司Android面试真题 (含BAT、小米、华为、美团、滴滴)和我自己整理Android复习笔记(包含Android基础知识点、Android扩展知识点、Android源码解析、设计模式汇总、Gradle知识点、常见算法题汇总。)

[外链图片转存中…(img-cgtAqKWB-1712614628956)]

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
[外链图片转存中…(img-JPhCQnvW-1712614628956)]

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
框架内部支持中/英文(其他语言只需要在对应的string.xml中取相同的名字即可)内部对话框背景图片、按钮支持自定义了查看版本中的Log只需要过滤AppUpdate开头的Tag重点: 如果没有设置downloadPath则默认为getExternalCacheDir()目录,同时不会申请[存储]权限!目录编译问题效果图功能介绍DownloadManagerUpdateConfiguration使用步骤Demo下载体验版本更新记录结语编译问题因为适配了Android O的通知栏,所以依赖的v7包版本比较高appcompat-v7:26.1.0使用的gradle版本为gradle-4.1-all,所以建议使用Android Studio 3.0及以上的版本打开此项目效果图     功能介绍 支持断点下载 支持后台下载 支持自定义下载过程 支持 设备 >= Android M 动态权限的申请 支持通知栏进度条展示(或者自定义显示进度) 支持Android N 支持Android O 支持中/英文双语 支持自定内置对话框的样式 使用HttpURLConnection下载,未集成其他第三方框架更加详细的文档参阅此处《AppUpdate API文档》DownloadManager:配置文档初始化使用DownloadManager.getInstance(this)属性描述默认值是否必须设置context上下文nulltrueapkUrlapk的下载地址nulltrueapkNameapk下载好的名字nulltruedownloadPathapk下载的位置getExternalCacheDir()falseshowNewerToast是否提示用户 "当前已是最新版本"falsefalsesmallIcon通知栏的图标(资源id)-1trueconfiguration这个库的额外配置nullfalseapkVersionCode更新apk的versionCode (如果设置了那么库中将会进行版本判断下面的属性也就需要设置了)1falseapkVersionName更新apk的versionNamenullfalseapkDescription更新描述nullfalseapkSize新版本的安装包大小(单位M)nullfalseauthorities兼容Android N uri授权应用包名falseUpdateConfiguration:配置文档属性描述默认值notifyId通知栏消息id1011notificationChannel适配Android O的渠道通知详情查阅源码httpManager设置自己的下载过程nullbreakpointDownload是否需要支持断点下载trueenableLog是否需要日志输出trueonDownloadListener下载过程的回调nulljumpInstallPage下载完成是否自动弹出安装页面trueshowNotification是否显示通知栏进度(后台下载提示)trueforcedUpgrade是否强制升级falseonButtonClickListener按钮点击事件回调nulldialogImage对话框背景图片资源(图片规范参考demo)-1dialogButtonColor对话框按钮的颜色-1dialogButtonTextColor对话框按钮的文字颜色-1所有版本:点击查看使用步骤第一步: app/build.gradle进行依赖implementation 'com.azhon:appupdate:1.7.3'第二步:创建DownloadManager,更多用法请查看这里示例代码DownloadManager manager = DownloadManager.getInstance(this); manager.setApkName("appupdate.apk")         .setApkUrl("https://raw.githubusercontent.com/azhon/AppUpdate/master/apk/appupdate.apk")         .setSmallIcon(R.mipmap.ic_launcher)         //可设置,可不设置         .setConfiguration(configuration)         .download();第三步:兼容Android N 及以上版本,在你应用的Manifest.xml添加如下代码<--! android:authorities="${applicationId}"  这个值必须与DownloadManager中的authorities一致(不设置则为应用包名)--> <provider     android:name="android.support.v4.content.FileProvider"     android:authorities="${applicationId}"     android:exported="false"     android:grantUriPermissions="true">     <meta-data         android:name="android.support.FILE_PROVIDER_PATHS"         android:resource="@xml/file_paths_public" /> </provider>第四步:资源文件res/xml/file_paths_public.xml内容<?xml version="1.0" encoding="utf-8"?> <paths>     <external-path         name="app_update_external"         path="/" />     <external-cache-path         name="app_update_cache"         path="/" /> </paths>兼容Android O及以上版本,需要设置NotificationChannel(通知渠道);库中已经写好可以前往查阅NotificationUtil.java温馨提示:升级对话框中的内容是可以上下滑动的哦!如果需要实现自己一套下载过程,只需要继承BaseHttpDownloadManager 并使用listener更新进度public class MyDownload extends BaseHttpDownloadManager {}

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值