【问题标题】:Unblocking UI Thread while avoiding NetworkOnMainThread Error非阻塞 UI 线程同时避免网络主线程错误
【发布时间】:2015-05-25 14:00:06
【问题描述】:

我有一个函数,我必须从服务器获取代码并返回它的操作。

这里是代码

public String getResult
{
        // Call to your backend

        try {
            String url = String.format(Constants.LOGIN_URL,
                    URLEncoder.encode(countryCode + phoneNumber, "UTF-8"),
                    URLEncoder.encode(smsCode, "UTF-8"),
                    URLEncoder.encode(Constants.WHERE_API_KEY, "UTF-8"));

            while (new LoginToServer().execute(url).get());

        }catch (Exception e)
        {}

return result; // Result will be saved to class in onPostExecute()

如果在检索结果时出错,我的 LoginToServer 将返回 true。现在,这将最明显地删除 NetworkOnMainThread 的异常,但它会阻止 UI。

由于该函数将由一些 sdks 调用,因此我必须创建 httpconnection 以便它完成然后传递结果。

如何在执行此代码时使 UI 解除阻塞?

再次,我不能将整个函数调用为 aysnc,因为该函数将由大多数 sdk 函数在内部调用,并且它们不会在异步中调用它

【问题讨论】:

  • 这不是我想要的。我想像同步一样返回直到操作完成
  • 打败异步的定义,这是你需要的,怎么样

标签: java android eclipse multithreading android-studio


【解决方案1】:

如何在执行此代码时使 UI 解除阻塞?

去掉get(),处理你AsyncTaskonPostExecute()中的URL结果。

或者,将AsyncTask 替换为常规线程,并在后台线程上调用getResult(),并在它们之间使用适当的同步逻辑。这会很浪费,因为您不应该在这里需要两个线程,但它会排除主应用程序线程。

您根本无法在主应用程序线程上调用 getResult() 来进行阻塞调用,并且让该阻塞调用以某种方式不会阻塞。

【讨论】:

  • 理论上可以编写一个在 UI 线程上运行而不阻塞它的阻塞方法:该方法必须在内部运行事件循环,在每次迭代时轮询 HTTP 请求的完成状态。这是 SWT 中的常规模式;但在 Android 上似乎不可用。
  • @CommonsWare 是的,我可以在后台线程上调用 getResult,但我使用的库不能。所以我需要一个解决方法
  • @MuhammadUmar:除非库为您提供应用程序组件(例如活动),否则我看不到库如何控制使用的线程。但是,假设您是正确的,并且库正在强制主应用程序线程,您要么必须停止使用这些库,要么停止尝试直接执行网络 I/O 以响应库的回调。
【解决方案2】:

您必须使用AsyncTask 之类的东西。当然,您可以从您的 SDK/库的用户中抽象出这种方式,以便他们调用简单地调用 doLogin() 函数,并在该函数中传递一个回调接口,该接口将在登录结果返回时调用。

public void doLogin(final MyCallback callback) {

    new AsyncTask<URL, Void, Boolean> {
        protected Boolean doInBackground(URL... urls) {
            // make network calls to login in this "background" thread.
            loginSuccess = true;
            return loginSuccess;
        }

        protected void onPostExecute(Boolean loginSuccess) {
           callback.onResult(loginSuccess);
        }
    }.execute();
}

注意doLogin 方法是如何立即返回的,并且只有在网络调用完成后(可能是几秒钟后)才会调用callback。这就是您进行非阻塞工作并保持主线程和应用 UI 响应的方式。

【讨论】:

  • 这很有趣,我没想到 :) 让我试试
【解决方案3】:

异步线程用于耗时的操作(网络可能很慢/服务器可能很慢/客户端服务器之间的跳数很多等)

在从服务器获取数据时,不阻塞 UI 线程的运行,这就是异步调用的用途。

您可以从 Asyctasks doInBackground() 方法中调用此函数。

UI 线程将正常运行并在 PostExecute() 回调中处理结果。

您面临的挑战是什么?肯定有几个函数可以异步调用它。是否要同步异步调用?你可以使用Executor

查看原生 Android 异步类或 LoopJ 等库

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-04-12
    • 1970-01-01
    • 1970-01-01
    • 2011-10-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多