Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android學習筆記039之文件上傳和下載

Android學習筆記039之文件上傳和下載

編輯:關於Android編程

文件上傳和下載在我們開發中經常需要用到,現在也有很多的網絡框架封裝了文件上傳和下載功能。不過這一篇,我們介紹一下Android系統提供的文件下載服務–DownLoadManager。在API 9之後,Android提供了Download Manager來優化和處理長時間的下載操作,在大多數情況需要用到下載文件的情況下,使用Download Manager都是一個不錯的選擇,並且Download Manager對於斷點續傳功能的支持很好。下面我們詳細介紹一下DownLoadManager

DownLoadManager

DownLoadManager在官方文檔是這樣描述的:

The download manager is a system service that handles long-running HTTP downloads. Clients may request that a URI be downloaded to a particular destination file. The download manager will conduct the download in the background, taking care of HTTP interactions and retrying downloads after failures or across connectivity changes and system reboots. Instances of this class should be obtained through getSystemService(String) by passing DOWNLOAD_SERVICE. Apps that request downloads through this API should register a broadcast receiver for ACTION_NOTIFICATION_CLICKED to appropriately handle when the user clicks on a running download in a notification or from the downloads UI. Note that the application must have the INTERNET permission to use this class.

DownLoadManager是一個系統服務,用於處理長時間下載任務,DownLoadManager會在後台處理HTTP交互和重試下載失敗或跨連接啟動系統,通過getSystemService傳入DOWNLOAD_SERVICE可以獲得DownLoadManager的實例,可以通過注冊廣播接受者接收ACTION_NOTIFICATION_CLICKED來處理用戶點擊下載通知。使用這個下載服務需要聯網的權限,所以需要在清單文件中添加如下代碼:


上面是官方的介紹,DownLoadManager中有兩個內部類:DownloadManager.Query和DownloadManager.Request。前者用於查詢下載,後者用於設置一些請求信息。下面我們詳細介紹一下這兩個內部類:

DownloadManager.Request類的常用方法:

addRequestHeader(String header, String value):添加一個請求頭

setAllowedNetworkTypes(int flags):設置下載時所使用的網絡類型,提供的常量有:NETWORK_BLUETOOTH、NETWORK_MOBILE、NETWORK_WIFI。

setAllowedOverRoaming(boolean allowed):是否允許漫游

setDescription(CharSequence description):設置下載的描述信息

setDestinationInExternalFilesDir(Context context, String dirType, String subPath):設置下載文件外部存儲目錄

setDestinationUri(Uri uri):設置下載目標的URI

setMimeType(String mimeType):設置MIME類型

setShowRunningNotification(boolean show):設置是否顯示下載進度提示

setTitle(CharSequence title):設置下載時Notification的標題

setVisibleInDownloadsUi(boolean isVisible):設置是否現在下載界面

以上的各個方法,如果不設置的話就是默認的。

DownloadManager.Query類

  DownloadManager.Query類只有兩個方法:setFilterById(long… ids)根據任務Id查找和setFilterByStatus(int flags) 根據任務狀態查找。但是定義了很多常量:

下載狀態常量:

int STATUS_FAILED 失敗

int STATUS_PAUSED 暫停

int STATUS_PENDING 等待將開始

int STATUS_RUNNING 正在處理中

int STATUS_SUCCESSFUL 已經下載成功

DownloadManager.Query類查詢返回的是一個Cursor游標,上面描述的狀態就會保存在COLUMN_STATUS 字段中。下載狀態會以廣播的形式通知,Android系統定義的Action有:

ACTION_DOWNLOAD_COMPLETE下載完成的動作。

ACTION_NOTIFICATION_CLICKED 當用戶單擊notification中下載管理的某項時觸發。

ACTION_VIEW_DOWNLOADS 查看下載項

對於未完成的狀態,我們查找COLUMN_REASON字段,定義的常量有:

int ERROR_CANNOT_RESUME 不能夠繼續,由於一些其他原因。

int ERROR_DEVICE_NOT_FOUND 外部存儲設備沒有找到,比如SD卡沒有插入。

int ERROR_FILE_ALREADY_EXISTS 要下載的文件已經存在了,要想重新下載需要刪除原來的文件

int ERROR_FILE_ERROR 可能由於SD卡原因導致了文件錯誤。

int ERROR_HTTP_DATA_ERROR 在Http傳輸過程中出現了問題。

int ERROR_INSUFFICIENT_SPACE 由於SD卡空間不足造成的

int ERROR_TOO_MANY_REDIRECTS 這個Http有太多的重定向,導致無法正常下載

int ERROR_UNHANDLED_HTTP_CODE 無法獲取http出錯的原因,比如說遠程服務器沒有響應。

int ERROR_UNKNOWN 未知的錯誤類型.

有關暫停的一些狀態,同樣COLUMN_REASON字段的值定義常量有:

int PAUSED_QUEUED_FOR_WIFI 由於移動網絡數據問題,等待WiFi連接能用後再重新進入下載隊列

int PAUSED_UNKNOWN 未知原因導致了任務下載的暫停

int PAUSED_WAITING_FOR_NETWORK 可能由於沒有網絡連接而無法下載,等待有可用的網絡連接恢復

int PAUSED_WAITING_TO_RETRY 由於重重原因導致下載暫停,等待重試

這就是DownLoadManager的介紹,下面我們實現一個簡單的下載文件例子:

package com.example.filedemo;

import android.app.DownloadManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;

public class MainActivity extends AppCompatActivity {
String url = "http://www.86kl.com/modules/article/txtarticle.php?id=25530&fname=%C4%E6%CC%EC%D0%A1%C5%A9%C3%F1";
private Button btn_down;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    btn_down = (Button) findViewById(R.id.btn_down);


    btn_down.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
            request.setTitle("下載文件");
            //設置允許在什麼網絡下下載,默認是所有網絡,提供的常量有:NETWORK_BLUETOOTH、NETWORK_MOBILE、NETWORK_WIFI。
            request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI);
            //用於設置在下載的時候顯示通知信息,提供的常量有:VISIBILITY_HIDDEN、VISIBILITY_VISIBLE、VISIBILITY_VISIBLE_NOTIFY_COMPLETED、VISIBILITY_VISIBLE_NOTIFY_ONLY_COMPLETION
            request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE);
            //用於設置是否允許在漫游狀態下下載
            request.setAllowedOverRoaming(false);
            //設置描述信息
            request.setDescription("文件正在下載");
            //三個參數:第一個是上下文對象,第二個是文件存放路徑,第三個是文件名
            request.setDestinationInExternalFilesDir(MainActivity.this, Environment.DIRECTORY_DOWNLOADS, "MYDown");
            //獲取到系統的下載服務
            DownloadManager manager = (DownloadManager) MainActivity.this.getSystemService(DOWNLOAD_SERVICE);
            long id = manager.enqueue(request);
            System.out.println("bianhao shi :" + id);
        }
    });
}
}

調用的是系統的下載服務,不需要我們關心很多,如果是下載應用的話下載完成之後會跳出安裝頁面。最後,照例附上國內鏡像API

文件上傳

文件上傳,有很多框架可以實現,也可以通過HTTP協議和Socket協議實現,這裡就直接附上一些源碼:

基於HTTP的HttpUrlconnection實現:

private static final String BOUNDARY = "----WebKitFormBoundaryT1HoybnYeFOGFlBR";

/**
 * 
 * @param params
 *            傳遞的普通參數
 * @param uploadFile
 *            需要上傳的文件名
 * @param fileFormName
 *            需要上傳文件表單中的名字
 * @param newFileName
 *            上傳的文件名稱,不填寫將為uploadFile的名稱
 * @param urlStr
 *            上傳的服務器的路徑
 * @throws IOException
 */
public void uploadForm(Map params, String fileFormName,
        File uploadFile, String newFileName, String urlStr)
        throws IOException {
    if (newFileName == null || newFileName.trim().equals("")) {
        newFileName = uploadFile.getName();
    }

    StringBuilder sb = new StringBuilder();
    /**
     * 普通的表單數據
     */
    for (String key : params.keySet()) {
        sb.append("--" + BOUNDARY + "\r\n");
        sb.append("Content-Disposition: form-data; name=\"" + key + "\""
                + "\r\n");
        sb.append("\r\n");
        sb.append(params.get(key) + "\r\n");
    }
    /**
     * 上傳文件的頭
     */
    sb.append("--" + BOUNDARY + "\r\n");
    sb.append("Content-Disposition: form-data; name=\"" + fileFormName
            + "\"; filename=\"" + newFileName + "\"" + "\r\n");
    sb.append("Content-Type: image/jpeg" + "\r\n");// 如果服務器端有文件類型的校驗,必須明確指定ContentType
    sb.append("\r\n");

    byte[] headerInfo = sb.toString().getBytes("UTF-8");
    byte[] endInfo = ("\r\n--" + BOUNDARY + "--\r\n").getBytes("UTF-8");
    System.out.println(sb.toString());
    URL url = new URL(urlStr);
    HttpURLConnection conn = (HttpURLConnection) url.openConnection();
    conn.setRequestMethod("POST");
    conn.setRequestProperty("Content-Type",
            "multipart/form-data; boundary=" + BOUNDARY);
    conn.setRequestProperty("Content-Length", String
            .valueOf(headerInfo.length + uploadFile.length()
                    + endInfo.length));
    conn.setDoOutput(true);

    OutputStream out = conn.getOutputStream();
    InputStream in = new FileInputStream(uploadFile);
    out.write(headerInfo);

    byte[] buf = new byte[1024];
    int len;
    while ((len = in.read(buf)) != -1)
        out.write(buf, 0, len);

    out.write(endInfo);
    in.close();
    out.close();
    if (conn.getResponseCode() == 200) {
        System.out.println("上傳成功");
    }

基於Socket的實現:

/**
 * 
 * @param params
 *            傳遞的普通參數
 * @param uploadFile
 *            需要上傳的文件名
 * @param fileFormName
 *            需要上傳文件表單中的名字
 * @param newFileName
 *            上傳的文件名稱,不填寫將為uploadFile的名稱
 * @param urlStr
 *            上傳的服務器的路徑
 * @throws IOException
 */
public void uploadFromBySocket(Map params,
        String fileFormName, File uploadFile, String newFileName,
        String urlStr) throws IOException {
    if (newFileName == null || newFileName.trim().equals("")) {
        newFileName = uploadFile.getName();
    }

    StringBuilder sb = new StringBuilder();
    /**
     * 普通的表單數據
     */

    if (params != null)
        for (String key : params.keySet()) {
            sb.append("--" + BOUNDARY + "\r\n");
            sb.append("Content-Disposition: form-data; name=\"" + key
                    + "\"" + "\r\n");
            sb.append("\r\n");
            sb.append(params.get(key) + "\r\n");
        }                                                                                                                                                  else{ab.append("\r\n");}
    /**
     * 上傳文件的頭
     */
    sb.append("--" + BOUNDARY + "\r\n");
    sb.append("Content-Disposition: form-data; name=\"" + fileFormName
            + "\"; filename=\"" + newFileName + "\"" + "\r\n");
    sb.append("Content-Type: image/jpeg" + "\r\n");// 如果服務器端有文件類型的校驗,必須明確指定ContentType
    sb.append("\r\n");

    byte[] headerInfo = sb.toString().getBytes("UTF-8");
    byte[] endInfo = ("\r\n--" + BOUNDARY + "--\r\n").getBytes("UTF-8");

    System.out.println(sb.toString());

    URL url = new URL(urlStr);
    Socket socket = new Socket(url.getHost(), url.getPort());
    OutputStream os = socket.getOutputStream();
    PrintStream ps = new PrintStream(os, true, "UTF-8");

    // 寫出請求頭
    ps.println("POST " + urlStr + " HTTP/1.1");
    ps.println("Content-Type: multipart/form-data; boundary=" + BOUNDARY);
    ps.println("Content-Length: "
            + String.valueOf(headerInfo.length + uploadFile.length()
                    + endInfo.length));
    ps.println("Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");

    InputStream in = new FileInputStream(uploadFile);
    // 寫出數據
    os.write(headerInfo);

    byte[] buf = new byte[1024];
    int len;
    while ((len = in.read(buf)) != -1)
        os.write(buf, 0, len);

    os.write(endInfo);

    in.close();
    os.close();
}

這樣就可以實現文件上傳,這裡不是很復雜的,也可以使用文件上傳的框架實現。關於Android文件上傳和下載就簡單介紹到這裡,後面我們介紹框架的時候也會介紹到這些的。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved