问题
I have an AsyncFacebookRunner
that uploads an image to Facebook. I want to create a cancel button that will stop the download.
How can one achieve that?
EDIT:
This is how I use it:
byte[] data = null;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);
data = baos.toByteArray();
Bundle params = new Bundle();
params.putByteArray("picture", data);
AsyncFacebookRunner mAsyncRunner = new AsyncFacebookRunner(facebook);
mAsyncRunner.request("me/photos", params, "POST",
new PhotoUploadListener(dialog), null);
回答1:
You can always extend the AsyncFacebookRunner
class and override the request
method.
Something like this:
public class CancelableAsyncFacebookRunner extends AsyncFacebookRunner {
private Thread requestThread;
public AsyncFacebookRunner(Facebook fb) {
super(fb);
}
@Override
public void request(final String graphPath,
final Bundle parameters,
final String httpMethod,
final RequestListener listener,
final Object state) {
this.requestThread = new Thread() {
@Override
public void run() {
try {
String resp = fb.request(graphPath, parameters, httpMethod);
listener.onComplete(resp, state);
} catch (FileNotFoundException e) {
listener.onFileNotFoundException(e, state);
} catch (MalformedURLException e) {
listener.onMalformedURLException(e, state);
} catch (IOException e) {
listener.onIOException(e, state);
}
}
};
}
public void cancel() {
this.requestThread.interrupt();
}
}
It hasn't been tested, but should give you the general idea.
Edit
Now that I think about it, this makes little sense, since you want to use the AsyncFacebookRunner
to make multiple requests and the cancel
will cancel the last request only.
I would suggest returning the thread and then have the ability to interupt it somewhere else, but you can't change the signature of the method like this and creating a new method won't make it possible to use other request
methods defined in the AsyncFacebookRunner
class.
Instead you can do something like:
public class CancelableAsyncFacebookRunner extends AsyncFacebookRunner {
private Hashtable<String, Thread> requestThreads;
public AsyncFacebookRunner(Facebook fb) {
super(fb);
this.requestThreads = new Hashtable<String, Thread>();
}
@Override
public void request(final String id,
final String graphPath,
final Bundle parameters,
final String httpMethod,
final RequestListener listener,
final Object state) {
Thread thread = new Thread() {
@Override
public void run() {
try {
String resp = fb.request(graphPath, parameters, httpMethod);
requestThreads.remove(id);
listener.onComplete(resp, state);
} catch (FileNotFoundException e) {
requestThreads.remove(id);
listener.onFileNotFoundException(e, state);
} catch (MalformedURLException e) {
requestThreads.remove(id);
listener.onMalformedURLException(e, state);
} catch (IOException e) {
requestThreads.remove(id);
listener.onIOException(e, state);
}
}
});
this.requestThreads.put(id, thread);
thread.start();
}
public void cancel(String id) {
if (this.requestThreads.containsKey(id) {
this.requestThreads.get(id).interrupt();
}
}
}
You'll need to generate an id somehow for the request, can be something simple like:
String.valueOf(System.currentTimeMillis());
回答2:
You can do something like this:
AsyncFacebookRunner fbRunner;
@Override
public void onClick(View v){
fbRunner.cancel(true);
}
Calling this will also not invoke onPostExecute(Object) so you need to take note of this
http://developer.android.com/reference/android/os/AsyncTask.html#cancel(boolean)
回答3:
This may not be an elegant solution but you may be able to interrupt the thread the AsyncFacebookRunner
is using, handle the resulting exception and gracefully cancel the comms.
Alternatively would you consider forking from the repository and adding your own cancel method to the code?
EDIT
Look at how AsyncTask
is implemented in the google source repository. Essentially you need to be able to call a method from any thread that sets a cancelled flag, this would normally be a
private volatile boolean cancelled = false;
// volatile ensures you always get up to date value when checking across threads
public void cancel() {
cancelled = true;
}
public boolean isCancelled() {
return cancelled;
}
As you cancel the task your method would set this to true and you would check it at regular intervals from your AsyncFacebookRunner
thread.
来源:https://stackoverflow.com/questions/10984531/how-to-stop-asyncfacebookrunner-or-stop-a-request-in-general