频道栏目
首页 > 资讯 > Android > 正文

Android学习笔记039之文件上传和下载

16-08-09        来源:[db:作者]  
收藏   我要投稿

文件上传和下载在我们开发中经常需要用到,现在也有很多的网络框架封装了文件上传和下载功能。不过这一篇,我们介绍一下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文件上传和下载就简单介绍到这里,后面我们介绍框架的时候也会介绍到这些的。

相关TAG标签
上一篇:扫雷(java版)
下一篇:Android单排上王者系列之Android MVP解析实践
相关文章
图文推荐

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训 | 举报中心

版权所有: 红黑联盟--致力于做实用的IT技术学习网站