【问题标题】:AsyncTask and Queue异步任务和队列
【发布时间】:2023-10-13 21:06:02
【问题描述】:

好的,这是我第一次使用 Java 中的异步和队列,所以代码可能不是最好的......无论如何:

我想编写一个运行 HTTP 请求的 AsyncTask,如果用户在 Async 运行时发送更多请求,它会将请求添加到队列中,然后异步执行每个请求。

private Queue<String> pasteQueue = new LinkedList<String>();
private boolean running = false;

我创建了这个方法来管理每个请求:

public void postPaste(String title, String code, String language, String scadenza, int visibility)
{
    String dev_key = "";
    StringBuilder url = new StringBuilder();

    url.append("http://pastebin.com/api/api_post.php?api_option=paste")
        .append("&api_paste_private=").append(visibility)
        .append("&api_paste_name=").append(title)
        .append("&api_paste_expire_date=").append(scadenza)
        .append("&api_paste_format=").append(language)
        .append("&api_dev_key=").append(dev_key)
        .append("&api_paste_code=").append(code);

    Log.d(MyActivity.DEBUG_TAG, "URL: " + url.toString());

    // Todo: implement api_user_key

    Log.d(MyActivity.DEBUG_TAG, "running == " + running);
    if (running)
    {
        Log.d(MyActivity.DEBUG_TAG, "PASTE added to queue");
        pasteQueue.add(url.toString());
    }
    else
    {
        Log.d(MyActivity.DEBUG_TAG, "Execute async");
        execute(url.toString());
    }
}

为了检查异步是否正在运行,我创建了一个布尔变量(正在运行),当调用 doInBackground 时它设置为“true”,当 onPostExecute 完成时设置为 false。

这是我的 doInBackground 方法:

@Override
protected String doInBackground(String... params) {
    Log.d(MyActivity.DEBUG_TAG, "doInBackground");
    if (params[0] == null)
    {
        return null;
    }

    running = true;
    HttpClient httpClient = new DefaultHttpClient();
    HttpResponse response;
    String finalResponse = null;

    try
    {
        response = httpClient.execute(new HttpGet(params[0]));
        StatusLine statusLine = response.getStatusLine();

        if (statusLine.getStatusCode() == HttpStatus.SC_OK)
        {
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            response.getEntity().writeTo(outputStream);
            outputStream.close();
            finalResponse = outputStream.toString();
        }
        else
        {
            response.getEntity().getContent().close();
        }
    } catch (ClientProtocolException e) {
        // ToDo: Something
    } catch (IOException e) {
        // ToDo: Something
    }

    return finalResponse;  //To change body of implemented methods use File | Settings | File Templates.
}

首先,我检查 params[0] 是否为 null(如果 pasteQueue.poll() 返回 null)然后我运行一个简单的 http 请求..

我放了完整的 doInBackground,因为问题可能出在 HTTP 请求中(我从未在 Android 中使用过 HTTP 函数,是的,我一般是 Android 新手。)

那么,onPosteExecute 就只有这个了:

@Override
protected void onPosteExecute(String s)
{
    Log.d(MyActivity.DEBUG_TAG, "onPostExecute");
    super.onPostExecute(s);    //To change body of overridden methods use File | Settings | File Templates.

    if (pasteQueue.size() > 0)
    {
        Log.d(MyActivity.DEBUG_TAG, "queue.size > 0, poll item");
        execute(pasteQueue.poll());
    }

    running = false;
    Log.d(MyActivity.DEBUG_TAG, "onPostExecute - fine");
}

(我删除了无用的代码)

我使用了一个运行 postPaste 的按钮,如果我再次按下该按钮(调用 onPostExecute),应用程序会因此崩溃:

Caused by: java.lang.IllegalStateException: 无法执行任务:任务已经执行过(一个任务只能执行一次)

11-30 18:06:50.608:错误/AndroidRuntime(2246):致命异常:主要 java.lang.IllegalStateException:无法执行活动的方法 在 android.view.View$1.onClick(View.java:3599) 在 android.view.View.performClick(View.java:4204) 在 android.view.View$PerformClick.run(View.java:17355) 在 android.os.Handler.handleCallback(Handler.java:725) 在 android.os.Handler.dispatchMessage(Handler.java:92) 在 android.os.Looper.loop(Looper.java:137) 在 android.app.ActivityThread.main(ActivityThread.java:5041) 在 java.lang.reflect.Method.invokeNative(Native Method) 在 java.lang.reflect.Method.invoke(Method.java:511) 在 com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793) 在 com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560) 在 dalvik.system.NativeStart.main(本机方法) 引起:java.lang.reflect.InvocationTargetException 在 java.lang.reflect.Method.invokeNative(Native Method) 在 java.lang.reflect.Method.invoke(Method.java:511) 在 android.view.View$1.onClick(View.java:3594) ... 11 更多 引起:java.lang.IllegalStateException:无法执行任务:任务已经执行(一个任务只能执行 一次) 在 android.os.AsyncTask.executeOnExecutor(AsyncTask.java:578) 在 android.os.AsyncTask.execute(AsyncTask.java:534) 在 com.revonline.pastebin.Pastebin.postPaste(Pastebin.java:65) 在 com.revonline.pastebin.MyActivity.sharePaste(MyActivity.java:132) ... 14 更多

有什么问题? AsyncTask 不适合这种情况?我应该使用普通线程代码吗?

我读过一个问题,其中有人说异步任务可能仍会运行 5 秒,但我认为这不是同一个问题..

【问题讨论】:

    标签: java android asynchronous android-asynctask


    【解决方案1】:

    有什么问题?

    您需要为每个execute() 调用创建一个新的AsyncTask 实例。您不能在同一个 AsyncTask 实例上调用 execute() 两次。

    AsyncTask 不适合这种情况?

    我不会在这里使用它。

    我应该使用普通线程代码吗?

    我会使用IntentService。它已经有一个后台线程。它已经有一个队列。如果您的应用移到后台,它会比AsyncTask 更可靠地完成队列中的工作,因为 Android 不太可能立即终止您的进程。

    【讨论】:

    • 谢谢,现在一切正常。我在 onCreate 中执行 registerReceiver 以在应用程序中显示一个带有 HTTP 请求结果的 AlertDialog 但 onCreate 被多次调用..当我需要停止广播而不引起问题时? onPause 和 onDestroy?