Giter Site home page Giter Site logo

tonyofrancis / fetch Goto Github PK

View Code? Open in Web Editor NEW
1.6K 1.6K 319.0 3.3 MB

The best file downloader library for Android

Home Page: https://www.meta.stackoverflow.com/tags/fetch2

License: Apache License 2.0

Java 60.74% Kotlin 39.26%
android android-development android-library android-tv app application downloader downloadmanager fast-networking filedownloader filemanager gradle http httpurlconnection internet internet-of-things mobile networking okhttp retrofit

fetch's People

Contributors

alexstarc avatar alvince avatar befora avatar dougkeen avatar ioltean avatar marcin-adamczewski avatar mikedawson avatar nitishgadangi avatar stustirling avatar thib-rdr avatar tonyofrancis avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

fetch's Issues

How does Fetch notifty the app about file already present

Hi @tonyofrancis ,

I want that my app should be notified by fetch if the requested file already exists.
I tried in the listener to get it notified, but couldn't.

I used Fetch.ERROR_ENQUEUE_ERROR and Fetch.ERROR_FILE_ALREADY_CREATED but couldn't get any response from fetch.

Any idea ?

Thanks,

How can I download a file that has already been downloaded?

For example, the user downloaded a file and then deleted it from the sdcard. In the future, he wants to download the file again, but Fetch throws the exception:
EnqueueException: DatabaseHelper already containsFilePath a request with the filePath: [...]

Is there a way to force the download?

Thanks for lib!

Need a "get" method that accepts several download IDs

It appears that Fetch is lacking a method that allows you to query for a list of download IDs. Would you be opposed to adding a method that looks like this:

public synchronized List<RequestInfo> get(long... ids)?

Scalability issues with a large amount of downloads

There are several issues I've encountered while trying to see if this library would scale for a large amount of downloads. I've tried enqueueing 500+ downloads at once and there are a few major issues. Doing this takes several seconds and causes noticeable lag in the UI.

  1. Even in a transaction, executing multiple queries is much more expensive than executing a single query. When inserting multiple rows, for example, it is much more efficient to do something like INSERT INTO TABLE VALUES (A, B, C), (D, E, F) than performing two insert statements in a transaction.
  2. containsFilePath is executed for each inserted row and it executes a query of its own. If the file path column was set to be UNIQUE you could catch SQLiteConstraintException and handle duplicate inserts much more efficiently.
  3. Cursors aren't closed correctly in some cases. Whenever you have cursor.close() in a try block, the cursor isnt closed if an exception happens. cursor.close() should always be in a finally block.

I've made a bunch of changes locally to remedy this situation but at this point the codebase has changed so much it would be difficult to port them back. I'm willing to do it, however, if you'd like help with these things.

fetch view is reducing it size with weight.

What I see is, When I use weight for height of fetch view. it is reducing its size,I will try to explain with the help of an example.
Please do visit this link .

As I have used the main views as "Linear layout" with "weight_sum=2", and two views one is video_view and the other is textview. I am using weight for making both views of equal height. but when I run the application, video_view(your fetch view) is reducing its size. For knowing it better I have set background color to green and textview color to blue.

Here is the below code what I have used in xml.

<fm.jiecao.jcvideoplayer_lib.JCVideoPlayerStandard
    android:id="@+id/MyVideoPlayer"
    android:layout_width="match_parent"
    android:layout_height="0dp"
    android:layout_weight="1"
    android:keepScreenOn="true" />

<TextView
    android:layout_width="match_parent"
    android:layout_height="0dp"
    android:layout_weight="1"
    android:background="#4fa0ab"
    android:gravity="center"
    android:text="TextView Area" />

Progress

Great, thanks. I have a question:
How to display progress of number of bytes download and % of data download ?

Progress and filesize issues

Scenario:
The file is being downloaded:

D/ fetchDebug: id:30547713379280,status:901,progress:25,error:-1
I/ fetchDebug: id: 30547713379280 downloadedBytes: 7428602 / fileSize: 29189424

Then I pause the download and close the application.
Progress and filesize are calculated incorrectly when I reopen the application and resume it.

D/ fetchDebug: id:30547713379280,status:901,progress:100,error:-1
I/ fetchDebug: id: 30547713379280 downloadedBytes: 22283153 / fileSize: 13935572

How to check if file already exists ?

Hey Tony !
You're very helpful so far,I want to check if the downloading file already exists or not ? Is there any method ? If exists do share with me .

On devices lower than Android 6.0

Hello,

Marshmallow does not download on low-end devices

Status = 905 in log output

`public class SingleDownloadActivity extends AppCompatActivity implements FetchListener {

private static final int STORAGE_PERMISSION_CODE = 100;

private View rootView;
private TextView progressTextView;
private TextView titleTextView;

private long downloadId = -1;
private Fetch fetch;
private  String url,path,fname;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_single_download);

    rootView = findViewById(R.id.activity_single_download);
    progressTextView = (TextView) findViewById(R.id.progressTextView);
    titleTextView = (TextView) findViewById(R.id.titleTextView);


    Bundle extras = getIntent().getExtras();
    url = extras.getString("url");
    path = extras.getString("path");
    fname = extras.getString("name");
    fetch = Fetch.getInstance(this);
    clearAllDownloads();
}

@Override
protected void onResume() {
    super.onResume();

    if(downloadId != -1) {

        RequestInfo info = fetch.get(downloadId);

        if (info != null) {
            setProgressView(info.getStatus(),info.getProgress());
        }

        fetch.addFetchListener(this);
    }
}

@Override
protected void onPause() {
    super.onPause();
    fetch.removeFetchListener(this);
}

@Override
protected void onDestroy() {
    super.onDestroy();
    fetch.release();
}

/*Removes all downloads managed by Fetch*/
private void clearAllDownloads() {

    fetch.removeAll();
    createRequest();
}

private void createRequest() {

    if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
    {

        requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}
                ,STORAGE_PERMISSION_CODE);
    }else
    {
        enqueueDownload();
    }
}

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {

    if(requestCode == STORAGE_PERMISSION_CODE || grantResults.length > 0
            && grantResults[0] == PackageManager.PERMISSION_GRANTED) {

        enqueueDownload();

    }else {
        Snackbar.make(rootView,R.string.permission_not_enabled,Snackbar.LENGTH_LONG).show();
    }
}

private void enqueueDownload() {

    Request request = new Request(url,path,fname);

    downloadId = fetch.enqueue(request);

    setTitleView(request.getFilePath());
    setProgressView(Fetch.STATUS_QUEUED,0);
}

@Override
public void onUpdate(long id, int status, int progress, long downloadedBytes, long fileSize, int error) {

    if(id == downloadId) {

        if(status == Fetch.STATUS_ERROR) {

            showDownloadErrorSnackBar(error);

        }else {

            setProgressView(status,progress);
        }
    }
}

private void setTitleView(String fileName) {

    Uri uri = Uri.parse(fileName);
    titleTextView.setText("yükleniyor");
}

private void setProgressView(int status,int progress) {


    switch (status) {

        case Fetch.STATUS_QUEUED : {
            progressTextView.setText(R.string.queued);
            break;
        }
        case Fetch.STATUS_DOWNLOADING :
        case Fetch.STATUS_DONE : {

            if(progress == -1) {

                progressTextView.setText(R.string.downloading);
            }else {

                String progressString = getResources()
                        .getString(R.string.percent_progress,progress);

                progressTextView.setText(progressString);
            }
            finish();
            break;
        }
        default: {
            Log.d("SingleDownloadActivity",status + "asd");
            progressTextView.setText(R.string.status_unknown);
            break;
        }
    }
}

private void showDownloadErrorSnackBar(int error) {

    final Snackbar snackbar = Snackbar.make(rootView,"Download Failed: ErrorCode: "
            + error,Snackbar.LENGTH_INDEFINITE);

    snackbar.setAction(R.string.retry, new View.OnClickListener() {
        @Override
        public void onClick(View v) {

            fetch.retry(downloadId);
            snackbar.dismiss();
        }
    });

    snackbar.show();
}`

Not able to download redirected url in android version 4.4(Kitkat)

It is not downloading form redirected links, as I am using Vimeo video for download, As the first links which Vimeo provides is an "https url" and later it changes to "http url" . Here I am proving a vimeo link from which am trying to download a video,

https://player.vimeo.com/play/720138981?s=210197530_1494265285_b46e1ab154e0464a03760f8805892af8&loc=external&context=Vimeo%5CController%5CApi%5CResources%5CUser%5CVideoController.&download=1&filename=Untitledsource.mp4

You can use the link to download the file in browser and it is downloading fine. And if you check the downloading url, it is an http url.

So, what I have to do to download, this kind of files.

onupdate never called

i just simple implemented this lib as u suggested but on update never be called you can see below code ... and if u might wud say to fetch.release().. so i t also didn't work

`public void fetchMethod(String url, String fileName) {
        Toast.makeText(DownloadService.this, "downloading started", Toast.LENGTH_SHORT).show();
        File file = new File(Environment.getExternalStorageDirectory(), File.separator + getString(R.string.app_name));
        if (!file.exists()) {
            file.mkdirs();
        }
        new Fetch.Settings(getApplicationContext())
                .setAllowedNetwork(Fetch.NETWORK_ALL)
                .enableLogging(true)
                .setConcurrentDownloadsLimit(3)
                .apply();
        Fetch fetch = Fetch.getInstance(this);
        Log.e("check", file.getAbsolutePath() + " " + fileName);
        Request request = new Request(url, file.getAbsolutePath(), File.separator + fileName);
        final long downloadId = fetch.enqueue(request);
        fetch.addFetchListener(new FetchListener() {

            @Override
            public void onUpdate(long id, int status, int progress, long downloadedBytes, long fileSize, int error) {

                if (downloadId == id && status == Fetch.STATUS_DOWNLOADING) {
                    Toast.makeText(DownloadService.this, "downloading   " + progress, Toast.LENGTH_SHORT).show();
                } else {
                    Toast.makeText(DownloadService.this, "no file" + progress, Toast.LENGTH_SHORT).show();
                }
            }
        });
    }`

`getInstance` method name is a misnomer

The getInstance method with a context parameter implies there is a single instance of Fetch per context. If you support multiple instances per context (which you do), you may want to consider renaming the method to newInstance. See item 1 in Effective Java for the naming conventions for static factory methods.

How to remove task, but remain file downloaded

I count number of files currently downloading and if 1 of them is done, i call fetch.get().size() to update count. But that size remains the same and fetch.remove(id) deletes downloaded file eather. Something like removeTask(id) possible?

getProgress() and getDownloadedBytes() issues

Scenario 2:
The file is being downloaded.
https://archive.org/download/Mozart_347/05.mp3

D/fetchDebug: id:165363055600,status:901,progress:5,error:-1
I/fetchDebug: id: 165363055600 downloadedBytes: 1875132 / fileSize: 17487404
D/fetchDebug: id:165363055600,status:901,progress:6,error:-1
I/fetchDebug: id: 165363055600 downloadedBytes: 2207640 / fileSize: 17487404
D/fetchDebug: id:165363055600,status:901,progress:7,error:-1
I/fetchDebug: id: 165363055600 downloadedBytes: 2585160 / fileSize: 17487404

.......

Then I pause the download, progress and downloadedBytes values are set to 0.

D/fetchDebug: id:165363055600,status:902,progress:0, error:-1
I/fetchDebug: id: 165363055600 downloadedBytes: 0 / fileSize: 17487404

When I pause, I want to show the last updated values in the download.

Configuration Problem

The build.gradle is configured and during rebuild gives the following errors:

/Users/shoaibrafa/AndroidStudioProjects/AppSaraaiV3/app/build/intermediates/res/merged/debug/values-v24/values-v24.xml
Error:(3) Error retrieving parent for item: No resource found that matches the given name 'android:TextAppearance.Material.Widget.Button.Borderless.Colored'.
Error:(4) Error retrieving parent for item: No resource found that matches the given name 'android:TextAppearance.Material.Widget.Button.Colored'.
Error:(3) Error retrieving parent for item: No resource found that matches the given name 'android:TextAppearance.Material.Widget.Button.Borderless.Colored'.
Error:(4) Error retrieving parent for item: No resource found that matches the given name 'android:TextAppearance.Material.Widget.Button.Colored'.
Error:Execution failed for task ':app:processDebugResources'.

com.android.ide.common.process.ProcessException: Failed to execute aapt

Exception download exception

com.tonyodev.fetch.exception.DownloadInterruptedException: DIE
at com.tonyodev.fetch.FetchRunnable.run(FetchRunnable.java:128)
at java.lang.Thread.run(Thread.java:856)

In sample when i am start single download getting this exception.

How to re download file?

Hi,

Nice fetcher by the way I have an error:
com.tonyodev.fetch.exception.EnqueueException: DatabaseHelper already containsFilePath a request with the filePath:

How can I re download file using this fetcher? thanks

When kill App. Downloading stop.

Hi,

I have download long file it is download but when app kill in background download stoped. and it is not a store in database.

Thanks

Possibility to change the download URL when it expires

Hello, i would like to use this library into my project, but i have one problem.
I have download URL with expiration time, and when user pause download, expiration time is over, and user want to resume download, fetcher give me STATUS_ERROR, that is fine.
My ask is: is there any possibility to change download URL to continue download file with different download link?
Because for now i can't continue download, i need to remove request and starts again, losing proviously dowloaded part of the file.

Design for supporting multiple downloads

Hi @tonyofrancis ,

I wanted help in designing the feature to support multiple downloads in my application.
How do I go about updating progress for each download in same notification ?

I have been thinking of showing something like 1 of 4 in progress in the notification and then when 1 completes update the notification as 2 of 4 in progress.

Any idea on this of what should be the efficient design for this feature and have good user experience ?

FetchService is running always in backgound?

i have noticed that after calling fetch.release(); method on fetch instance the FetchService is not stop it is running forever even if not downloading anything. did i need to do anything else to stop this service.

update issue

I'm trying to download a video from a URL:
http://www.sample-videos.com/video/mp4/720/big_buck_bunny_720p_2mb.mp4

progres and fileSize not updating while downloading a file.

D/fetchDebug: id:237955074420,status:901,progress:0,error:-1
I/fetchDebug: id: 237955074420 downloadedBytes: 444171 / fileSize: -1
D/fetchDebug: id:237955074420,status:901,progress:0,error:-1
I/fetchDebug: id: 237955074420 downloadedBytes: 744735 / fileSize: -1
D/fetchDebug: id:237955074420,status:901,progress:0,error:-1
I/fetchDebug: id: 237955074420 downloadedBytes: 1087407 / fileSize: -1
D/fetchDebug: id:237955074420,status:901,progress:0,error:-1
I/fetchDebug: id: 237955074420 downloadedBytes: 1637715 / fileSize: -1
......

error in verbose

com.tonyodev.fetch.exception.EnqueueException: DatabaseHelper already containsFilePath a request with the filePath:

multi-task downloads

Start another file after it finishes downloading one. How do I start multiple file downloads at the same time?

Onupdate() method is not calling in fetch.addListner

Fetch fetch = Fetch.getInstance(MainActivity.this);
String dateString = new Date().toString();
       
Request request = new Request("http://androhub.com/demo/demo.mp4",Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).toString()+"/"+dateString+"_demo.mp4");
        
final long downloadId = fetch.enqueue(request);
        
fetch.addFetchListener(new FetchListener() {
            @Override
            public void onUpdate(long id, int status, int progress, int error) {

               //This log is not visible in android monitor 
               
               Log.d("fetchDebug","id:" + id + ",status:" + status + ",download percentage:" + progress
                        + ",error:" + error);
            }
 });

`FetchConst` should probably be public

When you query the status of a download, you get a RequestInfo object that has a status value which is an integer that corresponds to the status codes in FetchConst. However, since FetchConst is not public, there is no way to to perform logic on the status unless the client app hard codes those values.

Get the List of all queued requests

Hi @tonyofrancis
This is one of the awesome library I have seen so far, very easy to user, very light weight and well documented.
I just have one question, how do I get the list of queued requests ?

Thanks for your help 😄

DownloadId

My downloadId = -1 what is the reason please help me asap .

Fetch fetch = Fetch.getInstance(MainActivity.this);
Request request = new Request("http://androhub.com/demo/demo.mp4", Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).toString();

final long downloadId = fetch.enqueue(request);

fetch.addFetchListener(new FetchListener() {
            @Override
            public void onUpdate(long id, int status, int progress, int error) {
                if(downloadId== id){
                    progressDialog.setProgress(progress);
                    Log.d("TAG",String.valueOf(progress));
                    if(progress>=100){
                        progressDialog.dismiss();
                    }
                }

            }
});

//Log.d("TAG",fetch.getFilePath(downloadId).toString());
fetch.release();

Cofiguratin problem

The build.gradle is configured and during rebuild gives the following errors:

/Users/shoaibrafa/AndroidStudioProjects/MyApp/app/build/intermediates/res/merged/debug/values-v24/values-v24.xml
Error:(3) Error retrieving parent for item: No resource found that matches the given name 'android:TextAppearance.Material.Widget.Button.Borderless.Colored'.
Error:(4) Error retrieving parent for item: No resource found that matches the given name 'android:TextAppearance.Material.Widget.Button.Colored'.
Error:(3) Error retrieving parent for item: No resource found that matches the given name 'android:TextAppearance.Material.Widget.Button.Borderless.Colored'.
Error:(4) Error retrieving parent for item: No resource found that matches the given name 'android:TextAppearance.Material.Widget.Button.Colored'.
Error:Execution failed for task ':app:processDebugResources'.

com.android.ide.common.process.ProcessException: Failed to execute aapt

Progress

Hi , I Keep logging the progress amount but it will not go up to 100 but the files is already downloaded

Wrong progress when downloading big files (Tested with 4.2 GB file)

httpURLConnection.getContentLenght() is not working correct when the file is bigger than the Integer.MAX_VALUE. In this case it will return -1 and I guess that's why the progress you return will always be 0%.

An option to fix this issue would be to get the content length directly from the headers and convert it to long:

Long.valueOf(connection.getHeaderField("Content-Length"))

instead of:

private void setContentLength() {
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
fileSize = downloadedBytes + httpURLConnection.getContentLengthLong();
} else {
fileSize = downloadedBytes + httpURLConnection.getContentLength();
}
}

Concurrent download limit problems

If you try to set the download limit to something that is above FetchConst.MAX_DOWNLOADS_LIMIT, the method silently sets the value to the default value, which is 1.

This is problematic partially because MAX_DOWNLOADS_LIMIT isn't public, so you're relying on the developer to use second hand knowledge to not call that method with a value greater than 7.

Why is there a hard coded limit to how many files can be downloaded concurrently? Is the number 7 chosen arbitrarily or based on some data? I would much prefer if you laid out a recommendation for the maximum number of downloads in the documentation but allow the developer to use whatever number they choose.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.