8

扩展 AsyncTask 的自定义类存在一些问题。我的应用程序面向 Android 4.0.3,下面的代码适用于 30 多人测试它。但是,当我像下面这样调用 new AsyncRequest 时,有两个用户看到应用程序崩溃。

我有一个工作记录器,它正在记录到用户存储上的文本文件中,并且不记录 AsyncRequest 构造函数中的条目。所以我必须假设崩溃是在调用构造函数之前发生的。

遇到此崩溃的两台设备之一显然正在运行 Android 4.0.4。不确定其他设备正在运行什么。不幸的是,我无法访问这两个设备,因此看不到 logcat 输出。

任何关于对象创建导致崩溃的原因的输入将不胜感激。

String url = "www.google.com";

new AsyncRequest(callback, context).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, url);

这是完整的 AsyncRequest 类

public class AsyncRequest extends AsyncTask<String, String, String>{

HttpURLConnection connection;
InputStream inStream;
IApiCallback callback;
Context context_;

public AsyncRequest(IApiCallback callback, Context context) {
    // Log entry added for testing. Never gets called.
    FileLogger.getFileLogger(context).ReportInfo("Enter AsyncRequest Constructor");
    this.callback = callback;
    context_ = context;
}

@Override
protected String doInBackground(String... uri) {

    try {
        URL url = new URL(uri[0] + "?format=json");
        FileLogger.getFileLogger(context_).ReportInfo("Async Request: Sending HTTP GET to " + url);

        connection = (HttpURLConnection) url.openConnection();
        connection.setConnectTimeout(5000);
        connection.setReadTimeout(5000);
        connection.addRequestProperty("Accept-Encoding", "gzip");
        connection.addRequestProperty("Cache-Control", "no-cache");

        connection.connect();

        String encoding = connection.getContentEncoding();

        // Determine if the stream is compressed and uncompress it if needed.
        if (encoding != null && encoding.equalsIgnoreCase("gzip")) {
            inStream = new GZIPInputStream(connection.getInputStream());

        }  else {
            inStream = connection.getInputStream();
        }

        if (inStream != null) {
            // process response
            BufferedReader br = new BufferedReader(new InputStreamReader(inStream));
            StringBuilder sb = new StringBuilder();
            String line;
            while ((line = br.readLine()) != null) {
                sb.append(line);
            }

            return sb.toString();  

        }

    } catch (SocketTimeoutException e) {
        FileLogger.getFileLogger(context_).ReportException("Async Request: SocketTimeoutException", e);
        Log.i("AsyncRequest", "Socket Timeout occured");
    } catch (MalformedURLException e) {
        FileLogger.getFileLogger(context_).ReportException("Async Request: MalformedUrlException", e);
    } catch (IOException e) {
        FileLogger.getFileLogger(context_).ReportException("Async Request: IOException", e);
        Log.i("doInBackground:","IOException");

        if (e != null && e.getMessage() != null) {
            Log.i("doInBackground:",e.getMessage());
        }
    } catch (Exception e) {
        FileLogger.getFileLogger(context_).ReportException("Async Request: Exception", e);

    } finally {
        if (connection != null)
            connection.disconnect();
    }

    return null;
}

@Override
protected void onPostExecute(String result) {

    if (result != null) 
        FileLogger.getFileLogger(context_).ReportInfo("Async Request: Response is valid");
    else
        FileLogger.getFileLogger(context_).ReportInfo("Async Request: Invalid response");

    callback.Execute(result);
}
}

编辑:根据下面的评论。

这是我调用自定义 AsyncTask 的完整方法。我创建 AsyncTask 之前的所有日志消息都显示在日志中。没有一个例外。

日志在创建我的 AsyncRequest 之前显示 url 值,并且该 URL 根本没有格式错误。这是我所期待的。

public void GetServerInfoAsync(IApiCallback callback, Context context) throws IllegalArgumentException, Exception {

    if (callback == null)
        throw new IllegalArgumentException("callback");

    if (context == null)
        throw new IllegalArgumentException("context");

    try {
        FileLogger.getFileLogger(context).ReportInfo("Build URL");
        String url = GetApiUrl("System/Info");
        FileLogger.getFileLogger(context).ReportInfo("Finished building URL");

        if (url != null) {
            FileLogger.getFileLogger(context).ReportInfo("GetServerInfoAsync: url is " + url);
            new AsyncRequest(callback, context).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, url);
        } else {
            FileLogger.getFileLogger(context).ReportError("GetServerInfoAsync: url is null");
        }

    } catch (IllegalArgumentException iae) {
        FileLogger.getFileLogger(context).ReportException("GetServerInfoAsync: IllegalArgumentException", iae);
        throw iae;
    } catch (Exception e) {
        FileLogger.getFileLogger(context).ReportException("GetServerInfoAsync: Exception", e);
        throw e;
    }
}
4

2 回答 2

0

很抱歉没有早点回来。这里有很多问题。

首先...感谢 Wolfram 的建议,我能够捕捉到异常并诊断出问题在于我的 FileLogger(和另一个类)是静态引用,而这两个平板电脑在运行时找不到引用。所以我最终从我的异步方法中删除了 Logging。

其次,在进行上述更改后,还有另一个问题是必须从主线程调用循环器。事实证明,这两个平板电脑并没有从主线程调用我的异步任务。所以我不得不使用 MainLooper 将异步调用包含在一个新的处理程序中。

于 2013-06-10T00:24:28.317 回答
0

首先,请记住executeOnExecutor()在 Api 11 之前不可用。您已经说过问题出在 4.0.4 设备上,但请记住这一点。

以下是我将采取的步骤来解决问题所在。似乎您已经对所有这些ReportInfo()陈述做了其中的一些。

首先,我假设您的呼叫GetServerInfoAsync在 a 内try...catch,对吗?我正在检查是因为您使用Throw. 此外,您已经添加了日志记录以检查 url 是否存在错误。由于错误发生在您实际使用它之前,因此错误不能与 url 或任何 Internet 权限有关。callback您使用对和的引用调用 AsyncTask 生成context。您已经通过ReportInfo()引用上下文添加了日志记录,并且这些工作,是吗?因此,上下文不是您的问题。但是,您永远不会检查是什么callback。如果它为空,则会引发错误,但在调用AsyncRequest. 试试看ReportInfo(callback.toString())它是什么。

如果一切都失败了,那似乎是线程错误。为什么不尝试只使用 AsyncTask,而不是executeOnExecutor(). 你真的需要超过 1 个后台线程吗?

于 2013-05-21T12:55:57.507 回答