從網路中下載檔案儲存到SD卡和顯示下載進度
阿新 • • 發佈:2018-12-11
任務:
1.從網路中下載檔案儲存到SD卡
2.顯示下載進度
人醜話不多,直接擼程式碼。
xml佈局檔案:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="點選我開始下載" android:id="@+id/btn_download" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="下載進度:" android:layout_marginTop="40dp"/> <ProgressBar android:id="@+id/progressBar" style="?android:attr/progressBarStyleHorizontal" android:layout_width="match_parent" android:layout_height="wrap_content" android:progress="100" /> </LinearLayout>
java程式碼:
package com.example.jiaho.handleproject; import android.Manifest; import android.app.Activity; import android.content.pm.PackageManager; import android.os.Bundle; import android.os.Environment; import android.os.Handler; import android.os.Message; import android.support.annotation.Nullable; import android.support.v4.app.ActivityCompat; import android.support.v7.app.AppCompatActivity; import android.view.View; import android.widget.Button; import android.widget.ProgressBar; import android.widget.Toast; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.MalformedURLException; import java.net.URL; import java.net.URLConnection; public class DownLoadActivity extends AppCompatActivity { public static final int DOWNLOAD_MESSAGE_CODE = 10001; public static final int DOWNLOAD_MESSAGE_FAIL_CODE = 10002; public static final String AppURL = "http://192.168.31.138/mukewang.apk"; private Button btn_download; private ProgressBar progressBar; private Handler mHandler; private static final int REQUEST_EXTERNAL_STORAGE=1; private static String[] PERMISSIONS_STORAGE={ Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE }; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_download); btn_download=findViewById(R.id.btn_download); progressBar=findViewById(R.id.progressBar); /* * 主執行緒 * 1.點選按鍵 * 2.發起下載 * 3.開啟子執行緒做下載 * 4.下載過程中通知主執行緒 ------> 主執行緒更新進度條 * */ btn_download.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { //在子執行緒中執行download方法 new Thread(new Runnable() { @Override public void run() { download(AppURL); } }).start(); } }); //接收子執行緒的訊息 mHandler=new Handler(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); //處理訊息 switch (msg.what){ case DOWNLOAD_MESSAGE_CODE: progressBar.setProgress((int)msg.obj); break; case DOWNLOAD_MESSAGE_FAIL_CODE: Toast.makeText(DownLoadActivity.this,"下載失敗",Toast.LENGTH_SHORT).show(); } } }; } public void download(String appUrl){ try { //拿到Url URL url=new URL(appUrl); //開啟一個connect URLConnection urlConnection=url.openConnection(); //獲取輸入流 InputStream inputStream=urlConnection.getInputStream(); //獲取檔案的總長度 int contentLength=urlConnection.getContentLength(); //建立一個下載路徑 String downloadFolderName= Environment.getExternalStorageDirectory()+File.separator+"imooc"+File.separator; //建立一個檔案 File file=new File(downloadFolderName); if(!file.exists()){ //如果檔案不存在,就建立一個檔案 file.mkdir(); } //建立檔案 String fileName=downloadFolderName+"mkapp.apk"; File fileMove=new File(fileName); //如果檔案存在就把它刪掉,下次執行程式就不會報錯 if (fileMove.exists()){ fileMove.delete(); } //記錄下載的大小 int downloadSize=0; byte[] bytes=new byte[1024]; int length=0; //建立一個輸出流 //verifyStoragePermissions(DownLoadActivity.this); OutputStream outputStream=new FileOutputStream(fileName); while ((length=inputStream.read(bytes))!=-1){ outputStream.write(bytes,0,length); downloadSize+=length; /* * 每完成一點下載,就及時更新UI * */ Message message = Message.obtain(); //提取出一個靜態變數 message.what = DOWNLOAD_MESSAGE_CODE; message.obj=(downloadSize/contentLength)*100; //將訊息通過Handle發出去 mHandler.sendMessage(message); } }catch (MalformedURLException e){ //如果下載失敗了,也要傳送下載失敗的訊息 NotifyDownLoadFail(); e.printStackTrace(); }catch (IOException e){ e.printStackTrace(); NotifyDownLoadFail(); } } //提取出一個方法 private void NotifyDownLoadFail() { Message message=Message.obtain(); message.what= DOWNLOAD_MESSAGE_FAIL_CODE; mHandler.sendMessage(message); } //檢查許可權的方法,android6.0才需要在java程式碼中實現許可權賦予 public static void verifyStoragePermissions(Activity activity){ //Check if we have write permission int permission = ActivityCompat.checkSelfPermission(activity,Manifest.permission.WRITE_EXTERNAL_STORAGE); if (permission!= PackageManager.PERMISSION_GRANTED){ //沒有許可權,則通知使用者 ActivityCompat.requestPermissions(activity,PERMISSIONS_STORAGE,REQUEST_EXTERNAL_STORAGE); } } }
解釋一下程式碼段:
//檢查許可權的方法,android6.0才需要在java程式碼中實現許可權賦予 public static void verifyStoragePermissions(Activity activity){ //Check if we have write permission int permission = ActivityCompat.checkSelfPermission(activity,Manifest.permission.WRITE_EXTERNAL_STORAGE); if (permission!= PackageManager.PERMISSION_GRANTED){ //沒有許可權,則通知使用者 ActivityCompat.requestPermissions(activity,PERMISSIONS_STORAGE,REQUEST_EXTERNAL_STORAGE); } }
這個程式碼在android6.0上才被需要,因為當時寫程式碼時,老是提示許可權不夠,就在網上查各種資料,所以各種變態許可權都試了一遍,足足嘗試了2個多小時,發現還是不行。後來我就納悶了,我的android才4.4啊,根本不需要這些才對啊。於是我重新認真檢查程式碼,發現了一個隱藏至深的bug,真是痛心疾首,老夫捶胸頓足,差點一口老血噴了出來。原來是我寫檔案路徑的時候,將程式碼File.separator寫成了File.pathSeparator。
簡單講下File.separator和File.pathSeparator的區別:
File.pathSeparator指的是分隔連續多個路徑字串的分隔符,例如:
java -cp test.jar;hello.jar
就是指";"
File.separator才是用來分隔同一個路徑字串中的目錄,例如:
E:\Android\androidProject
就是指"\"