使用Android下载文件,并在ProgressDialog中显示进度

Tom*_*ese 1017 java android download android-asynctask

我正在尝试编写一个更新的简单应用程序.为此,我需要一个简单的功能,可以下载一个文件,并显示当前进度ProgressDialog.我知道怎么做ProgressDialog,但我不知道如何显示当前进度以及如何首先下载文件.

Cri*_*ian 1836

有很多方法可以下载文件.以下我将发布最常见的方式; 您可以自行决定哪种方法更适合您的应用.

1. AsyncTask在对话框中使用并显示下载进度

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

这是一个示例代码:

import android.os.PowerManager;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.FileOutputStream;
import java.net.HttpURLConnection;
Run Code Online (Sandbox Code Playgroud)

AsyncTask会是这样的:

// 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
    }
});
Run Code Online (Sandbox Code Playgroud)

上面的方法(doInBackground)始终在后台线程上运行.你不应该在那里做任何UI任务.另一方面,onProgressUpdateonPreExecute在UI线程上运行,因此您可以更改进度条:

// 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;
    }
Run Code Online (Sandbox Code Playgroud)

要运行此选项,您需要WAKE_LOCK权限.

    @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();
    }
Run Code Online (Sandbox Code Playgroud)

2.从服务下载

这里最大的问题是:如何从服务更新我的活动?.在下一个例子中,我们将使用您可能不知道的两个类:ResultReceiverIntentService.ResultReceiver是允许我们从服务更新我们的线程的那个; IntentService是一个子类,Service它产生一个线程从那里做后台工作(你应该知道一个Service实际运行在你的应用程序的同一个线程;当你扩展时Service,你必须手动生成新的线程来运行CPU阻塞操作).

下载服务可能如下所示:

<uses-permission android:name="android.permission.WAKE_LOCK" />
Run Code Online (Sandbox Code Playgroud)

将服务添加到清单:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

活动将如下所示:

<service android:name=".DownloadService"/>
Run Code Online (Sandbox Code Playgroud)

以下是ResultReceiver发挥作用:

// 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);
Run Code Online (Sandbox Code Playgroud)

2.1使用Groundy库

Groundy是一个基本上可以帮助您在后台服务中运行代码的库,它基于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();
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

一个GroundyTask使用实施Groundy下载文件,并显示进度:

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 onClick(View view) {
                String url = ((EditText) findViewById(R.id.edit_url)).getText().toString().trim();
                Bundle extras = new Bundler().add(DownloadTask.PARAM_URL, url).build();
                Groundy.create(DownloadExample.this, DownloadTask.class)
                        .receiver(mReceiver)
                        .params(extras)
                        .queue();

                mProgressDialog = new ProgressDialog(MainActivity.this);
                mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
                mProgressDialog.setCancelable(false);
                mProgressDialog.show();
            }
        });
    }

    private ResultReceiver mReceiver = new ResultReceiver(new Handler()) {
        @Override
        protected void onReceiveResult(int resultCode, Bundle resultData) {
            super.onReceiveResult(resultCode, resultData);
            switch (resultCode) {
                case Groundy.STATUS_PROGRESS:
                    mProgressDialog.setProgress(resultData.getInt(Groundy.KEY_PROGRESS));
                    break;
                case Groundy.STATUS_FINISHED:
                    Toast.makeText(DownloadExample.this, R.string.file_downloaded, Toast.LENGTH_LONG);
                    mProgressDialog.dismiss();
                    break;
                case Groundy.STATUS_ERROR:
                    Toast.makeText(DownloadExample.this, resultData.getString(Groundy.KEY_ERROR), Toast.LENGTH_LONG).show();
                    mProgressDialog.dismiss();
                    break;
            }
        }
    };
}
Run Code Online (Sandbox Code Playgroud)

然后将其添加到清单中:

public class DownloadTask extends GroundyTask {    
    public static final String PARAM_URL = "com.groundy.sample.param.url";

    @Override
    protected boolean doInBackground() {
        try {
            String url = getParameters().getString(PARAM_URL);
            File dest = new File(getContext().getFilesDir(), new File(url).getName());
            DownloadUtils.downloadFile(getContext(), url, dest, DownloadUtils.getDownloadListenerForTask(this));
            return true;
        } catch (Exception pokemon) {
            return false;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我想这可不容易.只需从Github拿起最新的罐子,你就可以开始了.请记住,Groundy的主要目的是在后台服务中调用外部REST apis,并轻松地将结果发布到UI.如果你在你的应用程序中做了类似的事情,它可能真的很有用.

2.2使用https://github.com/koush/ion

3.使用DownloadManager类(GingerBread仅限更新)

GingerBread带来了一项新功能,DownloadManager它允许您轻松下载文件并将处理线程,流等的艰苦工作委派给系统.

首先,让我们看一个实用方法:

<service android:name="com.codeslap.groundy.GroundyService"/>
Run Code Online (Sandbox Code Playgroud)

方法的名称解释了这一切.一旦确定DownloadManager可用,您可以执行以下操作:

/**
 * @param context used to check the device version and DownloadManager information
 * @return true if the download manager is available
 */
public static boolean isDownloadManagerAvailable(Context context) {

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
        return true;
    }
    return false;
}
Run Code Online (Sandbox Code Playgroud)

下载进度将显示在通知栏中.

最后的想法

第一种和第二种方法只是冰山一角.如果您希望自己的应用程序功能强大,那么您需要记住很多事情.这是一个简短的清单:

  • 您必须检查用户是否有可用的Internet连接
  • 确保您拥有正确的权限(INTERNETWRITE_EXTERNAL_STORAGE); 同样ACCESS_NETWORK_STATE,如果你想检查网络可用性.
  • 确保目录是否要下载存在的文件并具有写入权限.
  • 如果下载太大,您可能希望实现一种方法,以便在以前的尝试失败时恢复下载.
  • 如果您允许用户中断下载,用户将不胜感激.

除非您需要详细控制下载过程,否则请考虑使用DownloadManager(3),因为它已经处理了上面列出的大多数项目.

但也要考虑您的需求可能会发生变化.例如,DownloadManager 没有响应缓存.它会盲目地多次下载同一个大文件.事后没有简单的方法来解决它.如果你从一个基本HttpURLConnection(1,2)开始,那么你只需要添加一个HttpResponseCache.因此,学习基本标准工具的初步努力可能是一项很好的投资.

此类在API级别26中已弃用.ProgressDialog是一个模式对话框,可防止用户与应用程序进行交互.您应该使用ProgressBar等进度指示器,而不是使用此类,可以将其嵌入到应用程序的UI中.或者,您可以使用通知来通知用户任务的进度.有关详细信息链接

  • 我希望android文档这个简洁. (95认同)
  • 不要硬编码/`sdcard /`使用`Environment.getExternalStorageDirectory()`代替. (32认同)
  • Cristian的回答有一个问题.因为"**1.使用AsyncTask并在对话框中显示下载进度**"中的代码执行connection.connect(); 然后是InputStream input = new BufferedInputStream(url.openStream()); 代码与服务器建立了2个连接.我已设法通过更新代码来更改此行为,如下所示InputStream input = new BufferedInputStream(connection.getInputStream()); (17认同)
  • 建议在`finally`而不是`try`中'close()`流(`input`和`output`),否则如果在`close()`之前抛出任何异常,你就会有未关闭的流. (12认同)
  • DownloadManager是操作系统的一部分,这意味着它始终以GB +提供,无法卸载. (8认同)
  • @Cristian感谢您提供了很棒的代码.我正在实施您的第二种方法"从服务下载".你能告诉我如何实现暂停和恢复功能吗?由于我正在下载大文件,因此互联网连接可能会中断,或者用户可能希望暂停下载并稍后恢复. (2认同)

小智 105

如果您要从互联网上下载内容,请不要忘记为清单文件添加权限!

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.helloandroid"
    android:versionCode="1"
    android:versionName="1.0">

        <uses-sdk android:minSdkVersion="10" />

        <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>

        <application 
            android:icon="@drawable/icon" 
            android:label="@string/app_name" 
            android:debuggable="true">

        </application>

</manifest>
Run Code Online (Sandbox Code Playgroud)

  • 我很确定你不需要 READ_PHONE_STATE 并且你绝对不需要 WRITE_EXTERNAL_STORAGE; 这是一个危险的权限,可以通过使用存储访问框架来避免。 (2认同)

she*_*tal 31

是的,上面的代码可以正常工作.但是如果你正在更新你progressbaronProgressUpdate内容Asynctask 而你按下后退按钮或完成你的活动就会AsyncTask失去你的用户界面.当你回到你的活动时,即使下载是在后台运行,你也会看到没有进度条更新.因此,OnResume()尝试运行一个类似于runOnUIThread计时器任务的线程,该任务progressbar使用从AsyncTask正在运行的背景更新的值来更新你的任务.

private void updateProgressBar(){
    Runnable runnable = new updateProgress();
    background = new Thread(runnable);
    background.start();
}

public class updateProgress implements Runnable {
    public void run() {
        while(Thread.currentThread()==background)
            //while (!Thread.currentThread().isInterrupted()) {
            try {
                Thread.sleep(1000); 
                Message msg = new Message();
                progress = getProgressPercentage();        
                handler.sendMessage(msg);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            } catch (Exception e) {
        }
    }
}

private Handler handler = new Handler(){
    @Override
    public void handleMessage(Message msg) {
        progress.setProgress(msg.what);
    }
};
Run Code Online (Sandbox Code Playgroud)

当您的活动不可见时,不要忘记销毁线程.

private void destroyRunningThreads() {
    if (background != null) {
        background.interrupt();
        background=null;
    }
}
Run Code Online (Sandbox Code Playgroud)

  • okk采取全局或静态变量来从asynctask更新你的值...或者你可以将它插入DataBase中以保证安全.所以关闭应用程序不会妨碍..当你重新启动你想要更新你的活动时UI运行UI线程.请参见下面的示例 (2认同)

Vin*_*ing 17

我建议你使用我的Project Netroid,它基于Volley.我添加了一些功能,如多事件回调,文件下载管理.这可能会有所帮助.

  • 它支持多文件下载吗?我正在开发一个允许用户下载预定的项目.在特定时间(例如,上午12点),该服务将下载用户之前选择的所有链接.我的意思是我需要的服务必须能够排队下载链接,然后下载所有这些(一个接一个或并行,取决于用户).谢谢 (2认同)

小智 14

我修改了AsyncTask类以处理progressDialog在相同上下文中的创建.我认为以下代码将更可重用.(可以从任何活动调用它只传递上下文,目标文件,对话框消息)

public static class DownloadTask extends AsyncTask<String, Integer, String> {
    private ProgressDialog mPDialog;
    private Context mContext;
    private PowerManager.WakeLock mWakeLock;
    private File mTargetFile;
    //Constructor parameters :
    // @context (current Activity)
    // @targetFile (File object to write,it will be overwritten if exist)
    // @dialogMessage (message of the ProgresDialog)
    public DownloadTask(Context context,File targetFile,String dialogMessage) {
        this.mContext = context;
        this.mTargetFile = targetFile;
        mPDialog = new ProgressDialog(context);

        mPDialog.setMessage(dialogMessage);
        mPDialog.setIndeterminate(true);
        mPDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
        mPDialog.setCancelable(true);
        // reference to instance to use inside listener
        final DownloadTask me = this;
        mPDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
            @Override
            public void onCancel(DialogInterface dialog) {
                me.cancel(true);
            }
        });
        Log.i("DownloadTask","Constructor done");
    }

    @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();
            }
            Log.i("DownloadTask","Response " + connection.getResponseCode());

            // 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(mTargetFile,false);

            byte data[] = new byte[4096];
            long total = 0;
            int count;
            while ((count = input.read(data)) != -1) {
                // allow canceling with back button
                if (isCancelled()) {
                    Log.i("DownloadTask","Cancelled");
                    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;
    }
    @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) mContext.getSystemService(Context.POWER_SERVICE);
        mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
                getClass().getName());
        mWakeLock.acquire();

        mPDialog.show();

    }

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

    }

    @Override
    protected void onPostExecute(String result) {
        Log.i("DownloadTask", "Work Done! PostExecute");
        mWakeLock.release();
        mPDialog.dismiss();
        if (result != null)
            Toast.makeText(mContext,"Download error: "+result, Toast.LENGTH_LONG).show();
        else
            Toast.makeText(mContext,"File Downloaded", Toast.LENGTH_SHORT).show();
    }
}
Run Code Online (Sandbox Code Playgroud)


ENS*_*ATE 8

不要忘记用新文件替换"/ sdcard ..." ("/ mnt/sdcard/...")否则你会得到一个FileNotFoundException

  • 不要做!有一个`Environment.getExternalStorageDirectory().getAbsolutePath()`用于获取sdcard的路径.另外不要忘记检查外部存储是否已挂载 - "Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)"([Mannaz](http://stackoverflow.com/questions/5453708/android-how-to - 使用 - 环境 - getexternalstoragedirectory#comment9395458_5453753)) (14认同)

chi*_*iya 8

我发现这篇博文很有帮助,它使用loopJ下载文件,它只有一个简单的功能,对一些新的android家伙会有所帮助.


San*_*eep 6

当我开始学习android开发时,我已经知道这ProgressDialog是要走的路.在下载文件时,可以调用其setProgress方法ProgressDialog来更新进度级别.

我在许多应用程序中看到的最好的是它们自定义此进度对话框的属性,以便为进度对话框提供比库存版本更好的外观和感觉.很好地保持用户参与一些像青蛙,大象或可爱的猫/小狗的动画.在进度对话框中的任何动画都会吸引用户,他们不想长时间等待.


Raj*_*epe 5

我个人的建议是使用进度对话框,并在执行之前进行构建,或者OnPreExecute()如果您使用进度对话框的水平样式进度条,则会经常发布进度.剩下的部分是优化算法doInBackground.


Ren*_*tik 5

使用Android查询库,非常酷.您可以将其更改为使用,ProgressDialog如您在其他示例中所看到的,这个将从您的布局显示进度视图并在完成后隐藏它.

File target = new File(new File(Environment.getExternalStorageDirectory(), "ApplicationName"), "tmp.pdf");
new AQuery(this).progress(R.id.progress_view).download(_competition.qualificationScoreCardsPdf(), target, new AjaxCallback<File>() {
    public void callback(String url, File file, AjaxStatus status) {
        if (file != null) {
            // do something with file  
        } 
    }
});
Run Code Online (Sandbox Code Playgroud)


Kin*_*jal 5

我们可以使用协程和工作管理器在 kotlin 中下载文件。

在 build.gradle 中添加依赖

    implementation "androidx.work:work-runtime-ktx:2.3.0-beta01"
    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.1"
Run Code Online (Sandbox Code Playgroud)

工作管理器类

    import android.content.Context
    import android.os.Environment
    import androidx.work.CoroutineWorker
    import androidx.work.WorkerParameters
    import androidx.work.workDataOf
    import com.sa.chat.utils.Const.BASE_URL_IMAGE
    import com.sa.chat.utils.Constants
    import kotlinx.coroutines.delay
    import java.io.BufferedInputStream
    import java.io.File
    import java.io.FileOutputStream
    import java.net.URL

    class DownloadMediaWorkManager(appContext: Context, workerParams: WorkerParameters)
        : CoroutineWorker(appContext, workerParams) {

        companion object {
            const val WORK_TYPE = "WORK_TYPE"
            const val WORK_IN_PROGRESS = "WORK_IN_PROGRESS"
            const val WORK_PROGRESS_VALUE = "WORK_PROGRESS_VALUE"
        }

        override suspend fun doWork(): Result {

            val imageUrl = inputData.getString(Constants.WORK_DATA_MEDIA_URL)
            val imagePath = downloadMediaFromURL(imageUrl)

            return if (!imagePath.isNullOrEmpty()) {
                Result.success(workDataOf(Constants.WORK_DATA_MEDIA_URL to imagePath))
            } else {
                Result.failure()
            }
        }

        private suspend fun downloadMediaFromURL(imageUrl: String?): String? {

            val file = File(
                    getRootFile().path,
                    "IMG_${System.currentTimeMillis()}.jpeg"
            )

            val url = URL(BASE_URL_IMAGE + imageUrl)
            val connection = url.openConnection()
            connection.connect()

            val lengthOfFile = connection.contentLength
            // download the file
            val input = BufferedInputStream(url.openStream(), 8192)
            // Output stream
            val output = FileOutputStream(file)

            val data = ByteArray(1024)
            var total: Long = 0
            var last = 0

            while (true) {

                val count = input.read(data)
                if (count == -1) break
                total += count.toLong()

                val progress = (total * 100 / lengthOfFile).toInt()

                if (progress % 10 == 0) {
                    if (last != progress) {
                        setProgress(workDataOf(WORK_TYPE to WORK_IN_PROGRESS,
                                WORK_PROGRESS_VALUE to progress))
                    }
                    last = progress
                    delay(50)
                }
                output.write(data, 0, count)
            }

            output.flush()
            output.close()
            input.close()

            return file.path

        }

        private fun getRootFile(): File {

            val rootDir = File(Environment.getExternalStorageDirectory().absolutePath + "/AppName")

            if (!rootDir.exists()) {
                rootDir.mkdir()
            }

            val dir = File("$rootDir/${Constants.IMAGE_FOLDER}/")

            if (!dir.exists()) {
                dir.mkdir()
            }
            return File(dir.absolutePath)
        }
    }
Run Code Online (Sandbox Code Playgroud)

通过活动类中的工作管理器开始下载

 private fun downloadImage(imagePath: String?, id: String) {

            val data = workDataOf(WORK_DATA_MEDIA_URL to imagePath)
            val downloadImageWorkManager = OneTimeWorkRequestBuilder<DownloadMediaWorkManager>()
                    .setInputData(data)
                    .addTag(id)
                    .build()

            WorkManager.getInstance(this).enqueue(downloadImageWorkManager)

            WorkManager.getInstance(this).getWorkInfoByIdLiveData(downloadImageWorkManager.id)
                    .observe(this, Observer { workInfo ->

                        if (workInfo != null) {
                            when {
                                workInfo.state == WorkInfo.State.SUCCEEDED -> {
                                    progressBar?.visibility = View.GONE
                                    ivDownload?.visibility = View.GONE
                                }
                                workInfo.state == WorkInfo.State.FAILED || workInfo.state == WorkInfo.State.CANCELLED || workInfo.state == WorkInfo.State.BLOCKED -> {
                                    progressBar?.visibility = View.GONE
                                    ivDownload?.visibility = View.VISIBLE
                                }
                                else -> {
                                    if(workInfo.progress.getString(WORK_TYPE) == WORK_IN_PROGRESS){
                                        val progress = workInfo.progress.getInt(WORK_PROGRESS_VALUE, 0)
                                        progressBar?.visibility = View.VISIBLE
                                        progressBar?.progress = progress
                                        ivDownload?.visibility = View.GONE

                                    }
                                }
                            }
                        }
                    })

        }
Run Code Online (Sandbox Code Playgroud)


归档时间:

查看次数:

523975 次

最近记录:

5 年,11 月 前