programing

Android로 파일을 다운로드하고 진행 상황을 ProgressDialog로 표시

prostudy 2022. 6. 11. 11:45
반응형

Android로 파일을 다운로드하고 진행 상황을 ProgressDialog로 표시

업데이트되는 간단한 어플리케이션을 작성하려고 합니다.이를 위해 파일을 다운로드하여 현재 진행 상황을 표시할 수 있는 간단한 기능이 필요합니다.ProgressDialog떻게 to to to 를 어떻게 하는지 안다.ProgressDialog그러나 현재 진행상황과 파일을 다운로드하는 방법을 먼저 알 수 없습니다.

파일을 다운로드하는 방법은 여러 가지가 있습니다.가장 일반적인 방법을 투고하겠습니다.어느 방법이 앱에 좋은지 결정하는 것은 당신에게 달려 있습니다.

. 1. 을 사용합니다.AsyncTask합니다.

이 방법을 사용하면 백그라운드 프로세스를 실행하는 동시에 UI를 업데이트할 수 있습니다(이 경우 진행 표시줄을 업데이트합니다).

Import:

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

코드 예를 다음에 나타냅니다.

// 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
    }
});

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

( 「 」 「 」 )doInBackground는 항상 백그라운드스레드에서 실행됩니다.UI를 사용합니다. 편,는onProgressUpdate ★★★★★★★★★★★★★★★★★」onPreExecuteUI 스레드에서 실행되므로 진행 표시줄을 변경할 수 있습니다.

    @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();
    }

이를 실행하려면 WAKE_LOCK 권한이 필요합니다.

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

2. 서비스에서 다운로드

여기서 중요한 질문은 서비스로부터의 액티비티를 어떻게 갱신할 인가 하는 입니다.다음 예제에서는 사용자가 인식하지 못할 수 있는 두 가지 클래스를 사용합니다.ResultReceiver ★★★★★★★★★★★★★★★★★」IntentServiceResultReceiver하게 하는 「」입니다.IntentService는 의 입니다.Service을 할 수 됩니다.Service됩니다.이러한 스레드를 하면,확장할 때ServiceCPU 블로킹 조작을 실행하려면 수동으로 새로운 스레드를 생성해야 합니다).

다운로드 서비스는 다음과 같습니다.

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);
    }
}

매니페스트에 서비스를 추가합니다.

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

액티비티는 다음과 같습니다.

// 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기다 here here here here 。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 Groundy 라이브러리 사용

Groundy는 백그라운드서비스에서 코드 조각을 실행하는 것을 기본적으로 지원하는 라이브러리입니다.이 라이브러리는ResultReceiver를 참조해 주세요.이 도서관은 현재 사용되지 않습니다.전체 코드는 다음과 같습니다.

대화 상자를 표시하는 작업...

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

A GroundyTask파일을 다운로드하고 진행 상황을 표시하기 위해 Groundy에 의해 사용되는 구현:

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

매니페스트에 이걸 추가해 주세요.

<service android:name="com.codeslap.groundy.GroundyService"/>

내 생각엔 이보다 더 쉬울 순 없어.Github에서 최신 항아리만 가져오면 바로 갈 수 있습니다.Groundy의 주된 목적은 백그라운드 서비스의 외부 REST apis에 전화를 걸어 쉽게 UI에 결과를 올리는 것입니다.앱에서 그런 걸 하고 있다면 정말 도움이 될 거예요.

2.2 https://github.com/koush/ion 사용

. 3. 용용을 하세요.DownloadManager클래스)GingerBread버전만)

는 GingerBread라는 기능을 했습니다.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;
}

방법 DownloadManager을 사용하다

String url = "url you want to download";
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
request.setDescription("Some descrition");
request.setTitle("Some title");
// in order for this if to run, you must use the android 3.2 to compile your app
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
    request.allowScanningByMediaScanner();
    request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
}
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "name-of-the-file.ext");

// get download service and enqueue file
DownloadManager manager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
manager.enqueue(request);

다운로드 진행 상황이 알림 표시줄에 표시됩니다.

마지막 생각

첫 번째와 두 번째 방법은 빙산의 일각일 뿐이다.앱이 강력해지길 원한다면 많은 것을 명심해야 합니다.다음은 간단한 목록입니다.

  • 사용자가 인터넷 연결을 사용할 수 있는지 확인해야 합니다.
  • 을 가지고 합니다.INTERNET ★★★★★★★★★★★★★★★★★」WRITE_EXTERNAL_STORAGE도 ); 또 )ACCESS_NETWORK_STATE인터넷 사용 가능 여부를 확인하려면 를 클릭하십시오.
  • 파일을 다운로드할 디렉토리가 존재하고 쓰기 권한이 있는지 확인하십시오.
  • 다운로드가 너무 큰 경우 이전 시도가 실패했을 경우 다운로드를 재개하는 방법을 구현할 수 있습니다.
  • 다운로드를 중단하는 것을 허락해 주시면 감사하겠습니다.

가 없는 한, 「」를 사용해 .DownloadManager(3을 이미 때문입니다3)

하지만 당신의 요구가 바뀔 수도 있다는 것도 고려하세요.를 들어, 「」라고 하는 것은,DownloadManager 는 응답 캐싱을 하지 않습니다.동일한 대용량 파일을 여러 번 맹목적으로 다운로드합니다.그 일이 있은 후에 그것을 고칠 수 있는 쉬운 방법은 없다.베이직부터 시작하면요?HttpURLConnection() '1, 2) ㄹ게요, 하다, 하다, 하다, 하다, 하다, 하다'를 넣으면 됩니다HttpResponseCache따라서 기본적인 표준 툴을 익히는 첫 번째 노력이 좋은 투자가 될 수 있습니다.

이 클래스는 API 수준 26에서 더 이상 사용되지 않습니다.ProgressDialog는 사용자가 앱과 상호 작용할 수 없도록 하는 모달 대화 상자입니다.이 클래스를 사용하는 대신 프로그램의 UI에 내장될 수 있는 ProgressBar와 같은 진행률 표시기를 사용해야 합니다.또는 통지를 사용하여 사용자에게 태스크 진행률을 알릴 수 있습니다.자세한 내용은 링크

인터넷에서 다운로드하려면 매니페스트 파일에 권한을 추가하는 것을 잊지 마세요!

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

, 위의 합니다., ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★progressbaronProgressUpdateAsynctask.AsyncTaskUI에서 트랙이 손실됩니다.또, 액티비티로 돌아가면, 다운로드가 백그라운드에서 실행되고 있어도, 프로그레스바의 갱신은 표시되지 않습니다. ①에 대해서.OnResume()runOnUIThread 갱신됩니다.progressbarAsyncTask실행 백그라운드

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);
    }
};

활동이 보이지 않을 때는 스레드를 파괴하는 을 잊지 마십시오.

private void destroyRunningThreads() {
    if (background != null) {
        background.interrupt();
        background=null;
    }
}

발리에 기반프로젝트 넷로이드 사용을 추천합니다.멀티 이벤트 콜백, 파일 다운로드 관리 등의 기능을 추가했습니다.이게 도움이 될 거야

했습니다.AsyncTaskprogressDialog같은 맥락에서. 메시지만 하면 호출할 수 있습니다.컨텍스트 통과, 타겟 파일, 대화상자 메시지만)

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();
    }
}

저는 이 블로그 투고가 매우 도움이 된다고 생각했습니다.loopJ를 사용하여 파일을 다운로드 할 수 있습니다.Simple 기능은 1개뿐이며, 새로운 Android 사용자에게 도움이 될 것입니다.

"/sdcard"를 교체하는 것을 잊지 마십시오.". 파일("/mnt/sdcard/..(."). 그렇지 않으면 FileNotFoundException 이 표시됩니다.

.ProgressDialog가는 길이에요. 게 요.setProgress의 of의 ProgressDialog파일 다운로드 시 진행률 수준을 업데이트하기 위해 호출할 수 있습니다.

많은 앱에서 본 가장 좋은 점은 스톡 버전보다 진행 상황 대화상자의 속성을 더 보기 좋게 커스터마이즈할 수 있다는 것입니다.사용자가 개구리, 코끼리, 귀여운 고양이/강아지 등의 애니메이션에 계속 몰입할 수 있습니다.진행 대화상자가 있는 애니메이션은 사용자를 끌어당겨 오래 기다려야 할 것 같지 않습니다.

개인 조언은 Progress Dialog를 사용하여 실행 전에 빌드업하거나 다음 위치에서 시작하는 것입니다.OnPreExecute()진행률 대화상자의 진행률 막대의 수평 스타일을 사용하는 경우 진행률을 게시하는 경우가 많습니다. 남은 은 '하는 것'입니다.doInBackground.

Android Query 。 바꿀 수 요.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  
        } 
    }
});

cotlin에서 파일을 다운로드 할 때 coroutine과 work manager를 사용할 수 있습니다.

build.gradle에 종속성을 추가합니다.

    implementation "androidx.work:work-runtime-ktx:2.3.0-beta01"
    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.1"

Work Manager 클래스

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

작업 클래스의 작업 관리자를 통해 다운로드 시작

 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

                                    }
                                }
                            }
                        }
                    })

        }

권한

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

Http 사용URL 접속

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

import android.app.Activity;
import android.app.Dialog;
import android.os.Bundle;
import android.os.Environment;
import android.view.View;
import android.view.Window;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;

public class DownloadFileUseHttpURLConnection extends Activity {

ProgressBar pb;
Dialog dialog;
int downloadedSize = 0;
int totalSize = 0;
TextView cur_val;
String dwnload_file_path =  
"http://coderzheaven.com/sample_folder/sample_file.png";
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    Button b = (Button) findViewById(R.id.b1);
    b.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {
             showProgress(dwnload_file_path);

                new Thread(new Runnable() {
                    public void run() {
                         downloadFile();
                    }
                  }).start();
        }
    });
}

void downloadFile(){

    try {
        URL url = new URL(dwnload_file_path);
        HttpURLConnection urlConnection = (HttpURLConnection)   
 url.openConnection();

        urlConnection.setRequestMethod("GET");
        urlConnection.setDoOutput(true);

        //connect
        urlConnection.connect();

        //set the path where we want to save the file           
        File SDCardRoot = Environment.getExternalStorageDirectory(); 
        //create a new file, to save the downloaded file 
        File file = new File(SDCardRoot,"downloaded_file.png");

        FileOutputStream fileOutput = new FileOutputStream(file);

        //Stream used for reading the data from the internet
        InputStream inputStream = urlConnection.getInputStream();

        //this is the total size of the file which we are downloading
        totalSize = urlConnection.getContentLength();

        runOnUiThread(new Runnable() {
            public void run() {
                pb.setMax(totalSize);
            }               
        });

        //create a buffer...
        byte[] buffer = new byte[1024];
        int bufferLength = 0;

        while ( (bufferLength = inputStream.read(buffer)) > 0 ) {
            fileOutput.write(buffer, 0, bufferLength);
            downloadedSize += bufferLength;
            // update the progressbar //
            runOnUiThread(new Runnable() {
                public void run() {
                    pb.setProgress(downloadedSize);
                    float per = ((float)downloadedSize/totalSize) *     
                    100;
                    cur_val.setText("Downloaded " + downloadedSize +  

                    "KB / " + totalSize + "KB (" + (int)per + "%)" );
                }
            });
        }
        //close the output stream when complete //
        fileOutput.close();
        runOnUiThread(new Runnable() {
            public void run() {
                // pb.dismiss(); // if you want close it..
            }
        });         

    } catch (final MalformedURLException e) {
        showError("Error : MalformedURLException " + e);        
        e.printStackTrace();
    } catch (final IOException e) {
        showError("Error : IOException " + e);          
        e.printStackTrace();
    }
    catch (final Exception e) {
        showError("Error : Please check your internet connection " +  
e);
    }       
}

void showError(final String err){
    runOnUiThread(new Runnable() {
        public void run() {
            Toast.makeText(DownloadFileDemo1.this, err,  
      Toast.LENGTH_LONG).show();
        }
    });
}

void showProgress(String file_path){
    dialog = new Dialog(DownloadFileDemo1.this);
    dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
    dialog.setContentView(R.layout.myprogressdialog);
    dialog.setTitle("Download Progress");

    TextView text = (TextView) dialog.findViewById(R.id.tv1);
    text.setText("Downloading file from ... " + file_path);
    cur_val = (TextView) dialog.findViewById(R.id.cur_pg_tv);
    cur_val.setText("Starting download...");
    dialog.show();

     pb = (ProgressBar)dialog.findViewById(R.id.progress_bar);
     pb.setProgress(0);
            pb.setProgressDrawable(
      getResources().getDrawable(R.drawable.green_progress));  
  }
}

Android Query는 매우 크고 유지보수가 되지 않아 현재 사용하고 있는 다른 솔루션에 대한 답변을 추가합니다.그래서 https://github.com/amitshekhariitbhu/Fast-Android-Networking으로 이동했습니다.

    AndroidNetworking.download(url,dirPath,fileName).build()
      .setDownloadProgressListener(new DownloadProgressListener() {
        public void onProgress(long bytesDownloaded, long totalBytes) {
            bar.setMax((int) totalBytes);
            bar.setProgress((int) bytesDownloaded);
        }
    }).startDownload(new DownloadListener() {
        public void onDownloadComplete() {
            ...
        }

        public void onError(ANError error) {
            ...
        }
    });

LiveData 및 Coroutines를 사용하여 다운로드 매니저의 진행 상황을 관찰할 수 있습니다.아래의 요지를 참조해 주세요.

https://gist.github.com/FhdAlotaibi/678eb1f4fa94475daf74ac491874fc0e

data class DownloadItem(val bytesDownloadedSoFar: Long = -1, val totalSizeBytes: Long = -1, val status: Int)

class DownloadProgressLiveData(private val application: Application, private val requestId: Long) : LiveData<DownloadItem>(), CoroutineScope {

    private val downloadManager by lazy {
        application.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
    }

    private val job = Job()

    override val coroutineContext: CoroutineContext
        get() = Dispatchers.IO + job

    override fun onActive() {
        super.onActive()
        launch {
            while (isActive) {
                val query = DownloadManager.Query().setFilterById(requestId)
                val cursor = downloadManager.query(query)
                if (cursor.moveToFirst()) {
                    val status = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS))
                    Timber.d("Status $status")
                    when (status) {
                        DownloadManager.STATUS_SUCCESSFUL,
                        DownloadManager.STATUS_PENDING,
                        DownloadManager.STATUS_FAILED,
                        DownloadManager.STATUS_PAUSED -> postValue(DownloadItem(status = status))
                        else -> {
                            val bytesDownloadedSoFar = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR))
                            val totalSizeBytes = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES))
                            postValue(DownloadItem(bytesDownloadedSoFar.toLong(), totalSizeBytes.toLong(), status))
                        }
                    }
                    if (status == DownloadManager.STATUS_SUCCESSFUL || status == DownloadManager.STATUS_FAILED)
                        cancel()
                } else {
                    postValue(DownloadItem(status = DownloadManager.STATUS_FAILED))
                    cancel()
                }
                cursor.close()
                delay(300)
            }
        }
    }

    override fun onInactive() {
        super.onInactive()
        job.cancel()
    }

}

중요한

Android 11에서는 AsyncTask가 권장되지 않습니다.

상세한 것에 대하여는, 다음의 투고를 확인해 주세요.

구글의 제안대로 concorency Framework로 이행해야 할 것 같다.

    private class DownloadTask extends AsyncTask<String, Integer, String> {

        private PowerManager.WakeLock mWakeLock;
        String onlinePathBundle, onlinePathMusic, offlinePathBundle, offlinePathMusic;

        CircleProgressBar progressBar;
        RelativeLayout rl_progress;
        ImageView btn_download;
        TextView tv_progress;

        public DownloadTask(String onlinePathBundle, String onlinePathMusic, String offlinePathBundle, String offlinePathMusic, CircleProgressBar progressBar, RelativeLayout rl_progress, ImageView btn_download,
                            TextView tv_progress) {
            this.offlinePathBundle = offlinePathBundle;
            this.offlinePathMusic = offlinePathMusic;
            this.progressBar = progressBar;
            this.rl_progress = rl_progress;
            this.btn_download = btn_download;
            this.tv_progress = tv_progress;
            this.onlinePathBundle = onlinePathBundle;
            this.onlinePathMusic = onlinePathMusic;
        }

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            progressBar.setMax(100);
            rl_progress.setVisibility(View.VISIBLE);
            btn_download.setVisibility(View.GONE);

            PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
            mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, getClass().getName());
            mWakeLock.acquire();
        }

        @Override
        protected String doInBackground(String... sUrl) {
            String firstResult = downTask(onlinePathBundle, 1, offlinePathBundle);
            String seondResult = downTask(onlinePathMusic, 2, offlinePathMusic);
            if (firstResult != null) {
                Toast.makeText(SplashActivity.this, "Download error: " + firstResult, Toast.LENGTH_LONG).show();
                return firstResult;
            } else {
                return seondResult;
            }

        }

        @Override
        protected void onProgressUpdate(Integer... progress) {
            super.onProgressUpdate(progress);
            progressBar.setProgress(progress[0]);
            tv_progress.setText(progress[0] + "%");

        }

        @Override
        protected void onPostExecute(String result) {
            super.onPostExecute(result);
            rl_progress.setVisibility(View.GONE);
            btn_download.setVisibility(View.VISIBLE);
            if (result != null) {
                Toast.makeText(SplashActivity.this, "Download error: " + result, Toast.LENGTH_LONG).show();
            } else {
                rl_progress.setVisibility(View.GONE);
                btn_download.setVisibility(View.GONE);
            }

        }

        public String downTask(String onlineNewPath, int numberOfTask, String offlineNewPath) {
            InputStream input = null;
            OutputStream output = null;
            HttpURLConnection connection = null;
            try {
                URL url = new URL(onlineNewPath);
                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(offlineNewPath);

                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
                        if (numberOfTask == 1) {
                            publishProgress((int) (total * 50 / fileLength));
                        } else if (numberOfTask == 2) {
                            publishProgress(((int) (total * 50 / fileLength)) + 50);
                        }

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

언급URL : https://stackoverflow.com/questions/3028306/download-a-file-with-android-and-showing-the-progress-in-a-progressdialog

반응형