国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統(tǒng) > Android > 正文

安卓(Android)應(yīng)用版本更新方法

2019-12-12 06:06:17
字體:
供稿:網(wǎng)友

開發(fā)中對版本進行檢查并更新的需求基本是所有應(yīng)用必須有的功能,可是在實際開發(fā)中有些朋友就容易忽略一些細節(jié)。

版本更新的基本流程:

一般是將本地版本告訴服務(wù)器,服務(wù)器經(jīng)過相關(guān)處理會返回客戶端相關(guān)信息,告訴客戶端需不需要更新,如果需要更新是強制更新還是非強制更新。客戶端得到服務(wù)器返回的相關(guān)信息后再進一步做邏輯處理。

強制更新:

一般的處理就是進入應(yīng)用就彈窗通知用戶有版本更新,彈窗可以沒有取消按鈕并不能取消。這樣用戶就只能選擇更新或者關(guān)閉應(yīng)用了,當然也可以添加取消按鈕,但是如果用戶選擇取消則直接退出應(yīng)用。

非強制更新

一般的處理是在應(yīng)用的設(shè)置中添加版本檢查的操作,如果用戶主動檢查版本則彈窗告知用戶有版本更新。這時用戶可以取消或者更新。

功能實際是比較簡單清晰的,但之所以寫這篇文章,是因為在我們公司的一個項目中,我把這個模塊分給了一個有著4年工作經(jīng)驗的哥們編寫,最后這哥們花了2個小時做完了。我還想這哥們寫得挺快,效率很高嘛,結(jié)果一測試發(fā)現(xiàn)問題不少:

   1. 進入首頁前關(guān)閉網(wǎng)絡(luò),進入后刷新界面發(fā)現(xiàn)強制更新提醒沒有彈窗
  2.  再進入其它界面也沒有任何更新提醒
 3.   在正常更新時點擊確定更新,沒有判斷網(wǎng)絡(luò)狀態(tài)(wifi,移動網(wǎng)絡(luò))直接下載apk文件,如果用戶在移動網(wǎng)絡(luò)下將耗費非常多的流量,直接影響用戶體驗
  4.  下載過程在應(yīng)用內(nèi)沒有進度條提醒,通知欄也沒有進度提醒
  5.  apk文件下載過程中,如果強制結(jié)束應(yīng)用,下載被中斷
  6.  apk如果正常下載下來,彈出了安裝界面,這時如果用戶取消了安裝回到應(yīng)用,在需要強制更新的情況下并沒有再次彈窗阻止用戶進行任何其它操作,失去了強制更新的意義

首先聲明下,我這絲毫沒有吐槽的意思喲,只是想說作為一個合格的程序員大家最起碼需要做到思維嚴謹這點,在有能力的情況下對用戶體驗?zāi)芴狳c建議最好。自己寫的代碼一定要經(jīng)過嚴格測試再交付,不要指望測試人員幫你測試再去修改,你要知道現(xiàn)在很多公司是沒有專業(yè)的測試人員甚至是沒有測試人員的喲。

針對以上問題出現(xiàn)的原因分析及解決方案如下:

    對于1,2問題
    很明顯他把檢查更新的工作只寫在了應(yīng)用的首頁(比如MainActivity)中了,在其它任何界面并沒有檢查更新的操作

    解決方案

    每個界面都需要檢查更新,當然咱們不能在每個Activity中都復(fù)制粘貼一樣的代碼。這時定義一個BaseActivity,所有其它Activity都從它繼承就顯得很有價值了。可以把檢查更新的操作放到BaseActivity的相關(guān)方法中,比如放在onResume中,這樣每當顯示一個界面時都將執(zhí)行檢查更新的操作

    對于5問題,如果把下載的操作放在了Activity中進行,如果應(yīng)用意外終止或者強制退出應(yīng)用,則下載線程也將被終止

    解決方案

可以將下載任務(wù)放到Service中執(zhí)行,這樣即使應(yīng)用被終止Service一樣有保活機制(startForeground)讓Service的任務(wù)有很大的機會繼續(xù)得以執(zhí)行

  對于6問題,如果檢查更新的操作沒有在Activity的resume時再次執(zhí)行,則回到Activity自然也就沒有檢查更新并彈窗了

    解決方案
在Activity的onResume中繼續(xù)檢查更新,如果是強制更新則彈窗阻止用戶進行其它操作

    對于3,4問題,我倒是覺得不是程序問題而是態(tài)度問題,實際加入非wifi和進度顯示的功能非常簡單

    整體解決方案

    定義Service類,比如VersionUpdateService.java。主要提供版本檢查及文件下載操作
    定義VersionUpdateHelper類,用來使用Service并提供和前臺Activity的交互
    如果大家對Service的使用還有問題(需要頻繁更新前臺ui等),建議大家閱讀android圖片壓縮上傳系列-service篇這篇文章先做了解。

核心代碼如下:

public class VersionUpdateService extends Service { private LocalBinder binder = new LocalBinder(); private DownLoadListener downLoadListener;//下載任務(wù)監(jiān)聽回調(diào)接口 private boolean downLoading; private int progress; private NotificationManager mNotificationManager; private NotificationUpdaterThread notificationUpdaterThread; private Notification.Builder notificationBuilder; private final int NOTIFICATION_ID = 100; private VersionUpdateModel versionUpdateModel; private CheckVersionCallBack checkVersionCallBack;//檢查結(jié)果監(jiān)聽回調(diào)接口 public interface DownLoadListener {  void begain();  void inProgress(float progress, long total);  void downLoadLatestSuccess(File file);  void downLoadLatestFailed(); } public interface CheckVersionCallBack {  void onSuccess();  void onError(); } ... private class NotificationUpdaterThread extends Thread {  @Override  public void run() {   while (true) {    notificationBuilder.setContentTitle("正在下載更新" + progress + "%"); // the label of the entry    notificationBuilder.setProgress(100, progress, false);    ...   }  } } private void starDownLoadForground() {  //創(chuàng)建通知欄  notificationBuilder = new Notification.Builder(this);  ...  Notification notification = notificationBuilder.getNotification();  startForeground(NOTIFICATION_ID, notification); } private void stopDownLoadForground() {  stopForeground(true); } //執(zhí)行版本檢查任務(wù) public void doCheckUpdateTask() {  //獲取本定版本號  final int currentBuild = AppUtil.getVersionCode(this);  //調(diào)用版本檢查接口  ApiManager.getInstance().versionApi.upgradeRecords(currentBuild, new RequestCallBack() {   @Override   public void onSuccess(Headers headers, String response) {     versionUpdateModel = JSON.parseObject(response, VersionUpdateModel.class);     ...     if (checkVersionCallBack != null)      checkVersionCallBack.onSuccess();   }   @Override   public void onError(int code, String response) {    ...   }  }); } public void doDownLoadTask() {  starDownLoadForground();  //啟動通知欄進度更新線程  notificationUpdaterThread = new NotificationUpdaterThread();  notificationUpdaterThread.start();  //文件下載存放路徑  final File fileDir = FolderUtil.getDownloadCacheFolder();  ...  downLoading = true;  if (downLoadListener != null) {   downLoadListener.begain();  }  NetManager.getInstance().download(url, fileDir.getAbsolutePath(), new DownloadCallBack() {   @Override   public void inProgress(float progress_, long total) {    ...    //執(zhí)行進度更新    if (downLoadListener != null)      downLoadListener.inProgress(progress_, total);    }   @Override   public void onSuccess(Headers headers, String response) {    //執(zhí)行成功回調(diào)    ...    installApk(destFile, VersionUpdateService.this);   }   @Override   public void onError(int code, String response) {    ...    //執(zhí)行失敗回調(diào)   }  }); } //安裝apk public void installApk(File file, Context context) {  ... }}
public class VersionUpdateHelper implements ServiceConnection { private Context context; private VersionUpdateService service; private AlertDialog waitForUpdateDialog; private ProgressDialog progressDialog; private static boolean isCanceled; private boolean showDialogOnStart; public static final int NEED_UPDATE = 2; public static final int DONOT_NEED_UPDATE = 1; public static final int CHECK_FAILD = -1; public static final int USER_CANCELED = 0; private CheckCallBack checkCallBack; public interface CheckCallBack{  void callBack(int code); } public VersionUpdateHelper(Context context) {  this.context = context; } public void startUpdateVersion() {  if (isCanceled)   return;  if (isWaitForUpdate() || isWaitForDownload()) {   return;  }  if (service == null && context != null) {   context.bindService(new Intent(context, VersionUpdateService.class), this, Context.BIND_AUTO_CREATE);  } } public void stopUpdateVersion() {  unBindService(); } private void cancel() {  isCanceled = true;  unBindService(); } private void unBindService() {  if (isWaitForUpdate() || isWaitForDownload()) {   return;  }  if (service != null && !service.isDownLoading()) {   context.unbindService(this);   service = null;  } } ... private void showNotWifiDownloadDialog() {  final AlertDialog.Builder builer = new AlertDialog.Builder(context);  builer.setTitle("下載新版本");  builer.setMessage("檢查到您的網(wǎng)絡(luò)處于非wifi狀態(tài),下載新版本將消耗一定的流量,是否繼續(xù)下載?");  builer.setNegativeButton("以后再說", new DialogInterface.OnClickListener() {   @Override   public void onClick(DialogInterface dialog, int which) {    ...    //如果是強制更新 exit app    if (mustUpdate) {     MainApplication.getInstance().exitApp();    }   }  });  builer.setPositiveButton("繼續(xù)下載", new DialogInterface.OnClickListener() {   @Override   public void onClick(DialogInterface dialog, int which) {    dialog.cancel();    service.doDownLoadTask();   }  });  ... } @Override public void onServiceConnected(ComponentName name, IBinder binder) {  service = ((VersionUpdateService.LocalBinder) binder).getService();  service.setCheckVersionCallBack(new VersionUpdateService.CheckVersionCallBack() {   @Override   public void onSuccess() {    VersionUpdateModel versionUpdateModel = service.getVersionUpdateModel();    //EventBus控制更新紅點提示    EventBus.getDefault().postSticky(versionUpdateEvent);    if (!versionUpdateModel.isNeedUpgrade()) {     if(checkCallBack != null){      checkCallBack.callBack(DONOT_NEED_UPDATE);     }     cancel();     return;    }    if (!versionUpdateModel.isMustUpgrade() && !showDialogOnStart) {     cancel();     return;    }    if(checkCallBack != null){     checkCallBack.callBack(NEED_UPDATE);    }    final AlertDialog.Builder builer = ...//更新提示對話框    builer.setPositiveButton("立即更新", new DialogInterface.OnClickListener() {     @Override     public void onClick(DialogInterface dialog, int which) {      dialog.cancel();      if (NetUtil.isWifi(context)) {       service.doDownLoadTask();      } else {       showNotWifiDownloadDialog();      }     }    });    //當點取消按鈕時進行登錄    if (!versionUpdateModel.isMustUpgrade()) {     builer.setNegativeButton("稍后更新", new DialogInterface.OnClickListener() {      public void onClick(DialogInterface dialog, int which) {       dialog.cancel();       cancel();       if(checkCallBack != null){        checkCallBack.callBack(USER_CANCELED);       }      }     });    }    builer.setCancelable(false);    waitForUpdateDialog = builer.create();    waitForUpdateDialog.show();   }   @Override   public void onError() {    unBindService();    ...   }  });  service.setDownLoadListener(new VersionUpdateService.DownLoadListener() {   @Override   public void begain() {    VersionUpdateModel versionUpdateModel = service.getVersionUpdateModel();    if (versionUpdateModel.isMustUpgrade()) {     progressDialog = ...//生成進度條對話框    }   }   @Override   public void inProgress(float progress, long total) {    ...//更新進度條   }   @Override   public void downLoadLatestSuccess(File file) {    ...//執(zhí)行成功處理    unBindService();   }   @Override   public void downLoadLatestFailed() {    ...//執(zhí)行失敗處理    unBindService();   }  });  service.doCheckUpdateTask(); } ...}

最后,使用方式還是非常簡單的。在BaseActivity中使用:

private VersionUpdateHelper versionUpdateHelper;@Overrideprotected void onResume() { super.onResume(); if(versionUpdateHelper == null)  versionUpdateHelper = new VersionUpdateHelper(this); versionUpdateHelper.startUpdateVersion();}@Overrideprotected void onPause() { super.onPause(); if(versionUpdateHelper != null)  versionUpdateHelper.stopUpdateVersion();}

保證在每進入一個界面和離開界面時都將檢查更新(bindService)和取消檢查(unBindService)。這時有些朋友可能認為這樣做會不會浪費資源呢?沒有!

1,如果應(yīng)用是強制更新,那么在網(wǎng)絡(luò)正常情況下進入應(yīng)用就能檢查出有新版本,這時彈窗后用戶不能進入任何操作,沒有機會進入別的界面,所有沒有進行重復(fù)檢查;如果進入應(yīng)用主頁由于網(wǎng)絡(luò)問題,檢查失敗,這時雖然不會彈窗提示更新,但是如果用戶的網(wǎng)絡(luò)恢復(fù)后進入任何其它界面都將得到正常的版本更新檢查并彈窗提示

2,如果應(yīng)用是非強制更新時,在Helper代碼里進行了如下的判斷:

SettingActivity.javaprivate VersionUpdateHelper versionUpdateHelper;@OnClick(R.id.rl_version_update)public void onClickVersionUpdate(View view) { if(updateTips.getVisibility() == View.VISIBLE){  return; } VersionUpdateHelper.resetCancelFlag();//重置cancel標記 if (versionUpdateHelper == null) {  versionUpdateHelper = new VersionUpdateHelper(this);  versionUpdateHelper.setShowDialogOnStart(true);  versionUpdateHelper.setCheckCallBack(new VersionUpdateHelper.CheckCallBack() {   @Override   public void callBack(int code) {    //EventBus發(fā)送消息通知紅點消失    VersionUpdateEvent versionUpdateEvent = new VersionUpdateEvent();    versionUpdateEvent.setShowTips(false);    EventBus.getDefault().postSticky(versionUpdateEvent);   }  }); } versionUpdateHelper.startUpdateVersion();}

寫在最后

由于代碼較多,且多數(shù)代碼和ui相關(guān),所以在文章中很多ui相關(guān)或者getter和setter方法等非核心代碼并沒有列出。演示代碼中用了EventBus和OkHttp開源控件,具體使用方法望大家自己找相關(guān)資料學(xué)習(xí)。本人打算有空的時候?qū)憘€EventBus系列文章,望大家多多關(guān)注。

文件下載也是使用的okHttp實現(xiàn)的,大家可以換成任何你熟悉的下載框架。VersionUpdateService.java和VersionUpdateHelper.java的完整代碼可以到我的github上下載,由于時間關(guān)系并沒有相關(guān)用法的完整案例還望見諒,等有時間一定奉上。

發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 吉隆县| 固阳县| 镇康县| 西宁市| 电白县| 忻州市| 甘南县| 曲靖市| 塔河县| 海淀区| 阜新| 新泰市| 阿鲁科尔沁旗| 大理市| 砚山县| 民丰县| 友谊县| 阳朔县| 察隅县| 安西县| 阿克| 肇州县| 定边县| 吴川市| 闸北区| 铁岭县| 鄂尔多斯市| 石狮市| 西藏| 濮阳市| 彩票| 长乐市| 钦州市| 密山市| 新乐市| 江源县| 玉山县| 伽师县| 公主岭市| 拜泉县| 普兰店市|