欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

 更新時(shí)間:2016年07月05日 17:41:54   投稿:lqh  
Android 開(kāi)發(fā)中對(duì)版本進(jìn)行檢查并更新的需求基本是所有應(yīng)用必須有的功能,可是在實(shí)際開(kāi)發(fā)中有些朋友就容易忽略一些細(xì)節(jié)。本文章提供解決方案,希望對(duì)大家有所幫助

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

版本更新的基本流程:

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

強(qiáng)制更新:

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

非強(qiáng)制更新

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

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

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

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

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

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

    解決方案

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

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

    解決方案

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

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

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

    對(duì)于3,4問(wèn)題,我倒是覺(jué)得不是程序問(wèn)題而是態(tài)度問(wèn)題,實(shí)際加入非wifi和進(jìn)度顯示的功能非常簡(jiǎn)單

    整體解決方案

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

核心代碼如下:

public class VersionUpdateService extends Service {
 private LocalBinder binder = new LocalBinder();

 private DownLoadListener downLoadListener;//下載任務(wù)監(jiān)聽(tīng)回調(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)聽(tīng)回調(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() {
  //獲取本定版本號(hào)
  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();
  //啟動(dòng)通知欄進(jìn)度更新線程
  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í)行進(jìn)度更新
    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("以后再說(shuō)", new DialogInterface.OnClickListener() {
   @Override
   public void onClick(DialogInterface dialog, int which) {
    ...
    //如果是強(qiáng)制更新 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控制更新紅點(diǎn)提示
    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 = ...//更新提示對(duì)話框
    builer.setPositiveButton("立即更新", new DialogInterface.OnClickListener() {
     @Override
     public void onClick(DialogInterface dialog, int which) {
      dialog.cancel();
      if (NetUtil.isWifi(context)) {
       service.doDownLoadTask();
      } else {
       showNotWifiDownloadDialog();
      }
     }
    });

    //當(dāng)點(diǎn)取消按鈕時(shí)進(jìn)行登錄
    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 = ...//生成進(jìn)度條對(duì)話框
    }
   }

   @Override
   public void inProgress(float progress, long total) {
    ...//更新進(jìn)度條
   }

   @Override
   public void downLoadLatestSuccess(File file) {
    ...//執(zhí)行成功處理
    unBindService();
   }

   @Override
   public void downLoadLatestFailed() {
    ...//執(zhí)行失敗處理
    unBindService();
   }
  });

  service.doCheckUpdateTask();
 }
 ...
}

最后,使用方式還是非常簡(jiǎn)單的。在BaseActivity中使用:

private VersionUpdateHelper versionUpdateHelper;
@Override
protected void onResume() {
 super.onResume();
 if(versionUpdateHelper == null)
  versionUpdateHelper = new VersionUpdateHelper(this);
 versionUpdateHelper.startUpdateVersion();
}

@Override
protected void onPause() {
 super.onPause();
 if(versionUpdateHelper != null)
  versionUpdateHelper.stopUpdateVersion();
}

保證在每進(jìn)入一個(gè)界面和離開(kāi)界面時(shí)都將檢查更新(bindService)和取消檢查(unBindService)。這時(shí)有些朋友可能認(rèn)為這樣做會(huì)不會(huì)浪費(fèi)資源呢?沒(méi)有!

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

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

SettingActivity.java

private VersionUpdateHelper versionUpdateHelper;

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

寫在最后

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

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

相關(guān)文章

  • Android Jetpack庫(kù)剖析之Lifecycle組件篇

    Android Jetpack庫(kù)剖析之Lifecycle組件篇

    本章也是帶來(lái)了Jetpack中我認(rèn)為最重要的架構(gòu)組件Lifecycle的原理探索,至于為什么覺(jué)得它是最重要是因?yàn)橄馰iewModel,LiveData這些組件也依賴于Lifecycle來(lái)感知宿主的生命周期,那么本章我們帶著幾個(gè)問(wèn)題來(lái)探索一下這個(gè)組件
    2022-07-07
  • Android使用GridView實(shí)現(xiàn)日歷的簡(jiǎn)單功能

    Android使用GridView實(shí)現(xiàn)日歷的簡(jiǎn)單功能

    這篇文章主要為大家詳細(xì)介紹了Android使用GridView實(shí)現(xiàn)日歷的簡(jiǎn)單功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-12-12
  • Android判斷是否為飛行模式簡(jiǎn)單方法

    Android判斷是否為飛行模式簡(jiǎn)單方法

    這篇文章主要介紹了Android判斷是否為飛行模式簡(jiǎn)單方法,本文使用最簡(jiǎn)單的方法實(shí)現(xiàn)判斷是否為飛行模式,需要的朋友可以參考下
    2015-04-04
  • Android與JS相互調(diào)用的方法

    Android與JS相互調(diào)用的方法

    這篇文章主要介紹了Android與JS相互通信的方法,幫助大家更好的理解和學(xué)習(xí)使用Android開(kāi)發(fā),感興趣的朋友可以了解下
    2021-04-04
  • 利用百度地圖Android sdk高仿微信發(fā)送位置功能及遇到的問(wèn)題

    利用百度地圖Android sdk高仿微信發(fā)送位置功能及遇到的問(wèn)題

    這篇文章給大家介紹了利用百度地圖Android sdk高仿微信發(fā)送位置功能,在實(shí)現(xiàn)此功能的時(shí)候遇到點(diǎn)小問(wèn)題,下面小編給大家列出來(lái),需要的朋友參考下吧
    2017-12-12
  • Android自定義View實(shí)現(xiàn)抽獎(jiǎng)轉(zhuǎn)盤

    Android自定義View實(shí)現(xiàn)抽獎(jiǎng)轉(zhuǎn)盤

    這篇文章主要為大家詳細(xì)介紹了Android自定義View實(shí)現(xiàn)抽獎(jiǎng)轉(zhuǎn)盤,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-12-12
  • Android ScrollView粘性頭部代碼分享

    Android ScrollView粘性頭部代碼分享

    本篇文章主要給大家分享了一個(gè)安卓的頭部效果ScrollView粘性頭部代碼分享,有興趣的朋友參考學(xué)習(xí)下。
    2018-01-01
  • Android實(shí)現(xiàn)左滑刪除控件

    Android實(shí)現(xiàn)左滑刪除控件

    這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)左滑刪除控件,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-09-09
  • Android 通過(guò)jni返回Mat數(shù)據(jù)類型方法

    Android 通過(guò)jni返回Mat數(shù)據(jù)類型方法

    今天小編就為大家分享一篇Android 通過(guò)jni返回Mat數(shù)據(jù)類型方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-08-08
  • Android數(shù)據(jù)流之Channel和Flow實(shí)現(xiàn)原理和技巧詳解

    Android數(shù)據(jù)流之Channel和Flow實(shí)現(xiàn)原理和技巧詳解

    在 Android 應(yīng)用程序的開(kāi)發(fā)中,處理異步數(shù)據(jù)流是一個(gè)常見(jiàn)的需求,為了更好地應(yīng)對(duì)這些需求,Kotlin 協(xié)程引入了 Channel 和 Flow,它們提供了強(qiáng)大的工具來(lái)處理數(shù)據(jù)流,本文將深入探討 Channel 和 Flow 的內(nèi)部實(shí)現(xiàn)原理、高級(jí)使用技巧以及如何在 Android 開(kāi)發(fā)中充分利用它們
    2023-11-11

最新評(píng)論