Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
527 views
in Technique[技术] by (71.8m points)

java - 使用Android下载文件,并在ProgressDialog中显示进度(Download a file with Android, and showing the progress in a ProgressDialog)

I am trying to write a simple application that gets updated.

(我正在尝试编写一个易于更新的简单应用程序。)

For this I need a simple function that can download a file and show the current progress in a ProgressDialog .

(为此,我需要一个简单的函数,该函数可以下载文件并在ProgressDialog 显示当前进度 。)

I know how to do the ProgressDialog , but I'm not sure how to display the current progress and how to download the file in the first place.

(我知道如何执行ProgressDialog ,但是我不确定如何首先显示当前进度以及如何下载文件。)

  ask by Tom Leese translate from so

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

There are many ways to download files.

(有许多下载文件的方法。)

Following I will post most common ways;

(接下来,我将发布最常见的方式;)

it is up to you to decide which method is better for your app.

(由您决定哪种方法更适合您的应用。)

1. Use AsyncTask and show the download progress in a dialog (1.使用AsyncTask并在对话框中显示下载进度)

This method will allow you to execute some background processes and update the UI at the same time (in this case, we'll update a progress bar).

(通过此方法,您可以执行一些后台进程并同时更新UI(在这种情况下,我们将更新进度条)。)

Imports:

(进口:)

import android.os.PowerManager;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.FileOutputStream;
import java.net.HttpURLConnection;

This is an example code:

(这是一个示例代码:)

// declare the dialog as a member field of your activity
ProgressDialog mProgressDialog;

// instantiate it within the onCreate method
mProgressDialog = new ProgressDialog(YourActivity.this);
mProgressDialog.setMessage("A message");
mProgressDialog.setIndeterminate(true);
mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
mProgressDialog.setCancelable(true);

// execute this when the downloader must be fired
final DownloadTask downloadTask = new DownloadTask(YourActivity.this);
downloadTask.execute("the url to the file you want to download");

mProgressDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {

    @Override
    public void onCancel(DialogInterface dialog) {
        downloadTask.cancel(true); //cancel the task
    }
});

The AsyncTask will look like this:

(AsyncTask将如下所示:)

// usually, subclasses of AsyncTask are declared inside the activity class.
// that way, you can easily modify the UI thread from here
private class DownloadTask extends AsyncTask<String, Integer, String> {

    private Context context;
    private PowerManager.WakeLock mWakeLock;

    public DownloadTask(Context context) {
        this.context = context;
    }

    @Override
    protected String doInBackground(String... sUrl) {
        InputStream input = null;
        OutputStream output = null;
        HttpURLConnection connection = null;
        try {
            URL url = new URL(sUrl[0]);
            connection = (HttpURLConnection) url.openConnection();
            connection.connect();

            // expect HTTP 200 OK, so we don't mistakenly save error report
            // instead of the file
            if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
                return "Server returned HTTP " + connection.getResponseCode()
                        + " " + connection.getResponseMessage();
            }

            // this will be useful to display download percentage
            // might be -1: server did not report the length
            int fileLength = connection.getContentLength();

            // download the file
            input = connection.getInputStream();
            output = new FileOutputStream("/sdcard/file_name.extension");

            byte data[] = new byte[4096];
            long total = 0;
            int count;
            while ((count = input.read(data)) != -1) {
                // allow canceling with back button
                if (isCancelled()) {
                    input.close();
                    return null;
                }
                total += count;
                // publishing the progress....
                if (fileLength > 0) // only if total length is known
                    publishProgress((int) (total * 100 / fileLength));
                output.write(data, 0, count);
            }
        } catch (Exception e) {
            return e.toString();
        } finally {
            try {
                if (output != null)
                    output.close();
                if (input != null)
                    input.close();
            } catch (IOException ignored) {
            }

            if (connection != null)
                connection.disconnect();
        }
        return null;
    }

The method above ( doInBackground ) runs always on a background thread.

(上面的方法( doInBackground )始终在后台线程上运行。)

You shouldn't do any UI tasks there.

(您不应该在那里执行任何UI任务。)

On the other hand, the onProgressUpdate and onPreExecute run on the UI thread, so there you can change the progress bar:

(另一方面, onProgressUpdateonPreExecute在UI线程上运行,因此您可以在其中更改进度栏:)

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        // take CPU lock to prevent CPU from going off if the user 
        // presses the power button during download
        PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
        mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
             getClass().getName());
        mWakeLock.acquire();
        mProgressDialog.show();
    }

    @Override
    protected void onProgressUpdate(Integer... progress) {
        super.onProgressUpdate(progress);
        // if we get here, length is known, now set indeterminate to false
        mProgressDialog.setIndeterminate(false);
        mProgressDialog.setMax(100);
        mProgressDialog.setProgress(progress[0]);
    }

    @Override
    protected void onPostExecute(String result) {
        mWakeLock.release();
        mProgressDialog.dismiss();
        if (result != null)
            Toast.makeText(context,"Download error: "+result, Toast.LENGTH_LONG).show();
        else
            Toast.makeText(context,"File downloaded", Toast.LENGTH_SHORT).show();
    }

For this to run, you need the WAKE_LOCK permission.

(要运行此程序,您需要WAKE_LOCK权限。)

<uses-permission android:name="android.permission.WAKE_LOCK" />

2. Download from Service (2.从服务下载)

The big question here is: how do I update my activity from a service?

(这里的最大问题是: 如何从服务更新我的活动?)

.

(。)

In the next example we are going to use two classes you may not be aware of: ResultReceiver and IntentService .

(在下一个示例中,我们将使用您可能不知道的两个类: ResultReceiverIntentService 。)

ResultReceiver is the one that will allow us to update our thread from a service;

(ResultReceiver是一个允许我们从服务更新线程的函数;)

IntentService is a subclass of Service which spawns a thread to do background work from there (you should know that a Service runs actually in the same thread of your app; when you extends Service , you must manually spawn new threads to run CPU blocking operations).

(IntentServiceService的子类,它从那里产生一个线程来执行后台工作(您应该知道Service实际上在应用程序的同一线程中运行;扩展Service ,您必须手动产生新线程来运行CPU阻塞操作) 。)

Download service can look like this:

(下载服务如下所示:)

public class DownloadService extends IntentService {
    public static final int UPDATE_PROGRESS = 8344;

    public DownloadService() {
        super("DownloadService");
    }
    @Override
    protected void onHandleIntent(Intent intent) {

        String urlToDownload = intent.getStringExtra("url");
        ResultReceiver receiver = (ResultReceiver) intent.getParcelableExtra("receiver");
        try {

            //create url and connect
            URL url = new URL(urlToDownload);
            URLConnection connection = url.openConnection();
            connection.connect();

            // this will be useful so that you can show a typical 0-100% progress bar
            int fileLength = connection.getContentLength();

            // download the file
            InputStream input = new BufferedInputStream(connection.getInputStream());

            String path = "/sdcard/BarcodeScanner-debug.apk" ;
            OutputStream output = new FileOutputStream(path);

            byte data[] = new byte[1024];
            long total = 0;
            int count;
            while ((count = input.read(data)) != -1) {
                total += count;

                // publishing the progress....
                Bundle resultData = new Bundle();
                resultData.putInt("progress" ,(int) (total * 100 / fileLength));
                receiver.send(UPDATE_PROGRESS, resultData);
                output.write(data, 0, count);
            }

            // close streams 
            output.flush();
            output.close();
            input.close();

        } catch (IOException e) {
            e.printStackTrace();
        }

        Bundle resultData = new Bundle();
        resultData.putInt("progress" ,100);

        receiver.send(UPDATE_PROGRESS, resultData);
    }
}

Add the service to your manifest:

(将服务添加到清单中:)

<service android:name=".DownloadService"/>

And the activity will look like this:

(活动将如下所示:)

// initialize the progress dialog like in the first example

// this is how you fire the downloader
mProgressDialog.show();
Intent intent = new Intent(this, DownloadService.class);
intent.putExtra("url", "url of the file to download");
intent.putExtra("receiver", new DownloadReceiver(new Handler()));
startService(intent);

Here is were ResultReceiver comes to play:

(这是ResultReceiver发挥作用的:)

private class DownloadReceiver extends ResultReceiver{

    public DownloadReceiver(Handler handler) {
        super(handler);
    }

    @Override
    protected void onReceiveResult(int resultCode, Bundle resultData) {

        super.onReceiveResult(resultCode, resultData);

        if (resultCode == DownloadService.UPDATE_PROGRESS) {

            int progress = resultData.getInt("progress"); //get the progress
            dialog.setProgress(progress);

            if (progress == 100) {
                dialog.dismiss();
            }
        }
    }
}

2.1 Use Groundy library (2.1使用Groundy库)

Groundy is a library that basically helps you run pieces of code in a background service, and it is based on the ResultReceiver concept shown above.

(Groundy是一个库,它基本上基于上面显示的ResultReceiver概念来帮助您在后台服务中运行代码。)

This library is deprecated at the moment.

(目前不推荐使用该库。)

This is how the whole code would look like:

(整个代码如下所示:)

The activity where you are showing the dialog...

(显示对话框的活动...)

public class MainActivity extends Activity {

    private ProgressDialog mProgressDialog;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        findViewById(R.id.btn_download).setOnClickListener(new View.OnClickListener() {
            public void onCl

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...