2

So I'm trying to download a huge file. So naturally my first step is to open the stream

RNFetchBlob.RCTContext.getContentResolver().openInputStream(Uri.parse(fromUri));

My problem is that this instead of working quickly and just opening the stream, it in fact downloads the thing in the background. How do I know? Well this command blocks for like 5 minutes and then when I read from the stream, it's instantaneous.

Could I make this action prevent from download in the background? I want to inform the user about the progress and not just wait.

Edit: to make clear, I'm using a content:// URI for the resource

Novellizator
  • 13,633
  • 9
  • 43
  • 65
  • Found any solution? I got the same problem while importing 116MB File from GDrive - my app "stalls" on openInputStream. I may start a thread for this but who knows if that call ever finishes. – coyer Mar 04 '20 at 09:15

2 Answers2

1

This is a wrong method to read a file over the network, you need to use network-specific methods.

HttpURLConnection request = 
    (HttpURLConnection)(new URL(Uri.parse(fromUri)).openConnection());
// Connect to the server, expect a delay and draw a progress bar
request.connect();
// This will read HTTP headers with content length, expect another delay
// Must be called before request.getContentLength()
request.getInputStream();
// Get the size of your file, to draw your progress bar properly
long total = request.getContentLength();
// Now you can finally start reading the data
InputStream input = request.getInputStream();
pelya
  • 4,326
  • 2
  • 24
  • 23
  • thanks, going to try! one minor thing - my URI is a content:// thing, hopefully it works for that as well :) – Novellizator Nov 15 '18 at 15:09
  • That would be a problem, `HttpURLConnection` only handles `http://` and `https://` URIs. You cannot do that with `content://` URI, it is downloaded by the content provider code, not by your app code, and the app cannot control the download progress. – pelya Nov 15 '18 at 15:13
  • so there's no way to get the download progress and no one in the android community complained about that? (I googled quite extensively) – Novellizator Nov 15 '18 at 15:15
0

For long-running HTTP downloads you can use DownloadManager and show download progress e.g. like in this question of Victor Laerte:

    String urlDownload = <YOUR_URL>;
    DownloadManager.Request request = new DownloadManager.Request(Uri.parse(urlDownload));

    request.setDescription("Testando");
    request.setTitle("Download");
    request.allowScanningByMediaScanner();
    request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
    request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS,"teste.zip");

    final DownloadManager manager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);

    final long downloadId = manager.enqueue(request);

    final ProgressBar mProgressBar = (ProgressBar) findViewById(R.id.progressBar1);

    new Thread(new Runnable() {

        @Override
        public void run() {

            boolean downloading = true;

            while (downloading) {

                DownloadManager.Query q = new DownloadManager.Query();
                q.setFilterById(downloadId);

                Cursor cursor = manager.query(q);
                cursor.moveToFirst();
                int bytes_downloaded = cursor.getInt(cursor
                        .getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR));
                int bytes_total = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES));

                if (cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS)) == DownloadManager.STATUS_SUCCESSFUL) {
                    downloading = false;
                }

                final int dl_progress = (int) ((bytes_downloaded * 100l) / bytes_total);

                runOnUiThread(new Runnable() {

                    @Override
                    public void run() {

                        mProgressBar.setProgress((int) dl_progress);

                    }
                });

                Log.d(Constants.MAIN_VIEW_ACTIVITY, statusMessage(cursor));
                cursor.close();
            }

        }
    }).start();
Andrii Omelchenko
  • 13,183
  • 12
  • 43
  • 79
  • hello, just making sure, will that work for content:// addresses? – Novellizator Nov 15 '18 at 15:16
  • Seems `DownloadManager` [content:// frendly](https://blog.stylingandroid.com/downloadmanager-part-1/): *The important thing which facilitates that is the Uri that DownloadManager returns is actually a content://... Uri which is very friendly to other apps andf allows them to easily access the content through as `ContentProvider` provided by `DownloadManager`*. – Andrii Omelchenko Nov 15 '18 at 15:22
  • @Novellizator Also take a look at [this](https://stackoverflow.com/q/30671548/6950238) and [that](https://stackoverflow.com/q/14798569/6950238) questions and answers. – Andrii Omelchenko Nov 15 '18 at 15:28
  • So in the end it looks like it's not that easy. tried your approach, and got: `java.lang.IllegalArgumentException: Can only download HTTP/HTTPS URIs: content://com.google.android.apps.docs.storage/document/acc%3D2%3Bdoc%3D43` – Novellizator Nov 15 '18 at 16:14
  • @Novellizator What is your `fromUri` kind? – Andrii Omelchenko Nov 15 '18 at 20:30
  • retrieved from pile pickers when getting the google drive document – Novellizator Nov 16 '18 at 12:52