Как остановить AsyncFacebookRunner или вообще остановить запрос?

У меня есть AsyncFacebookRunner который загружает изображение в Facebook. Я хочу создать кнопку отмены, которая остановит загрузку.

Как можно этого достичь?

РЕДАКТИРОВАТЬ:

Вот как я это использую:

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);

3 ответа

Решение

Вы всегда можете продлить AsyncFacebookRunner класс и переопределить request метод.
Что-то вроде этого:

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();
    }
}

Это не было проверено, но должно дать вам общее представление.


редактировать

Теперь, когда я думаю об этом, это не имеет большого смысла, так как вы хотите использовать AsyncFacebookRunner сделать несколько запросов и cancel отменит только последний запрос.

Я бы предложил вернуть поток, а затем иметь возможность перехватить его где-то еще, но вы не можете изменить сигнатуру метода, как этот, и создание нового метода не позволит использовать другие request методы, определенные в AsyncFacebookRunner учебный класс.

Вместо этого вы можете сделать что-то вроде:

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();
        }
    }
}

Вам нужно как-то сгенерировать идентификатор для запроса, может быть что-то простое, например:

String.valueOf(System.currentTimeMillis());

Вы можете сделать что-то вроде этого:

AsyncFacebookRunner fbRunner;

@Override
public void onClick(View v){
    fbRunner.cancel(true);
}

Вызов этого также не вызовет onPostExecute(Object), поэтому вы должны принять это к сведению

http://developer.android.com/reference/android/os/AsyncTask.html)

Это может быть не элегантным решением, но вы можете прервать поток AsyncFacebookRunner использует, обработайте полученное исключение и корректно отмените связь.

В качестве альтернативы вы могли бы рассмотреть возможность разветвления из репозитория и добавления собственного метода отмены в код?

РЕДАКТИРОВАТЬ

Посмотри как AsyncTask реализовано в репозитории исходного кода Google. По сути, вы должны иметь возможность вызывать метод из любого потока, который устанавливает отмененный флаг, обычно это

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;
}

Когда вы отменяете задачу, ваш метод установит для нее значение true, и вы будете регулярно проверять его AsyncFacebookRunner нить.

Другие вопросы по тегам