Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ParseFile.cancel() not working - file keeps being downloaded

I'm using parse.com Android SDK to manage some images in my app. Is cancel() the only way to stop a transaction with the parse.com server?

Minimal example:

final ParseFile file = ... ;
file.getDataInBackground(new GetDataCallback() {

    //called when loading is done
    @Override
    public void done(byte[] bytes, ParseException e) {
        Log.e(TAG, String.valueOf(bytes == null));
    }

}, new ProgressCallback() {

    //called to notify progress   
    @Override
    public void done(Integer integer) {
        Log.e(TAG, String.valueOf(integer));
        if (integer > 50) {
            file.cancel();
        }
    }
});

I would expect that loading stops after the 50% is reached, but it does not. My log in this situation would be:

1
2
3
....
49
50
51
....
98
99
100
true

The only difference from times you call cancel() and times you don't, is that if you canceled the byte[] result is null. But that is really secondary, the point here is that file keeps consuming bandwidth and, moreover, overlaps with future downloads, slowing things down.

Is there any way to really stop ParseFile loading? Do you see any workaround, like stopping its thread? Maybe something using the underlying bolts framework? Using my own async task?

Example: continueWhile() method might be useful, but I can't figure out how to use it.


I would like to know the reason for the downvote, maybe the common title? That is really what I am experiencing: ParseFile.cancel() is not working. And it should, according to the official docs.

Comments suggest that I should simply call break. While I don't think it would work, I might clarify that the code I posted was just a minimal, concise working example providing both context and the issue. I don't want to cancel() the transaction from inside the progress callback; I want to call parseFile.cancel() from everywhere. I put in the progress callback to show that, while it should stop, it doesn't.


Edit This is what I'm really trying to do. I have tried different ways but this is it.

ParseFile currentFile;
public void setFile(ParseFile file) {

    if (currentFile != null) {
        currentFile.cancel();
    }

    currentFile = file;
    currentFile.getDataInBackground(new GetDataCallback() {
        ...
    }, new ProgressCallback() {
        ... // logs
    });
}

With such code and say, two big images to download, things go like:

//calling setFile(file1)
1
2
3
...
20
21
22
//calling setFile(file2), thus also calling file1.cancel()
1
2
23 //file1 going on!
3
24
4
25
... //things get slower and this screws up progress bars and such.
like image 480
natario Avatar asked Aug 09 '15 21:08

natario


2 Answers

TL;DR;

The only conclusion I can draw at this point is that there is a difference in our implementations that is causing cancel to fail for you.

EDIT: this seems to be the case as seen in your own answer. The difference being SDK versions. https://stackoverflow.com/a/32034500/2680506

Full Answer:

The description for the cancel() method:

"Cancels the current network request and callbacks whether it's uploading or fetching data from the server."

I was curious about this so I did a little testing of my own. I took my app, made a ParseFile from the bytes of an image and attempted to save it in the background.

Test 1

    Bitmap file = BitmapFactory.decodeResource(context.getResources(), R.drawable.background);
    ByteArrayOutputStream stream = new ByteArrayOutputStream();
    file.compress(Bitmap.CompressFormat.PNG, 100, stream);
    byte[] byteArray = stream.toByteArray();
    final ParseFile myTestFile = new ParseFile(byteArray);
    myTestFile.saveInBackground(new SaveCallback(){

        @Override
        public void done(ParseException e) {
            if(e == null)
            {
                Log.i(null, "Done saving.");
            }

        }

    }, new ProgressCallback(){

        @Override
        public void done(Integer progress) {
            Log.i(null, "Progress at " + progress + "%");
            if(progress > 50)
            {
                myTestFile.cancel();
            }
        }});
    //myTestFile.cancel();

Test 2

    Bitmap file = BitmapFactory.decodeResource(context.getResources(), R.drawable.background);
    ByteArrayOutputStream stream = new ByteArrayOutputStream();
    file.compress(Bitmap.CompressFormat.PNG, 100, stream);
    byte[] byteArray = stream.toByteArray();
    ParseFile myTestFile = new ParseFile(byteArray);
    myTestFile.saveInBackground(new SaveCallback(){

        @Override
        public void done(ParseException e) {
            if(e == null)
            {
                Log.i(null, "Done saving.");
            }

        }

    }, new ProgressCallback(){

        @Override
        public void done(Integer progress) {
            Log.i(null, "Progress at " + progress + "%");
        }});
    myTestFile.cancel();

The results for Test 1 were similar to what you describe, because the file is very small I only got one progress callback at 100% but then it also invoked the SaveCallback.

In Test 2, however, the cancel() method appears to function as one would expect, resulting in no logs or callbacks.

It appears that cancel fails to work because you are calling it from the Callback. This is consistent with the fact that you continue to see ProgressCallbacks after you originally cancel in your own tests.

EDIT

I just uploaded an image and tested cancel for myself, in the onCreate() method of my activity I have this code:

ParseQuery<ParseObject> newQuery = ParseQuery.getQuery("TestObject");
newQuery.findInBackground(new FindCallback<ParseObject>(){
    @Override
    public void done(List<ParseObject> objects, ParseException e)
    {
        ParseFile myTestFile = objects.get(0).getParseFile("file");
        myTestFile.getDataInBackground(new GetDataCallback()
        {
            @Override
            public void done(byte[] data, ParseException e)
            {
                Log.i(null, "Download finished");
            }
        }, 
        new ProgressCallback()
        {

            @Override
            public void done(Integer percentDone)
            {
                Log.i(null, "Download at " + percentDone + "%");
            }
        });
        //myTestFile.cancel();
    }});

When cancel is commented, It will enter the GetDataCallback with a populated byte array. When cancel is not commented no call back will occur. Strangely enough the ProgressCallback is never called although it says it is guaranteed. However, it still appears that cancel is working for me.

like image 113
Dave S Avatar answered Nov 10 '22 17:11

Dave S


Looks like this was a real bug, now fixed. I used to stay with the v1.9.2 release; today I updated to v1.10.0 and everything works fine.

like image 41
natario Avatar answered Nov 10 '22 17:11

natario