安卓:如何在安卓系统中下载文件?

6
我正在尝试从URL下载文件。我有以下代码。
package com.example.downloadfile;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.ProtocolException;
import java.net.URL;

import android.app.Activity;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.widget.TextView;
import android.widget.Toast;

public class DownloadFile extends Activity {

     private static String fileName = "al.jpg";

     @Override
     public void onCreate(Bundle savedInstanceState) 
     {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        TextView tv = new TextView(this);
        tv.setText("This is download file program... ");

        try {
            //this is the file you want to download from the remote server
            String path ="http://www.fullissue.com/wp-content/uploads/2010/12/Adam-Lambert.jpg";
            //this is the name of the local file you will create

            String targetFileName = "al.jpg";

            boolean eof = false;

            URL u = new URL(path);
            HttpURLConnection c = (HttpURLConnection) u.openConnection();
            c.setRequestMethod("GET");
            c.setDoOutput(true);
            c.connect();

            String PATH_op = Environment.getExternalStorageDirectory() + "/download/" + targetFileName;

            tv.append("\nPath > " + PATH_op);

            FileOutputStream f = new FileOutputStream(new File(PATH_op));

            InputStream in = c.getInputStream();
            byte[] buffer = new byte[1024];
            int len1 = 0;
            while ( (len1 = in.read(buffer)) > 0 ) {
                f.write(buffer,0, len1);
            }

            f.close();

            } catch (MalformedURLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            } catch (ProtocolException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            Toast.makeText(this, e.getMessage(), Toast.LENGTH_LONG).show();
        }

        tv.append("\nAnother append!");
        this.setContentView(tv);
    }

}

有人能告诉我这段代码哪里出了问题吗?我无法看到我应该下载的文件。我是java和android开发的新手,非常感谢任何帮助。:)


1
嘿,看看这个:http://www.anddev.org/novice-tutorials-f8/imageview-with-loading-spinner-t49439.html 免费源代码下载和图像显示加载旋转器,同时它正在发生:-)。但是如果你想要下载到文件,那么这只是一个评论而不是答案。 - Blundell
@Blundell:感谢教程链接,很有趣。但是是的,我想要下载一个文件而不只是图片 :) - Kris
3个回答

7
  1. 您正在主应用程序线程上进行网络I/O。最好情况下,这将在下载进行时冻结您的UI。最坏的情况下,您的活动将崩溃并显示“应用程序未响应”(ANR)对话框。

  2. 您正在尝试写入可能不存在的外部存储器上的目录(download/)。请先创建该目录。

  3. 请考虑切换到使用Log.e()进行错误日志记录,因为我不知道printStackTrace()在Android上是否有效。

此外,请确保您具有WRITE_EXTERNAL_STORAGE权限,并且您正在使用adb logcat、DDMS或Eclipse中的DDMS透视图来检查LogCat并查找您要记录的错误消息。


感谢您的回复。1. 我只想先尝试下载一个文件。2. download/目录已经存在。我还在我的AndroidManifest.xml中添加了WRITE_EXTERNAL_STORAGE权限。3. 是否有其他方法可以获得错误,我正在做的是,我复制apk文件,然后将其传输并安装到我的平板电脑上。 - Kris
你应该使用ADB将平板电脑连接到Eclipse,这样你就可以在DDMS视角中获取堆栈跟踪,并且可以立即部署而不需要复制APK文件。 - Blundell

2
首先,您应该在AndroidManifest.xml中添加权限:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"></uses-permission>
<uses-permission android:name="android.permission.READ_PHONE_STATE"></uses-permission>

其次,添加以下代码,以便如果文件夹不存在,则检查并创建该文件夹:
File root = android.os.Environment.getExternalStorageDirectory();               

           File dir = new File (root.getAbsolutePath() + "/download");
           if(!dir.exists()) {
                dir.mkdirs();
           }

第三,正如Commons Ware所说的那样,在主线程上下载不是一个好的实践;你应该在新线程上实现它;因为在下载时,主线程会忙于下载文件。如果等待时间超过预期,系统将生成“无响应”错误。
为了做到这一点,你可以使用 "TaskAsync" 或 "IntentService" 或者创建一个新线程。
正如你所说,你还是Java的新手,我建议使用 "TaskAsync",因为它非常直观和易于理解。

2

这个库将会帮助你

https://github.com/AriaLyy/Aria

只需一行代码即可下载文件

Aria.download(this)
    .load(DOWNLOAD_URL)
    .setDownloadPath(DOWNLOAD_PATH) //file save path
    .add();

获取下载状态

@Download.onPre(DOWNLOAD_URL)
  protected void onPre(DownloadTask task) {}

  @Download.onTaskStart
  void taskStart(DownloadTask task) {}

  @Download.onTaskRunning
  protected void running(DownloadTask task) {}

  @Download.onTaskResume
  void taskResume(DownloadTask task) {}

  @Download.onTaskStop
  void taskStop(DownloadTask task) {}

  @Download.onTaskCancel
  void taskCancel(DownloadTask task) {}

  @Download.onTaskFail
  void taskFail(DownloadTask task) {}

  @Download.onTaskComplete
  void taskComplete(DownloadTask task) {}

  @Download.onNoSupportBreakPoint
  public void onNoSupportBreakPoint(DownloadTask task) {}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接