Android學習系列(2)–App自動更新之通知欄下載

來源:互聯網
上載者:User

見證過部落格園的多次升級,你也希望你的軟體通過更新發布新特性通知使用者吧,是的。
這篇文章是android開發人員的必備知識,是我特別為大家整理和總結的,不求完美,但是有用。 

1.設計思路,使用VersionCode定義為版本升級參數。
  android為我們定義版本提供了2個屬性:

<manifest package="com.cnblogs.tianxia.subway"      android:versionCode="1" <!--Integer類型,系統不顯示給使用者-->      android:versionName="1.0"<!--String類型,系統顯示使用者-->></manifest>

     Google建議我們使用versionCode自增來表明版本升級,無論是大的改動還是小的改動,而versionName是顯示使用者看的軟體版本,作為顯示使用。所以我們選擇了VersionCode作為我們定義版本升級的參數。

2.工程目錄
  為了對真實項目或者企業運用有實戰指導作用,我類比一個獨立的項目,工程目錄設定的合理嚴謹一些,而不是僅僅一個demo。
  假設我們以上海地鐵為項目,命名為"Subway",工程結構如下,
      

3.版本初始化和版本號碼的對比。
  首先定義在通用檔案Global.java中定義變數localVersion和serverVersion分別存放本地版本號碼和伺服器版本號碼。

public class Global {    //版本資訊    public static int localVersion = 0;    public static int serverVersion = 0;    public static String downloadDir = "app/download/";}

   因為本文只是重點說明升級更新,為了防止其他太多無關代碼冗餘其中,我直接在SubwayApplication中定義方法initGlobal()方法。

    /**     * 初始化全域變數     * 實際工作中這個方法中serverVersion從伺服器端擷取,最好在啟動畫面的activity中執行     */    public void initGlobal(){        try{            Global.localVersion = getPackageManager().getPackageInfo(getPackageName(),0).versionCode; //設定本地版本號碼            Global.serverVersion = 1;//假定伺服器版本為2,本地版本預設是1        }catch (Exception ex){            ex.printStackTrace();        }    }

      如果檢測到新版本發布,提示使用者是否更新,我在SubwayActivity中定義了checkVersion()方法:

    /**     * 檢查更新版本     */    public void checkVersion(){        if(Global.localVersion < Global.serverVersion){            //發現新版本,提示使用者更新            AlertDialog.Builder alert = new AlertDialog.Builder(this);            alert.setTitle("軟體升級")                 .setMessage("發現新版本,建議立即更新使用.")                 .setPositiveButton("更新", new DialogInterface.OnClickListener() {                     public void onClick(DialogInterface dialog, int which) {                         //開啟更新服務UpdateService                         //這裡為了把update更好模組化,可以傳一些updateService依賴的值                         //如布局ID,資源ID,動態擷取的標題,這裡以app_name為例                         Intent updateIntent =new Intent(SubwayActivity.this, UpdateService.class);                         updateIntent.putExtra("titleId",R.string.app_name);                         startService(updateIntent);                     }                 })                 .setNegativeButton("取消",new DialogInterface.OnClickListener(){                     public void onClick(DialogInterface dialog, int which) {                         dialog.dismiss();                     }                 });            alert.create().show();        }else{            //清理工作,略去            //cheanUpdateFile(),文章後面我會附上代碼        }    }

如:

  好,我們現在把這些東西串一下:
  第一步在SubwayApplication的onCreate()方法中執行initGlobal()初始化版本變數

    public void onCreate() {        super.onCreate();        initGlobal();    }

      第二步在SubwayActivity的onCreate()方法中檢測版本更新checkVersion()。

    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.main);        checkVersion();    }

  現在入口已經開啟,在checkVersion方法的第18行代碼中看出,當使用者點擊更新,我們開啟更新服務,從伺服器上下載最新版本。

4.使用Service在後台從伺服器端下載,完成後提示使用者下載完成,並關閉服務。
  定義一個服務UpdateService.java,首先定義與下載和通知相關的變數:

    //標題    private int titleId = 0;    //檔案儲存體    private File updateDir = null;      private File updateFile = null;    //通知欄    private NotificationManager updateNotificationManager = null;    private Notification updateNotification = null;    //通知欄跳轉Intent    private Intent updateIntent = null;    private PendingIntent updatePendingIntent = null;

在onStartCommand()方法中準備相關的下載工作:

    @Override    public int onStartCommand(Intent intent, int flags, int startId) {        //擷取傳值        titleId = intent.getIntExtra("titleId",0);        //建立檔案        if(android.os.Environment.MEDIA_MOUNTED.equals(android.os.Environment.getExternalStorageState())){            updateDir = new File(Environment.getExternalStorageDirectory(),Global.downloadDir);            updateFile = new File(updateDir.getPath(),getResources().getString(titleId)+".apk");        }        this.updateNotificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);        this.updateNotification = new Notification();        //設定下載過程中,點擊通知欄,回到主介面        updateIntent = new Intent(this, SubwayActivity.class);        updatePendingIntent = PendingIntent.getActivity(this,0,updateIntent,0);        //設定通知欄顯示內容        updateNotification.icon = R.drawable.arrow_down_float;        updateNotification.tickerText = "開始下載";        updateNotification.setLatestEventInfo(this,"上海地鐵","0%",updatePendingIntent);        //發出通知        updateNotificationManager.notify(0,updateNotification);        //開啟一個新的線程下載,如果使用Service同步下載,會導致ANR問題,Service本身也會阻塞        new Thread(new updateRunnable()).start();//這個是下載的重點,是下載的過程                return super.onStartCommand(intent, flags, startId);    }

上面都是準備工作,

  從代碼中可以看出來,updateRunnable類才是真正下載的類,出於使用者體驗的考慮,這個類是我們單獨一個線程後台去執行的。
  下載的過程有兩個工作:1.從伺服器上下載資料;2.通知使用者下載的進度。
  線程通知,我們先定義一個空的updateHandler。

    private Handler updateHandler = new  Handler(){        @Override        public void handleMessage(Message msg) {                    }    };

      再來建立updateRunnable類的真正實現:

class updateRunnable implements Runnable {        Message message = updateHandler.obtainMessage();        public void run() {            message.what = DOWNLOAD_COMPLETE;            try{                //增加許可權;                if(!updateDir.exists()){                    updateDir.mkdirs();                }                if(!updateFile.exists()){                    updateFile.createNewFile();                }                //下載函數,以QQ為例子                //增加許可權;                long downloadSize = downloadUpdateFile("http://softfile.3g.qq.com:8080/msoft/179/1105/10753/MobileQQ1.0(Android)_Build0198.apk",updateFile);                if(downloadSize>0){                    //下載成功                    updateHandler.sendMessage(message);                }            }catch(Exception ex){                ex.printStackTrace();                message.what = DOWNLOAD_FAIL;                //下載失敗                updateHandler.sendMessage(message);            }        }    }

下載函數的實現有很多,我這裡把代碼貼出來,而且我們要在下載的時候通知使用者下載進度:

public long downloadUpdateFile(String downloadUrl, File saveFile) throws Exception {            //這樣的下載代碼很多,我就不做過多的說明            int downloadCount = 0;            int currentSize = 0;            long totalSize = 0;            int updateTotalSize = 0;                        HttpURLConnection httpConnection = null;            InputStream is = null;            FileOutputStream fos = null;                        try {                URL url = new URL(downloadUrl);                httpConnection = (HttpURLConnection)url.openConnection();                httpConnection.setRequestProperty("User-Agent", "PacificHttpClient");                if(currentSize > 0) {                    httpConnection.setRequestProperty("RANGE", "bytes=" + currentSize + "-");                }                httpConnection.setConnectTimeout(10000);                httpConnection.setReadTimeout(20000);                updateTotalSize = httpConnection.getContentLength();                if (httpConnection.getResponseCode() == 404) {                    throw new Exception("fail!");                }                is = httpConnection.getInputStream();                                   fos = new FileOutputStream(saveFile, false);                byte buffer[] = new byte[4096];                int readsize = 0;                while((readsize = is.read(buffer)) > 0){                    fos.write(buffer, 0, readsize);                    totalSize += readsize;                    //為了防止頻繁的通知導致應用吃緊,百分比增加10才通知一次                    if((downloadCount == 0)||(int) (totalSize*100/updateTotalSize)-10>downloadCount){                         downloadCount += 10;                        updateNotification.setLatestEventInfo(UpdateService.this, "正在下載", (int)totalSize*100/updateTotalSize+"%", updatePendingIntent);                        updateNotificationManager.notify(0, updateNotification);                    }                                        }            } finally {                if(httpConnection != null) {                    httpConnection.disconnect();                }                if(is != null) {                    is.close();                }                if(fos != null) {                    fos.close();                }            }            return totalSize;        }

顯示下載進度,

下載完成後,我們提示使用者下載完成,並且可以點擊安裝,那麼我們來補全前面的Handler吧。
先在UpdateService.java定義2個常量來表示下載狀態:

    //下載狀態    private final static int DOWNLOAD_COMPLETE = 0;    private final static int DOWNLOAD_FAIL = 1;

根據下載狀態處理主線程:

    private Handler updateHandler = new  Handler(){        @Override        public void handleMessage(Message msg) {            switch(msg.what){                case DOWNLOAD_COMPLETE:                    //點擊安裝PendingIntent                    Uri uri = Uri.fromFile(updateFile);                    Intent installIntent = new Intent(Intent.ACTION_VIEW);                    installIntent.setDataAndType(uri, "application/vnd.android.package-archive");                    updatePendingIntent = PendingIntent.getActivity(UpdateService.this, 0, installIntent, 0);                                        updateNotification.defaults = Notification.DEFAULT_SOUND;//鈴聲提醒                     updateNotification.setLatestEventInfo(UpdateService.this, "上海地鐵", "下載完成,點擊安裝。", updatePendingIntent);                    updateNotificationManager.notify(0, updateNotification);                                        //停止服務                    stopSelf();                    break;                case DOWNLOAD_FAIL:                    //下載失敗                    updateNotification.setLatestEventInfo(UpdateService.this, "上海地鐵", "下載完成,點擊安裝。", updatePendingIntent);                    updateNotificationManager.notify(0, updateNotification);                    break;                default:                    stopSelf();            }        }    };

下載完成,

至此,檔案下載並且在通知欄通知進度。
發現本人廢話很多,其實幾句話的事情,來來回回寫了這麼多,囉嗦了,後面博文我會朝著精簡方面努力。
PS:前面說要附上cheanUpdateFile()的代碼

File updateFile = new File(Global.downloadDir,getResources().getString(R.string.app_name)+".apk");if(updateFile.exists()){   //當不需要的時候,清除之前的下載檔案,避免浪費使用者空間   updateFile.delete(); }

謝謝大家!!!!

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.