【问题标题】:Starting an activity as a Thread?将活动作为线程启动?
【发布时间】:2016-02-04 16:27:39
【问题描述】:

我目前正在努力创建我最近编写的“战舰”程序的移动 (Android) 版本。虽然我的 GUI 现在已经完成并且程序的大部分部分应该可以工作,但我(至少)还有一个主要问题:除了服务器部分(它将对用户输入等做出反应)之外,我的程序的主要部分依赖于Java NIO,即网络访问。但是,由于它在主线程上运行,我收到了

java.lang.RuntimeException: Unable to start activity ComponentInfo{x.battleship/x.battleship.BattleshipMain}: android.os.NetworkOnMainThreadException`

(出于隐私原因,我将包名替换为 x)。

因此,我的问题是:如何将活动作为新线程开始?到目前为止,我已经使用过

Intent i = new Intent(getApplicationContext(), BattleshipMain.class);
startActivity(i);
i.putExtra("ip",joinip);
i.putExtra("port",joinport);

起初,我认为这是一个替代方案:

new Thread(new Runnable() {
                        @Override
                        public void run() {
                            Intent i = new Intent(getApplicationContext(), BattleshipMain.class);
                            startActivity(i);
                            i.putExtra("ip",joinip);
                            i.putExtra("port",joinport);
                        }
                    });

但是,它似乎不起作用 - 我在控制台中收到一条消息,BattleshipMain 已启动,但显示屏上实际上没有显示任何内容(除了已经存在的内容)。 有人知道该怎么做吗?我真的不知道如何解决这个问题;不过,我还是 Android 新手,也不是真正的长期 Java 专家。

提前致谢!

//编辑:如果我应该这样做,我不太熟悉,但是在我将网络代码移动到单独的线程后,在我看来我无法连接手机上的应用程序到我的 PC 上运行的服务器。他们在同一个网络中并且服务器应该与移动应用程序兼容,但考虑到我收到的错误/冻结屏幕,我看不出还有什么问题。 Java NIO 是否可以在 android 上正常工作/我是否可以将手机上的客户端(这是 Galaxy S3,顺便说一句 -> API 18)连接到装有 Windows 的 PC 上的服务器? 谢谢! :)

//编辑:没关系,错误是 100% 愚蠢的。当使用 Intent 创建新活动时,我创建了 Intent,启动了它,然后使用了 intentname.putExtra(key, value) - 这显然不起作用。现在,我遇到了另一个错误,因为我试图从不同的线程更改复选框,但网络部分工作,所以我想我很快就会完成。

【问题讨论】:

  • 您不能在非 UI 线程上运行 Activity。您需要将网络代码移动到 UI 线程上。您在 Activity 中拥有的网络代码。
  • NetworkOnMainThreadException 中的关键字是 Network,表示您正在做一些网络访问的事情,而 Android 不喜欢这样。如果您添加更多代码,我们可以解决您的XY Problem
  • @Knossos 我相信您的意思是您需要将网络代码移出 UI 线程。
  • 糟糕!是的!网络代码需要移动到后台线程。
  • 我想你不是原生的安卓开发者,但你应该熟悉restclients(比如Spring)。那么为什么不尝试使用retrofit/okhttp之类的东西呢?

标签: java android


【解决方案1】:

你遇到的问题是你在主线程上做网络,这是被禁止的。将所有网络和网络/api 调用移至AsyncTasks,这样应该就可以了。

编辑: 除此之外,请放弃将活动作为线程启动的想法,因为活动有自己的生命周期which is described here

EDIT2:也许如果您设法关闭 StrictMode(可在开发人员选项中使用),您可以在主线程上进行联网,但......我不会指望它。

【讨论】:

  • networking on the main thread 请忘记这些话,永远不要再说一遍
  • 感谢您的担心,@Droidman,但我可以向您保证,我无意利用任何“黑客”,因此我不必将我的网络转移到单独的线程。 a)这可能比实际移动网络部分需要更多的工作,并且 b)因为我现在知道我不允许在我的主线程上做网络工作,所以我以后不会以这种方式构建我的程序。除此之外,我还想知道为什么确切地使用这些黑客是不好的——我想谷歌禁用它是有原因的,对吧?
  • 在主线程上进行联网被认为是不好的做法,因为这会导致糟糕的用户界面体验。主线程也称为 UI 线程,因为用户界面是由该线程驱动的。如果您在主线程上执行长时间运行的操作,您将阻止系统对 UI 进行更新,因此您的应用程序会冻结,直到操作结束。所以你可以在主线程上做短时间的操作,但不能像网络操作那样需要几秒钟甚至几分钟的时间。
  • P.S.量化主线程上的短操作和长操作:长操作大致是任何花费超过 10 或 15 毫秒的操作。当屏幕以每秒 60 帧的速度刷新时,可以获得流畅的用户界面体验。这意味着每帧需要 16 毫秒(1 秒除以 60 帧)。如果您用尽所有可用于绘制帧的时间,那么系统将不得不跳过该帧。用户会注意到这是屏幕抖动。
  • 顺便提一下,持续超过 5 秒的 UI 阻塞操作将导致 ANR。这些应该像瘟疫一样避免。这就是 Google 引入 NetworkingOnMainThreadException(在 API 级别 11 中)的原因。太糟糕了,他们强迫应用程序崩溃,而不是一开始就让坏代码进入应用程序。
【解决方案2】:

你不能。您只有一个 UI 线程。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多