下載的流程:
文件下載的代碼:public class DownloadActivity extends AppCompatActivity { PRivate ProgressBar mProgressBar; //準備下載 public static final int BEGIN = 0; //正在下載 public static final int DOWNLOADING = 1; //結束下載 public static final int END = 2; //下載的進度 private static int progress; //是否停止下載 private boolean cancel ; OkHttpClient okHttpClient = new OkHttpClient(); MyHandler mHandler = new MyHandler(this); private ImageView mShowImage; ByteArrayOutputStream baos = new ByteArrayOutputStream(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_download); mProgressBar = (ProgressBar) findViewById(R.id.down_progress_bar); mShowImage = (ImageView) findViewById(R.id.down_image); } public void click2(View view) { cancel = true; } public void click(View view) { cancel = false; new Thread(new Runnable() { @Override public void run() { //實例化Builder對象 Request.Builder builder = new Request.Builder(); //設置Url builder.url(Config.IMAGE_URL); //獲取已經下載的大小 int size = baos.size(); //size表示已經下載的大小。如果不為0,則進行斷點續傳。 if (size > 0) { //設置斷點續傳的開始位置,格式bytes=123456- builder.header("Range", "bytes=" + size + "-"); //設置ProgressBar的當前進度從停止位置開始 progress = size; } //創建Request對象 Request request = builder.build(); try { //執行下載請求,并獲得Response對象 Response response = okHttpClient.newCall(request).execute(); //請求成功 if (response.isSuccessful()) { //從Response對象中獲取輸入流對象 InputStream inputStream = response.body().byteStream(); //size==0表示第一次下載,非斷點續傳 if (size == 0) { //獲取文件的大小 int contentLength = (int) response.body().contentLength(); //將文件總大小通過Handler傳遞到UI線程,設置ProgressBar的總進度值 mHandler.obtainMessage(BEGIN,contentLength,0).sendToTarget(); } int len = 0; byte[] buffer = new byte[1024]; //循環讀取文件流,開始下載 while((len = inputStream.read(buffer)) != -1) { if (cancel) { //如果點擊了停止按鈕,cancel為true。則結束循環 break; } //將流寫入緩存 baos.write(buffer,0,len); baos.flush(); //發送下載進度 mHandler.obtainMessage(DOWNLOADING,len,0).sendToTarget(); } //下載完成,結束請求,關閉body response.body().close(); //將字節轉成Bitmap對象 byte[] bytes = baos.toByteArray(); Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length); //下載完成通知更新試圖 mHandler.obtainMessage(END,bitmap).sendToTarget(); } } catch (IOException e) { e.printStackTrace(); } } }).start(); } static class MyHandler extends Handler { private WeakReference<DownloadActivity> activityWeakReference; public MyHandler(DownloadActivity activity) { this.activityWeakReference = new WeakReference<DownloadActivity>(activity); } @Override public void handleMessage(Message msg) { switch (msg.what) { case BEGIN: activityWeakReference.get().mProgressBar.setMax(msg.arg1); break; case DOWNLOADING: progress += msg.arg1; activityWeakReference.get().mProgressBar.setProgress(progress); break; case END: progress = 0; activityWeakReference.get().mShowImage.setImageBitmap((Bitmap)msg.obj); break; } } }}復制代碼以上是文件下的代碼。實現了斷點續傳,其中能進行斷點續傳的關鍵代碼為builder.header("Range", "bytes=" + size + "-");代碼中都有注釋,結合上面的流程圖應該不難理解。代碼解釋:源碼的效果是點擊開始按鈕出發click事件開始下載,點擊停止按鈕觸發click2事件中斷下載。下載的進度監聽是在while循環中,通過Handler進行的進度更新。文件上傳本案例中,實現帶參數的文件上傳功能-----同時完成參數傳遞和文件上傳。代碼如下:public class UploadActivity extends AppCompatActivity { public static final int GET_PIC = 1; private ImageView mShowImage; private Uri uri; OkHttpClient okHttpClient = new OkHttpClient(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_upload); mShowImage = (ImageView) findViewById(R.id.upload_show_image); } public void click(View view) { switch (view.getId()) { case R.id.upload_choose_file: choosePic();//選擇圖片 break; case R.id.upload_start: upload();//上傳 break; } } /** * 上傳 */ private void upload() { if (uri == null) { Toast.makeText(UploadActivity.this, "請先選擇文件", Toast.LENGTH_SHORT).show(); return; } //設置文件的媒體類型,image/*表示匹配所有的圖片文件 MediaType mediaType = MediaType.parse("image/*"); MultipartBody.Builder builder = new MultipartBody.Builder(); //文件上傳,此處是關鍵,設置媒體類型為multipart/form-data,表示多種格式的表單數據上傳 builder.setType(MultipartBody.FORM); //添加上傳的參數username=androidxx builder.addFormDataPart("username","androidxx"); //添加上傳的文件。文件是從相冊讀取的文件流。 try { //獲得需要上傳的文件流 InputStream inputStream = getContentResolver().openInputStream(uri); int len = 0; byte[] buffer = new byte[1024]; ByteArrayOutputStream baos = new ByteArrayOutputStream(); while((len = inputStream.read(buffer)) != -1) { baos.write(buffer, 0, len); } inputStream.close(); /* * 添加文件到Builder中。如果要實現多文件同時上傳,可以添加多個addFormDataPart。 * 注意: * 參數一:上傳的文件的標示,同username。也就是可以在服務器端通過upload找到對應的文件流 * 參數二:文件的名稱。上傳到服務器之后以此名稱命名文件 * 參數三:需要上傳的文件。包含在RequestBody中 * RequestBody.create方法有多個重載的方法,可以選擇不同的數據源。此處選擇的是字節形式(baos.toByteArray())的數據眼。 */builder.addFormDataPart("upload", "test.jpg", RequestBody.create(mediaType, baos.toByteArray())); } catch (IOException e) { e.printStackTrace(); } //創建MultipartBody對象,MultipartBody是RequestBody的子類,用于文件上傳。 MultipartBody multipartBody = builder.build(); Request request = new Request.Builder() .url("http://192.168.3.4:8080/WebServer/upload.do")//上傳的服務器地址 .post(multipartBody) .build(); //開始上傳。采用Post異步請求的方式 okHttpClient.newCall(request).enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { Log.d("androidxx.cn","--" + e.getMessage()); e.printStackTrace(); } @Override public void onResponse(Call call, Response response) throws IOException { //接受到成功的返回結果 if (response.isSuccessful()) { Log.d("androidxx.cn","-上傳成功-"); } else { Log.d("androidxx.cn","-失敗--" + response.body().string()); } } }); } /** * 打開相冊,選擇文件后返回 */ private void choosePic() { Intent intent = new Intent(Intent.ACTION_GET_CONTENT); intent.setType("image/*"); startActivityForResult(intent,GET_PIC); } /** * 接收選擇的圖片 * @param requestCode * @param resultCode * @param data */ @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (resultCode == RESULT_CANCELED) { return; } //獲得圖片的URI uri = data.getData(); //通過ContentResolver獲得圖片對象 ContentResolver contentResolver = getContentResolver(); InputStream inputStream = null; try { inputStream = contentResolver.openInputStream(uri); } catch (FileNotFoundException e) { e.printStackTrace(); } //將流轉換成圖片,顯示到ImageView中 Bitmap bitmap = BitmapFactory.decodeStream(inputStream); mShowImage.setImageBitmap(bitmap); }}復制代碼如上代碼,第37行和第59行是上傳能成功的重點。多文件長傳實現多文件上傳,只需將上面單文件上傳中的builder.addFormDataPart("upload", "test.jpg", RequestBody.create(mediaType, baos.toByteArray()));這一句執行多次,即使用多個addFormDataPart方法添加多個文件,然后就可以同時上傳多個文件了。總結1、文件上傳和下載的過程其實就是一種特殊的Post和Get請求。總體的過程與Post請求和Get請求方式一樣。2、下載相當于一個特殊的Get請求,只是服務器返回的數據格式是文件流。我們也只能通過讀取流來獲得數據。3、上傳相當于一個特殊的Post請求,前面我們說過,Post請求就是傳參數比較特殊和多樣化。文件上傳就是一種特殊的參數傳遞----參數是一個文件。大家在看如上代碼的時候,不要覺得陌生,其實代碼的流程和邏輯同Post和Get請求一樣,只是多了幾行代碼。本案例的android端源碼:Github本案例的上傳服務器配置方式【點擊查看】,上傳服務端源碼:Github 服務器端代碼請閱讀Github中的readme.md文件。服務器端代碼導入工程沒有錯之后,可以將代碼加載到服務器,之后啟動服務器就可以運行。本案例使用的是Tomcat服務器。備注:對于android程序員如果想運行服務器代碼,按照readme.md文檔。然后有不懂的,可以留言。轉載請注明:androidxx.cn最后附上下載效果(注意點擊按鈕開始和停止后下載進度條的變化,實現斷點續傳)。
新聞熱點
疑難解答