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:

  • Creating integer array of resource IDs
  • Android: Issue with acceptable file types via bluetooth
  • A good tutorial for using AccountManager in Android?
  • Genymotion devices not working in Eclipse on OS X Yosemite
  • getWidth() and getHeight() always returning 0. Custom view
  • Difference between “onMenuItemSelected” and “onOptionsItemSelected”
  • 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.
    

  • Android Studio Error: “You must install the Android Support Repository though the SDK Manager”
  • Custom view constructor does not get called on android 5.0.2
  • Browse SQLite database from Android Studio
  • PhoneGap Android get the app version code
  • Setting Request Priority Volley
  • Extrakting Zip to SD-Card is very slow. How can i optimize performance?
  • 2 Solutions collect form web for “ParseFile.cancel() not working – file keeps being downloaded”

    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.

    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.

    Android Babe is a Google Android Fan, All about Android Phones, Android Wear, Android Dev and Android Games Apps and so on.