如何修复android.os.NetworkOnMainThreadException?

bej*_*rge 2308 java android android-networking networkonmainthread

我在为RssReader运行我的Android项目时遇到错误.

码:

URL url = new URL(urlToRssFeed);
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser parser = factory.newSAXParser();
XMLReader xmlreader = parser.getXMLReader();
RssHandler theRSSHandler = new RssHandler();
xmlreader.setContentHandler(theRSSHandler);
InputSource is = new InputSource(url.openStream());
xmlreader.parse(is);
return theRSSHandler.getFeed();
Run Code Online (Sandbox Code Playgroud)

它显示以下错误:

android.os.NetworkOnMainThreadException
Run Code Online (Sandbox Code Playgroud)

我该如何解决这个问题?

Mic*_*tor 2491

当应用程序尝试在其主线程上执行网络操作时,抛出此异常.运行您的代码AsyncTask:

class RetrieveFeedTask extends AsyncTask<String, Void, RSSFeed> {

    private Exception exception;

    protected RSSFeed doInBackground(String... urls) {
        try {
            URL url = new URL(urls[0]);
            SAXParserFactory factory = SAXParserFactory.newInstance();
            SAXParser parser = factory.newSAXParser();
            XMLReader xmlreader = parser.getXMLReader();
            RssHandler theRSSHandler = new RssHandler();
            xmlreader.setContentHandler(theRSSHandler);
            InputSource is = new InputSource(url.openStream());
            xmlreader.parse(is);

            return theRSSHandler.getFeed();
        } catch (Exception e) {
            this.exception = e;

            return null;
        } finally {
            is.close();
        }
    }

    protected void onPostExecute(RSSFeed feed) {
        // TODO: check this.exception
        // TODO: do something with the feed
    }
}
Run Code Online (Sandbox Code Playgroud)

如何执行任务:

MainActivity.java文件中,您可以在oncreate()方法中添加此行

new RetrieveFeedTask().execute(urlToRssFeed);
Run Code Online (Sandbox Code Playgroud)

不要忘记将其添加到AndroidManifest.xml文件中:

<uses-permission android:name="android.permission.INTERNET"/>
Run Code Online (Sandbox Code Playgroud)

  • **这是完全错误的答案.**我在人们的代码中一直遇到这个问题,而且一直都需要修复它很烦人.AsyncTask不应该用于网络活动,因为它与活动有关,而与活动生命周期无关.在此任务正在运行的情况下旋转设备将导致异常并导致应用程序崩溃.使用IntentService来删除sqlite数据库中的数据. (64认同)
  • 我认为值得注意的是,上面的代码片段应该是一个子类(内部类),最好是私有的.这样,当AsyncTask结束时,您仍然可以操纵类的内部. (35认同)
  • 由于 AsyncTask 已被弃用,最新的解决方案是什么? (25认同)
  • 实际上我做了与你上面提到的相同的事情,但我面临这个错误**java.lang.RuntimeException:无法在未调用Looper.prepare()的线程内创建处理程序** (4认同)
  • 注意,AsyncTask通常用于不宜使用的按活动网络操作。其生命周期与活动不同步。为了获取数据,您应该使用IntentService和视图后面的数据库。 (4认同)

小智 647

您应该几乎总是在线程上运行网络操作或作为异步任务.

但是,如果您愿意接受后果,可以删除此限制并覆盖默认行为.

加:

StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();

StrictMode.setThreadPolicy(policy); 
Run Code Online (Sandbox Code Playgroud)

在你的班上,

在android manifest.xml文件中添加此权限:    

<uses-permission android:name="android.permission.INTERNET"/>
Run Code Online (Sandbox Code Playgroud)

后果:

您的应用程序将(在互联网连接不稳定的区域)变得无响应并锁定,用户感知速度缓慢并且必须执行强制终止,并且您冒着活动管理器杀死您的应用并告诉用户该应用已停止的风险.

Android提供了一些关于良好编程实践的好建议,以设计响应能力:http: //developer.android.com/reference/android/os/NetworkOnMainThreadException.html

  • 这是一个非常糟糕的主意.解决方案是避免主线程上的网络IO(如接受的答案所示). (451认同)
  • Upvoted.这个答案是正确的,对于那些既不天真也不愚蠢,但只需要SYNCHRONOUS(即:这*必须阻止app*)调用的程序员来说,这正是需要的.我很高兴Android默认抛出异常(恕我直言,这是一个非常"有用"的事情!) - 但我同样乐意说"谢谢,但是 - 这实际上是我的意图"并覆盖它. (92认同)
  • 有了它,你只能隐藏你真正的问题. (74认同)
  • @TwistedUmbrella AsyncTask不添加代码页,它添加了6行(类声明,覆盖注释,`doInBackground`声明,2个右括号和对`execute()`的调用).另一方面,即使您提到的网站中的单个提取也会导致UI响应性显着滞后.不要偷懒. (27认同)
  • 我认为这是一个完美的解决方案,如果您希望在实现正确的AsyncTask之前只运行一大块代码来查看是否有效.这就是为什么我赞成这个答案,尽管正如所有其他人所说的那样,这不应该在生产应用程序中完成,只能作为开发测试的快速解决方法. (19认同)
  • 对于那些很快想要测试某些功能并且不关心他们的应用需要很长时间来响应的人来说,这是一个很好的解决方案. (9认同)
  • @TwistedUmbrella如果您正在阅读txt文件,或者甚至只是在2G等慢速连接时注销,您将看到显着的延迟. (8认同)
  • 这可能不是下载图库的解决方案,但是当您有一个应用程序只是从网站获取一些文本并将其显示给用户时,这比添加的代码页更好. (6认同)
  • @ChrisStratton为什么你认为我们都是新手?我会再说一遍:我*需要*阻止通话.不是"我想要一个允许应用程序继续进行的阻止类型的通话",而是一个实际,阻止,呼叫.在发生这种情况时,整个应用程序停止工作至关重要.我已经用Java编写了将近20年的编程,其中10个专门研究低级多线程系统 - 我确切地知道我在做什么,并且令人愤怒的是那些不知道我的代码库的人很乐意讲课"正确的方式". (6认同)
  • 或者,可能:我知道我在做什么以及为什么.问题是合理的,答案是正确的,我们这些知道我们正在做的事情的人都很高兴.它似乎被那些不知道我们正在做什么的人所贬低,但是他们都很乐意对它进行演讲. (6认同)
  • @Adam - 不,这不是完成SYNCHRONOUS操作的正确方法.正确的方法是让程序保持并依赖于一系列状态.这不是一种安全的同步方式的原因是即使部分用户体验可能是同步的,Android也可能需要紧急将其他事件传递给UI线程.如果UI线程被阻塞等待慢速网络,则它不可能这样做.使用state方法,您可以暂停依赖于网络结果的事物,但仍然可以立即处理其他UI /生命周期/ etc事件. (5认同)
  • 不会.您的方法绝对错误,因为您无法阻止用户生成UI事件.您与Android平台的合同要求您允许及时交付这些内容.以符合标准的方式解决问题的关键是实现让android向您报告事件并不意味着您的程序必须使用这些事件.您拒绝适应平台的需求(例如通过仅使用UI线程进行翻译,而不是顺序编程逻辑)显然是拒绝正确地完成工作. (5认同)
  • 这个答案对于我们这些需要实施快速可行性测试而不需要通过实施的人来说是有帮助的. (5认同)
  • @TwistedUmbrella你错了......你永远不应该在主线程上执行网络请求.这是开发响应式GUI的首要规则之一,它不仅适用于Android ......它也适用于像Swing这样的桌面应用程序.网络请求取决于许多其他因素,例如地理位置接近,服务器发生故障/无响应,数据包丢失等.无法保证需要多长时间,研究表明0.1秒的延迟足以让人感到沮丧大多数用户. (4认同)
  • @RvdK抑制警告的目的是帮助学习者快速查看他们的代码是否有效,而不会受到"最佳实践"之后的更多额外花哨代码的困扰.当学习者确定他们的代码时,他们可以开始学习其他东西,例如asynchtask,这比在开始时学习太多东西要好得多. (3认同)
  • @ZoltánAsyncTask(完成右侧)添加了任务本身的整个声明,前后执行,调用,导入,访问调用等.我还没有看到一点"UI响应性显着滞后" "阅读和解析文本文件.我不是懒惰,只是高效.这就是更好的应用程序的制作方式. (2认同)
  • @AlexLockwood您的论文很有意思,但这里有一个场景:本地服务器托管一些文本文件,每个文本文件有3个链接,每个链接由PHP生成,应用程序在启动时需要这些链接,然后使用它们连接到其他服务器.您列出的变量非常少,异步任务将以不同于线程的方式处理,因为它们都是在线任务.我也明确表示只有**一些**场景才有用.如果你有任何进一步的一心一意的咆哮,请亲自指导我,并为未来的读者留下不必要的,过多的评论. (2认同)
  • @TwistedUmbrella TL; DR ...不在主线程上执行网络操作.检查Android Developer网站,他们会告诉你同样的事情.之所以称它为"NetworkOnMainThreadException",是因为他们不希望你在**主线程**上执行**network**操作.进一步评论保留. (2认同)
  • 这个答案有用的原因有一个:我禁止抛出异常来**评估**与另一个设备的套接字连接.现在我们办公室的每个人都相信原型,网络将被转移到一个单独的线程.应用程序的发布版本当然不会阻止其UI. (2认同)
  • 对于Android学习者来说,这是一个很好的解决方案,可以通过遵循一些愚蠢的"最佳实践"来避免不必要地使代码复杂化.我们的想法是暂时逃脱它,看看核心应用程序是否有效."最佳实践"适用于商业产品,但不应强制使用.例如,您可以发出警告但返回错误并让人困惑是一个坏主意.竖起大拇指回答这个问题,或者只是不要用拇指向下. (2认同)
  • +1快速和肮脏的解决方案.所有的反对者 - 它只是*.这使我能够超越我已经持续数小时的问题,并做一些更有趣的事情.周围有评论`//!HACKY - CLEAN IT UP LATER`.我会回来并正确地做到这一点.现在好了. (2认同)
  • 对于所有人都说这个功能没有任何可能用处:Android无论上下文如何都会抛出此异常.我们在一个单独的流程中运行一个服务,以便多个应用程序可以通过我们的库共享一个公共服务.没有UI,只有这种网络服务 - 它不需要严格的策略检查,因为我们已经在不妨碍我们的UI的情况下与它进行交互 (2认同)
  • @JRaymond:即使在您的场景中,您仍然需要一个后台线程,因为如果您在主应用程序线程上花费太长时间,Android仍将终止您的工作.在你的情况下,"太长"是在5-10秒的范围内,最后我检查,而不是防止一个janky UI所需的几毫秒范围.但是,设备制造商可能会修改确切的超时,因此即使您有自己的逻辑尝试在某个固定的持续时间之前结束工作,也可能不够短.通过比较分叉线程很简单并避免风险. (2认同)

Dr.*_*iji 410

我用新的方法解决了这个问题Thread.

Thread thread = new Thread(new Runnable() {

    @Override
    public void run() {
        try  {
            //Your code goes here
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
});

thread.start(); 
Run Code Online (Sandbox Code Playgroud)

  • 简单但危险.匿名Runnable具有对封闭类的隐式引用(例如,您的Activity或Fragment),防止它在线程完成之前被垃圾收集.您至少应该将优先级设置为Process.BACKGROUND,否则此线程将以与main/ui线程相同的优先级运行,与生命周期方法和ui帧速率竞争(注意编排者的日志中的警告). (65认同)
  • 您可以使用单个线程执行程序服务,而不是每次要执行网络操作时都创建新线程. (7认同)

Ste*_*vie 157

接受的答案有一些重要的缺点.除非你真的知道自己在做什么,否则不建议使用AsyncTask进行网络连接.一些不利方面包括:

  • 作为非静态内部类创建的AsyncTask具有对封闭的Activity对象,其上下文以及该活动创建的整个View层次结构的隐式引用.此引用可防止在AsyncTask的后台工作完成之前对Activity进行垃圾回收.如果用户的连接速度很慢,和/或下载量很大,则这些短期内存泄漏可能会成为问题 - 例如,如果方向发生多次更改(并且您没有取消执行的任务),或者用户导航远离活动.
  • AsyncTask具有不同的执行特性,具体取决于它执行的平台:API级别4之前AsyncTasks在单个后台线程上串行执行; 从API级别4到API级别10,AsyncTasks在最多128个线程的池上执行; 从API级别11开始,AsyncTask在单个后台线程上串行执行(除非您使用重载executeOnExecutor方法并提供备用执行程序).当在Gingerbread上同时执行时,在ICS上串行运行时运行正常的代码可能会中断,例如,如果您有无意的执行顺序依赖项.

如果您想避免短期内存泄漏,在所有平台上都有明确定义的执行特性,并且有基础来构建非常强大的网络处理,您可能需要考虑:

  1. 使用一个能为你做得很好的库 - 在这个问题中对网络库进行了很好的比较,或者
  2. 使用a Service或者IntentService替代,也许使用a PendingIntent来通过Activity的onActivityResult方法返回结果.

IntentService方法

下行方面:

  • 更多的代码和复杂性AsyncTask,虽然没有您想象的那么多
  • 将队列请求排队并在单个后台线程上运行它们.您可以通过替换IntentService等效Service实现来轻松控制此操作,也许就像这样.
  • 嗯,实际上我现在想不出任何其他人

向上方面:

  • 避免短期内存泄漏问题
  • 如果您的活动在网络操作正在进行时重新启动,它仍然可以通过其onActivityResult方法接收下载结果
  • 比AsyncTask更好的平台来构建和重用强大的网络代码.示例:如果您需要执行重要上传,则可以从中AsyncTask进行Activity,但如果用户上下文切换出应用程序以进行电话呼叫,系统可能会在上载完成之前终止应用程序.它不太可能杀死具有活动的应用程序Service.
  • 如果您使用自己的并发版本IntentService(如上面链接的那个),您可以通过控制并发级别来控制并发级别Executor.

实施摘要

您可以IntentService非常轻松地实现在单个后台线程上执行下载.

第1步:创建一个IntentService以执行下载.您可以通过Intentextra 来告诉它要下载什么,并将其传递PendingIntent给用于将结果返回到Activity:

import android.app.IntentService;
import android.app.PendingIntent;
import android.content.Intent;
import android.util.Log;

import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;

public class DownloadIntentService extends IntentService {

    private static final String TAG = DownloadIntentService.class.getSimpleName();

    public static final String PENDING_RESULT_EXTRA = "pending_result";
    public static final String URL_EXTRA = "url";
    public static final String RSS_RESULT_EXTRA = "url";

    public static final int RESULT_CODE = 0;
    public static final int INVALID_URL_CODE = 1;
    public static final int ERROR_CODE = 2;

    private IllustrativeRSSParser parser;

    public DownloadIntentService() {
        super(TAG);

        // make one and re-use, in the case where more than one intent is queued
        parser = new IllustrativeRSSParser();
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        PendingIntent reply = intent.getParcelableExtra(PENDING_RESULT_EXTRA);
        InputStream in = null;
        try {
            try {
                URL url = new URL(intent.getStringExtra(URL_EXTRA));
                IllustrativeRSS rss = parser.parse(in = url.openStream());

                Intent result = new Intent();
                result.putExtra(RSS_RESULT_EXTRA, rss);

                reply.send(this, RESULT_CODE, result);
            } catch (MalformedURLException exc) {
                reply.send(INVALID_URL_CODE);
            } catch (Exception exc) {
                // could do better by treating the different sax/xml exceptions individually
                reply.send(ERROR_CODE);
            }
        } catch (PendingIntent.CanceledException exc) {
            Log.i(TAG, "reply cancelled", exc);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

第2步:在清单中注册服务:

<service
        android:name=".DownloadIntentService"
        android:exported="false"/>
Run Code Online (Sandbox Code Playgroud)

步骤3:从Activity调用服务,传递PendingResult对象,Service将使用该对象返回结果:

PendingIntent pendingResult = createPendingResult(
    RSS_DOWNLOAD_REQUEST_CODE, new Intent(), 0);
Intent intent = new Intent(getApplicationContext(), DownloadIntentService.class);
intent.putExtra(DownloadIntentService.URL_EXTRA, URL);
intent.putExtra(DownloadIntentService.PENDING_RESULT_EXTRA, pendingResult);
startService(intent);
Run Code Online (Sandbox Code Playgroud)

第4步:处理onActivityResult中的结果:

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == RSS_DOWNLOAD_REQUEST_CODE) {
        switch (resultCode) {
            case DownloadIntentService.INVALID_URL_CODE:
                handleInvalidURL();
                break;
            case DownloadIntentService.ERROR_CODE:
                handleError(data);
                break;
            case DownloadIntentService.RESULT_CODE:
                handleRSS(data);
                break;
        }
        handleRSS(data);
    }
    super.onActivityResult(requestCode, resultCode, data);
}
Run Code Online (Sandbox Code Playgroud)

包含一个完整的工作Android的工作室/ gradle这个项目一个项目的GitHub可以在这里.

  • @BrillPappin我几乎完全同意并且已经重新措辞以强调AsyncTask的缺点.(我仍然认为有非常少数的情况 - 如果你真的知道你在做什么 - 它可以使用AsyncTask,但是接受的答案并没有指出任何缺点并且太过受欢迎了Android). (3认同)

Mar*_*son 141

你可以不执行网络I/O在UI线程上的蜂窝.从技术上讲,这可能在早期版本的Android,但它是一个非常糟糕的主意,因为它会导致你的应用程序停止响应,并可能导致操作系统杀死你的应用程序被用于非常表现.您需要运行后台进程或使用AsyncTask在后台线程上执行网络事务.

Android开发者网站上有一篇关于无痛线程的文章,这是对此的一个很好的介绍,它将为您提供比这里现实提供的更好的答案深度.


ven*_*iac 72

  1. 不要使用strictMode(仅在调试模式下)
  2. 不要更改SDK版本
  3. 不要使用单独的线程

使用Service或AsyncTask

另请参阅Stack Overflow问题:

android.os.NetworkOnMainThreadException从Android发送电子邮件

  • 也许值得强调的一点是,如果使用服务,您仍然需要创建一个单独的线程 - 在主线程上运行服务回调.另一方面,IntentService在后台线程上运行其onHandleIntent方法. (8认同)

hen*_*343 71

在另一个线程上执行网络操作

例如:

new Thread(new Runnable(){
    @Override
    public void run() {
        // Do network action in this function
    }
}).start();
Run Code Online (Sandbox Code Playgroud)

并将其添加到AndroidManifest.xml

<uses-permission android:name="android.permission.INTERNET"/>
Run Code Online (Sandbox Code Playgroud)

  • 但是我们如何才能找到线程何时完成,以便我们可以在UI线程中执行下一组任务?AsyncTask提供了执行此操作的工具.有没有办法使用runnable线程做同样的事情? (5认同)
  • 它将逐步处理您的代码,因此在代码结束时,您需要使用处理程序返回UI线程 (3认同)

San*_*eep 58

您使用以下代码禁用严格模式:

if (android.os.Build.VERSION.SDK_INT > 9) {
    StrictMode.ThreadPolicy policy = 
        new StrictMode.ThreadPolicy.Builder().permitAll().build();
    StrictMode.setThreadPolicy(policy);
}
Run Code Online (Sandbox Code Playgroud)

建议不要这样做:使用AsyncTask界面.

这两种方法的完整代码

  • 这是一个非常糟糕的答案.您不应该更改线程的策略,而是编写更好的代码:不要在主线程上进行网络操作! (10认同)
  • 是的,将会出现ANR错误。表示应用程序在5秒钟内没有响应。 (2认同)

Dhr*_*dal 51

基于网络的操作无法在主线程上运行.您需要在子线程上运行所有基于网络的任务或实现AsyncTask.

这是您在子线程中运行任务的方式:

new Thread(new Runnable(){
    @Override
    public void run() {
        try {
            // Your implementation goes here
        } 
        catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}).start();
Run Code Online (Sandbox Code Playgroud)


Vai*_*iya 46

把你的代码放在里面:

new Thread(new Runnable(){
    @Override
    public void run() {
        try {
            // Your implementation
        }
        catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}).start();
Run Code Online (Sandbox Code Playgroud)

要么:

class DemoTask extends AsyncTask<Void, Void, Void> {

    protected Void doInBackground(Void... arg0) {
        //Your implementation
    }

    protected void onPostExecute(Void result) {
        // TODO: do something with the feed
    }
}
Run Code Online (Sandbox Code Playgroud)


小智 43

这种情况发生在Android 3.0及更高版本中.从Android 3.0及更高版本开始,他们限制使用网络操作(访问Internet的功能)在主线程/ UI线程中运行(从创建活动中生成的内容和活动中的恢复方法).

这是为了鼓励使用单独的线程进行网络操作.有关如何以正确方式执行网络活动的更多详细信息,请参阅AsyncTask.


Ole*_*siy 43

使用Android Annotations是一种选择.它允许您在后台线程中简单地运行任何方法:

// normal method
private void normal() {
    doSomething(); // do something in background
}

@Background
protected void doSomething() 
    // run your networking code here
}
Run Code Online (Sandbox Code Playgroud)

请注意,虽然它提供了简单性和可读性的好处,但它有其缺点.

  • @Gavriel它创建了你注释的所有内容的副本,无论是方法,活动,片段,单例等,所以代码的数量是代码的两倍,编译它需要更长的时间.由于库中的错误,它也可能存在一些问题.调试和查找错误会变得更加困难. (5认同)

Ash*_*hok 40

该错误是由于在主线程中执行长时间运行操作,您可以使用AsynTaskThread轻松解决问题.您可以检查此库AsyncHTTPClient以获得更好的处理.

AsyncHttpClient client = new AsyncHttpClient();
client.get("http://www.google.com", new AsyncHttpResponseHandler() {

    @Override
    public void onStart() {
        // Called before a request is started
    }

    @Override
    public void onSuccess(int statusCode, Header[] headers, byte[] response) {
        // Called when response HTTP status is "200 OK"
    }

    @Override
    public void onFailure(int statusCode, Header[] headers, byte[] errorResponse, Throwable e) {
        // Called when response HTTP status is "4XX" (for example, 401, 403, 404)
    }

    @Override
    public void onRetry(int retryNo) {
        // Called when request is retried
    }
});
Run Code Online (Sandbox Code Playgroud)


Kap*_*ats 39

您不应该在主线程(UI线程)上执行任何耗时的任务,例如任何网络操作,文件I/O或SQLite数据库操作.因此,对于这种操作,您应该创建一个工作线程,但问题是您不能直接从工作线程执行任何与UI相关的操作.为此,你必须使用Handler并传递Message.

为了简化这些东西,Android提供各种方式,如AsyncTask,AsyncTaskLoader,CursorLoaderIntentService.因此,您可以根据您的要求使用其中任何一种.


siv*_*ag1 38

spektom的最佳答案是完美的.

如果您正在编写AsyncTask内联而不是作为类扩展,并且除此之外,如果需要从中获取响应AsyncTask,则可以使用如下get()方法.

RSSFeed feed = new RetreiveFeedTask().execute(urlToRssFeed).get();
Run Code Online (Sandbox Code Playgroud)

(从他的例子.)

  • 使用`get()`是一个坏主意......它使AsyncTask再次"同步" (5认同)
  • 我想你可以信息关于结果的主线程.例如,发送广播到主线程包括结果. (2认同)

per*_*rry 31

仅针对Honeycomb SDK或更高版本的应用程序进行此操作.针对早期SDK版本的应用程序可以在其主要事件循环线程上进行联网.

错误是SDK警告!


rha*_*vey 27

对我来说就是这样:

<uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="10" />
Run Code Online (Sandbox Code Playgroud)

我正在测试我的应用程序的设备是4.1.2,这是SDK版本16!

确保目标版本与Android目标库相同.如果您不确定目标库是什么,请右键单击您的项目 - > 构建路径 - > Android,它应该是勾选的那个.

此外,正如其他人所提到的,包括访问Internet的正确权限:

<uses-permission android:name="android.permission.INTERNET"/>
Run Code Online (Sandbox Code Playgroud)

  • 让我来解释一下你在这里做了什么:`NetworkOnMainThreadException`是卫士,告诉你:不要自己开枪......你的解决方案是:让我们回到没有卫报的过去 - 现在我可以自由地射击我的脚 (11认同)

dhi*_*ran 23

在您的活动中使用此功能

    btnsub.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            new Thread(new Runnable() {

                @Override
                public void run() {
                    // TODO Auto-generated method stub

                    //Initialize soap request + add parameters
                    SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME1);

                    //Use this to add parameters
                    request.addProperty("pincode", txtpincode.getText().toString());
                    request.addProperty("bg", bloodgroup.getSelectedItem().toString());

                    //Declare the version of the SOAP request
                    SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);

                    envelope.setOutputSoapObject(request);
                    envelope.dotNet = true;

                    try {
                        HttpTransportSE androidHttpTransport = new HttpTransportSE(URL);

                        //this is the actual part that will call the webservice
                        androidHttpTransport.call(SOAP_ACTION1, envelope);

                        // Get the SoapResult from the envelope body.
                        SoapObject result = (SoapObject) envelope.getResponse();
                        Log.e("result data", "data" + result);
                        SoapObject root = (SoapObject) result.getProperty(0);
                        // SoapObject s_deals = (SoapObject) root.getProperty(0);
                        // SoapObject s_deals_1 = (SoapObject) s_deals.getProperty(0);
                        //

                        System.out.println("********Count : " + root.getPropertyCount());

                        value = new ArrayList<Detailinfo>();

                        for (int i = 0; i < root.getPropertyCount(); i++) {
                            SoapObject s_deals = (SoapObject) root.getProperty(i);
                            Detailinfo info = new Detailinfo();

                            info.setFirstName(s_deals.getProperty("Firstname").toString());
                            info.setLastName(s_deals.getProperty("Lastname").toString());
                            info.setDOB(s_deals.getProperty("DOB").toString());
                            info.setGender(s_deals.getProperty("Gender").toString());
                            info.setAddress(s_deals.getProperty("Address").toString());
                            info.setCity(s_deals.getProperty("City").toString());
                            info.setState(s_deals.getProperty("State").toString());
                            info.setPinecode(s_deals.getProperty("Pinecode").toString());
                            info.setMobile(s_deals.getProperty("Mobile").toString());
                            info.setEmail(s_deals.getProperty("Email").toString());
                            info.setBloodgroup(s_deals.getProperty("Bloodgroup").toString());
                            info.setAdddate(s_deals.getProperty("Adddate").toString());
                            info.setWaight(s_deals.getProperty("waight").toString());
                            value.add(info);
                        }

                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    Intent intent = new Intent(getApplicationContext(), ComposeMail.class);
                    //intent.putParcelableArrayListExtra("valuesList", value);

                    startActivity(intent);
                }
            }).start();
        }
    });
Run Code Online (Sandbox Code Playgroud)


Nov*_*vak 23

只是明确说明一些事情:

主线程基本上是UI线程.

所以说你不能在主线程中进行网络操作意味着你不能在UI线程中进行网络操作,这意味着你不能在*runOnUiThread(new Runnable() { ... }*其他线程内块中进行网络操作.

(我只是想知道为什么我在主线程以外的其他地方得到了这个错误.这就是为什么;这个线程帮助了;希望这个评论会帮助其他人.)


ama*_*eep 21

如果执行任务花费太多时间,则由于在主线程上执行任何繁重的任务而发生此异常.

为避免这种情况,我们可以使用线程执行器来处理它

Executors.newSingleThreadExecutor().submit(new Runnable() {
    @Override
    public void run() {
        // You can perform your task here.
    }
});
Run Code Online (Sandbox Code Playgroud)


KG6*_*ZVP 18

关于这个问题已经有很多很好的答案,但是自从这些答案发布以来,已经出现了许多优秀的图书馆.这是一种新手指南.

我将介绍几个用于执行网络操作的用例和一个或两个解决方案.

通过HTTP重新安装

通常Json可以是XML或其他东西

完整的API访问权限

假设您正在编写一个应用程序,用户可以跟踪股票价格,利率和货币汇率.您找到一个类似于以下内容的Json API:

http://api.example.com/stocks                       //ResponseWrapper<String> object containing a list of Srings with ticker symbols
http://api.example.com/stocks/$symbol               //Stock object
http://api.example.com/stocks/$symbol/prices        //PriceHistory<Stock> object
http://api.example.com/currencies                   //ResponseWrapper<String> object containing a list of currency abbreviation
http://api.example.com/currencies/$currency         //Currency object
http://api.example.com/currencies/$id1/values/$id2  //PriceHistory<Currency> object comparing the prices of the first currency (id1) to the second (id2)
Run Code Online (Sandbox Code Playgroud)

广场改造

对于具有多个端点的API而言,这是一个很好的选择,并允许您声明ReST端点,而不必像其他库(如ion或Volley)那样单独编写它们.(网站:http://square.github.io/retrofit/)

你如何在财务API中使用它?

的build.gradle

将这些行添加到模块级别buid.gradle:

implementation 'com.squareup.retrofit2:retrofit:2.3.0' //retrofit library, current as of September 21, 2017
implementation 'com.squareup.retrofit2:converter-gson:2.3.0' //gson serialization and deserialization support for retrofit, version must match retrofit version
Run Code Online (Sandbox Code Playgroud)

FinancesApi.java

public interface FinancesApi {
    @GET("stocks")
    Call<ResponseWrapper<String>> listStocks();
    @GET("stocks/{symbol}")
    Call<Stock> getStock(@Path("symbol")String tickerSymbol);
    @GET("stocks/{symbol}/prices")
    Call<PriceHistory<Stock>> getPriceHistory(@Path("symbol")String tickerSymbol);

    @GET("currencies")
    Call<ResponseWrapper<String>> listCurrencies();
    @GET("currencies/{symbol}")
    Call<Currency> getCurrency(@Path("symbol")String currencySymbol);
    @GET("currencies/{symbol}/values/{compare_symbol}")
    Call<PriceHistory<Currency>> getComparativeHistory(@Path("symbol")String currency, @Path("compare_symbol")String currencyToPriceAgainst);
}
Run Code Online (Sandbox Code Playgroud)

FinancesApiBuilder

public class FinancesApiBuilder {
    public static FinancesApi build(String baseUrl){
        return new Retrofit.Builder()
                    .baseUrl(baseUrl)
                    .addConverterFactory(GsonConverterFactory.create())
                    .build()
                    .create(FinancesApi.class);
    }
}
Run Code Online (Sandbox Code Playgroud)

FinancesFragment片段

FinancesApi api = FinancesApiBuilder.build("http://api.example.com/"); //trailing '/' required for predictable behavior
api.getStock("INTC").enqueue(new Callback<Stock>(){
    @Override
    public void onResponse(Call<Stock> stockCall, Response<Stock> stockResponse){
        Stock stock = stockCall.body();
        //do something with the stock
    }
    @Override
    public void onResponse(Call<Stock> stockCall, Throwable t){
        //something bad happened
    }
}
Run Code Online (Sandbox Code Playgroud)

如果您的API要求发送API密钥或其他标头(如用户令牌等),则Retrofit可以轻松实现(请参阅此详细答案以获取详细信息:https://stackoverflow.com/a/42899766/1024412).

一次关闭ReST API访问

假设你正在构建一个"情绪天气"应用程序,它可以查找用户的GPS位置并检查该区域的当前温度并告诉他们心情.这种类型的应用程序不需要声明API端点; 它只需要能够访问一个API端点.

离子

对于这种类型的访问,这是一个很棒的库.

请阅读msysmilu的好答案(/sf/answers/1999191911/)

通过HTTP加载图像

齐射

Volley也可用于ReST API,但由于需要更复杂的设置,我更喜欢使用Square上的Retrofit(http://square.github.io/retrofit/)

假设您正在构建社交网络应用,并希望加载朋友的个人资料照片.

的build.gradle

将此行添加到模块级别buid.gradle:

implementation 'com.android.volley:volley:1.0.0'
Run Code Online (Sandbox Code Playgroud)

ImageFetch.java

Volley需要比Retrofit更多的设置.您需要创建一个这样的类来设置RequestQueue,ImageLoader和ImageCache,但它不是太糟糕:

public class ImageFetch {
    private static ImageLoader imageLoader = null;
    private static RequestQueue imageQueue = null;

    public static ImageLoader getImageLoader(Context ctx){
        if(imageLoader == null){
            if(imageQueue == null){
                imageQueue = Volley.newRequestQueue(ctx.getApplicationContext());
            }
            imageLoader = new ImageLoader(imageQueue, new ImageLoader.ImageCache() {
                Map<String, Bitmap> cache = new HashMap<String, Bitmap>();
                @Override
                public Bitmap getBitmap(String url) {
                    return cache.get(url);
                }
                @Override
                public void putBitmap(String url, Bitmap bitmap) {
                    cache.put(url, bitmap);
                }
            });
        }
        return imageLoader;
    }
}
Run Code Online (Sandbox Code Playgroud)

user_view_dialog.xml

将以下内容添加到布局xml文件中以添加图像:

<com.android.volley.toolbox.NetworkImageView
    android:id="@+id/profile_picture"
    android:layout_width="32dp"
    android:layout_height="32dp"
    android:layout_alignParentTop="true"
    android:layout_centerHorizontal="true"
    app:srcCompat="@android:drawable/spinner_background"/>
Run Code Online (Sandbox Code Playgroud)

UserViewDialog.java

将以下代码添加到onCreate方法(Fragment,Activity)或构造函数(Dialog):

NetworkImageView profilePicture = view.findViewById(R.id.profile_picture);
profilePicture.setImageUrl("http://example.com/users/images/profile.jpg", ImageFetch.getImageLoader(getContext());
Run Code Online (Sandbox Code Playgroud)

毕加索

Square的另一个优秀图书馆.请访问该网站以获取一些很好的例子:http://square.github.io/picasso/


Nab*_*bin 16

简单来说,

不要在UI线程中进行网络工作

例如,如果您执行HTTP请求,那就是网络操作.

解:

  1. 你必须创建一个新的线程
  2. 或者使用AsyncTask类

办法:

把你所有的作品都放进去

  1. run() 新线程的方法
  2. doInBackground() AsyncTask类的方法.

但:

当您从Network响应中获取某些内容并希望在您的视图中显示它时(如在TextView中显示响应消息),您需要返回到UI线程.

如果你不这样做,你会得到ViewRootImpl$CalledFromWrongThreadException.

如何?

  1. 使用AsyncTask时,从onPostExecute()方法更新视图
  2. 或者runOnUiThread()run()方法内部调用方法和更新视图.


msy*_*ilu 10

虽然上面有一个巨大的解决方案池,但没有人提到com.koushikdutta.ion:https://github.com/koush/ion

它也是异步的,使用起来非常简单:

Ion.with(context)
.load("http://example.com/thing.json")
.asJsonObject()
.setCallback(new FutureCallback<JsonObject>() {
   @Override
    public void onCompleted(Exception e, JsonObject result) {
        // do stuff with the result or error
    }
});
Run Code Online (Sandbox Code Playgroud)


Rav*_*abu 10

已经解释了新的ThreadAsyncTask解决方案.

AsyncTask理想情况下应该用于短期操作.普通Thread不适合Android.

使用HandlerThreadHandler查看备用解决方案

HandlerThread

用于启动具有looper的新线程的方便类.然后可以使用looper来创建处理程序类.请注意,start()仍然必须调用.

处理器:

Handler允许您发送和处理与线程的MessageQueue关联的Message和Runnable对象.每个Handler实例都与一个线程和该线程的消息队列相关联.当您创建一个新的Handler时,它被绑定到正在创建它的线程的线程/消息队列 - 从那时起,它将消息和runnables传递给该消息队列并在消息出来时执行它们队列.

解:

  1. 创建 HandlerThread

  2. 呼叫start()HandlerThread

  3. Handler通过获取Looper来创建HanlerThread

  4. 将与网络操作相关的代码嵌入到Runnable对象中

  5. 提交Runnable任务Handler

示例代码段,其中包含地址 NetworkOnMainThreadException

HandlerThread handlerThread = new HandlerThread("URLConnection");
handlerThread.start();
handler mainHandler = new Handler(handlerThread.getLooper());

Runnable myRunnable = new Runnable() {
    @Override
    public void run() {
        try {
            Log.d("Ravi", "Before IO call");
            URL page = new URL("http://www.google.com");
            StringBuffer text = new StringBuffer();
            HttpURLConnection conn = (HttpURLConnection) page.openConnection();
            conn.connect();
            InputStreamReader in = new InputStreamReader((InputStream) conn.getContent());
            BufferedReader buff = new BufferedReader(in);
            String line;
            while ( (line =  buff.readLine()) != null) {
                text.append(line + "\n");
            }
            Log.d("Ravi", "After IO call");
            Log.d("Ravi",text.toString());

        }catch( Exception err){
            err.printStackTrace();
        }
    }
};
mainHandler.post(myRunnable);
Run Code Online (Sandbox Code Playgroud)

使用这种方法的优点:

  1. Thread/AsyncTask为每个网络操作创建新的是昂贵的.在Thread/AsyncTask将被销毁且下一次网络运营重新创建.但随着HandlerHandlerThread方法,您可以提交许多网络操作(如Runnable的任务),以单HandlerThreadHandler.


yoA*_*ex5 10

您可以将代码的一部分移动到另一个线程中以卸载main thread并避免获取ANR,NetworkOnMainThreadException,IllegalStateException(例如,无法访问主线程上的数据库,因为它可能会长时间锁定UI).

您应该选择一些方法取决于具体情况

Java Thread或Android HandlerThread

Java线程只能一次性使用,并在执行其run方法后死掉.

HandlerThread是一个方便的类,用于启动具有looper的新线程.

的AsyncTask

AsyncTask旨在成为ThreadHandler的辅助类,并不构成通用的线程框架.理想情况下,AsyncTasks应该用于短操作(最多几秒钟.)如果需要保持线程长时间运行,强烈建议您使用java.util.concurrent包提供的各种API,例如Executor,ThreadPoolExecutorFutureTask.

线程池实现ThreadPoolExecutor,ScheduledThreadPoolExecutor ...

实现ExecutorService的ThreadPoolExecutor类,它可以对线程池进行精细控制(例如,核心池大小,最大池大小,保持活动时间等)

ScheduledThreadPoolExecutor - 一个扩展ThreadPoolExecutor的类.它可以在给定延迟之后或定期安排任务.

FutureTask

FutureTask执行异步处理,但是,如果结果尚未就绪或处理尚未完成,则调用get()将阻塞该线程

AsyncTaskLoaders

AsyncTaskLoaders因为它们解决了AsyncTask固有的许多问题

IntentService

这是Android上长时间运行处理的事实选择,一个很好的例子就是上传或下载大文件.即使用户退出应用程序,上传和下载也可能继续,您肯定不希望阻止用户在执行这些任务时使用该应用程序.

的jobscheduler

实际上,您必须使用JobInfo.Builder创建服务并创建作业,该作业指定了何时运行服务的条件.

RxJava

用于通过使用可观察序列来编写异步和基于事件的程序的库.

协同程序(Kotlin)

它的主要内容是,它使异步代码看起来非常像同步

阅读更多内容:
8种在Android中进行异步处理的方法,以及 使用
Android中的线程池计算Android网络访问的演变


小智 9

Android 不允许在主线程上运行长时间运行的操作。

因此,只需使用不同的线程并在需要时将结果发布到主线程即可。

new Thread(new Runnable() {
        @Override
        public void run() {
            /*
            // Run operation here
            */
            // After getting the result
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    // Post the result to the main thread
                }
            });
        }
    }).start();
Run Code Online (Sandbox Code Playgroud)


小智 8

RxAndroid是这个问题的另一个更好的替代方案,它使我们免于创建线程的麻烦,然后在Android UI线程上发布结果.我们只需要指定需要执行任务的线程,并在内部处理所有事务.

Observable<List<String>> musicShowsObservable = Observable.fromCallable(new Callable<List<String>>() { 

  @Override 
  public List<String> call() { 
    return mRestClient.getFavoriteMusicShows(); 
  }
});

mMusicShowSubscription = musicShowsObservable
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<List<String>>() {

    @Override 
    public void onCompleted() { }

    @Override 
    public void onError(Throwable e) { }

    @Override 
    public void onNext(List<String> musicShows){
        listMusicShows(musicShows);
    }
});
Run Code Online (Sandbox Code Playgroud)
  1. 通过指定(Schedulers.io()),RxAndroid将getFavoriteMusicShows() 在不同的线程上运行.

  2. 通过使用AndroidSchedulers.mainThread()我们想在UI线程上观察这个Observable,即我们希望onNext()在UI线程上调用我们的回调


Kac*_*acy 7

这有效.刚刚将Dr.Luiji的答案变得更简单一些.

new Thread() {
    @Override
    public void run() {
        try {
            //Your code goes here
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}.start();
Run Code Online (Sandbox Code Playgroud)


Pon*_*rai 7

在Android上,网络操作无法在主线程上运行.您可以使用Thread,AsyncTask(短期运行任务),Service(长时间运行的任务)来执行网络操作.


Rev*_* V. 7

从主(UI)线程访问网络资源会导致此异常.使用单独的线程或AsyncTask访问网络资源以避免此问题.


Ale*_*tov 7

还有另一种解决此问题的非常方便的方法 - 使用rxJava的并发功能.您可以在后台执行任何任务并以非常方便的方式将结果发布到主线程,因此这些结果将被传递到处理链.

第一个经过验证的答案建议是使用AsynTask.是的,这是一个解决方案,但现在已经过时,因为有新的工具.

String getUrl() {
    return "SomeUrl";
}

private Object makeCallParseResponse(String url) {
    return null;
    //
}

private void processResponse(Object o) {

}
Run Code Online (Sandbox Code Playgroud)

getUrl方法提供URL地址,它将在主线程上执行.

makeCallParseResponse(..) - 做实际工作

processResponse(..) - 将在主线程上处理结果.

异步执行的代码如下所示:

rx.Observable.defer(new Func0<rx.Observable<String>>() {
    @Override
    public rx.Observable<String> call() {
        return rx.Observable.just(getUrl());
    }
})
    .subscribeOn(Schedulers.io())
    .observeOn(Schedulers.io())
    .map(new Func1<String, Object>() {
        @Override
        public Object call(final String s) {
            return makeCallParseResponse(s);
        }
    })
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(new Action1<Object>() {
        @Override
        public void call(Object o) {
             processResponse(o);
        }
    },
    new Action1<Throwable>() {
        @Override
        public void call(Throwable throwable) {
            // Process error here, it will be posted on
            // the main thread
        }
    });
Run Code Online (Sandbox Code Playgroud)

与AsyncTask相比,此方法允许任意次数切换调度程序(例如,在一个调度程序上获取数据并在另一个调度程序上处理这些数据(例如,Scheduler.computation()).您还可以定义自己的调度程序.

要使用此库,请在build.gradle文件中包含以下行:

   compile 'io.reactivex:rxjava:1.1.5'
   compile 'io.reactivex:rxandroid:1.2.0'
Run Code Online (Sandbox Code Playgroud)

最后一个依赖项包括对.mainThread()调度程序的支持.

一个优秀的rx-java电子书.


Rah*_*hul 7

在Android上,网络操作不能在主线程上运行。您可以使用Thread, AsyncTask(short-running tasks), Service(long-running tasks) 进行网络操作。android.os.NetworkOnMainThreadException当应用程序尝试在其主线程上执行网络操作时抛出。如果您的任务耗时超过 5 秒,则需要强制关闭。

运行您的代码AsyncTask

class FeedTask extends AsyncTask<String, Void, Boolean> {

    protected RSSFeed doInBackground(String... urls) {
       // TODO: Connect
    }

    protected void onPostExecute(RSSFeed feed) {
        // TODO: Check this.exception
        // TODO: Do something with the feed
    }
}
Run Code Online (Sandbox Code Playgroud)

或者

new Thread(new Runnable(){
    @Override
    public void run() {
        try {
            // Your implementation
        }
        catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}).start();
Run Code Online (Sandbox Code Playgroud)

不建议这样做。

但出于调试目的,您也可以使用以下代码禁用严格模式:

if (android.os.Build.VERSION.SDK_INT > 9) {
    StrictMode.ThreadPolicy policy =
        new StrictMode.ThreadPolicy.Builder().permitAll().build();
    StrictMode.setThreadPolicy(policy);
}
Run Code Online (Sandbox Code Playgroud)


小智 7

Google 在 Android 11 中弃用了 Android AsyncTask API。

\n

即使您在主活动之外创建线程类,仅通过在主活动中调用它,您也会得到相同的错误。这些调用必须在可运行线程内,但如果您需要一些异步代码在后台执行或稍后在此处执行,您可以查看 Kotlin 和 Java 的一些替代方案:

\n
*/sf/ask/4113741341/*\n
Run Code Online (Sandbox Code Playgroud)\n

对我特别有用的是 mayank1513 的答案,用于在上面的链接上找到的可运行线程的Java\xc2\xa08实现。代码如下:

\n
new Thread(() -> {\n    // do background stuff here\n    runOnUiThread(() -> {\n        // OnPostExecute stuff here\n    });\n}).start();\n
Run Code Online (Sandbox Code Playgroud)\n

但是,您可以首先在代码的某些部分定义线程,然后在其他地方启动它,如下所示:

\n

线程定义

\n
Thread thread = new Thread(() -> {\n    // do background stuff here\n    runOnUiThread(() -> {\n        // OnPostExecute stuff here\n    });\n});\n
Run Code Online (Sandbox Code Playgroud)\n

线程调用

\n
thread.start();\n
Run Code Online (Sandbox Code Playgroud)\n

我希望这可以避免某人因看到已弃用的而感到头疼AsyncTask

\n


小智 6

您不能在Android上的UI线程上实现网络操作.你将不得不使用AsyncTask类来执行网络相关的操作,如发送API请求,从URL下载图像等,并使用AsyncTask的回调方法,你可以得到onPostExecute menthod的结果,你将在UI线程和你可以使用来自Web服务或类似内容的数据填充UI.

示例:假设您要从URL下载图像:https://www.samplewebsite.com/sampleimage.jpg

使用AsyncTask的解决方案:分别是.

    public class MyDownloader extends AsyncTask<String,Void,Bitmap>
    {
        @Override
        protected void onPreExecute() {
            // Show progress dialog
            super.onPreExecute();
        }

        @Override
        protected void onPostExecute(Bitmap bitmap) {
            //Populate Ui
            super.onPostExecute(bitmap);
        }

        @Override
        protected Bitmap doInBackground(String... params) {
            // Open URL connection read bitmaps and return form here
            return result;
        }

        @Override
        protected void onProgressUpdate(Void... values) {
            // Show progress update
            super.onProgressUpdate(values);
        }


    }
}
Run Code Online (Sandbox Code Playgroud)

注意:不要忘记在Android清单文件中添加Internet权限.它会像魅力一样工作.:)


J.D*_*731 6

你可以使用KOTLINANKO.

KotlinAndroid的新官方语言更多关于它你可以在这里找到 https://kotlinlang.org/docs/tutorials/kotlin-android.html

Anko支持Android中的Kotlin库,其中一些文档 https://github.com/Kotlin/anko

该解决方案非常实用,只有少量代码由@AntonioLeiva编写 https://antonioleiva.com/anko-background-kotlin-android/

doAsync {
    var result = runLongTask()
    uiThread {
        toast(result)
    }
}
Run Code Online (Sandbox Code Playgroud)

虽然很简单,但是NetworkOnMainThread当您运行后台作业时,UI Thread您需要做的就是longTask job在后台运行您的工作.您可以在Android App中使用此方法和KotlinAnko一起执行此操作.

  • 从 GitHub 页面:*“Anko 已弃用。请参阅[此页面](https://github.com/Kotlin/anko/blob/master/GOODBYE.md) 了解更多信息。”* (2认同)

sha*_*mar 6

主线程是UI线程,并且您无法在主线程中执行可能阻止用户交互的操作。您可以通过两种方式解决此问题:

像这样强制在主线程中执行任务

StrictMode.ThreadPolicy threadPolicy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(threadPolicy);
Run Code Online (Sandbox Code Playgroud)

或创建一个简单的处理程序并根据需要更新主线程。

Runnable runnable;
Handler newHandler;

newHandler = new Handler();
runnable = new Runnable() {
    @Override
    public void run() {
         try {
            //update UI
        } catch (Exception e) {
            e.printStackTrace();
        } 
    }
};
newHandler.post(runnable);
Run Code Online (Sandbox Code Playgroud)

并停止使用该线程:

newHandler.removeCallbacks(runnable);
Run Code Online (Sandbox Code Playgroud)

有关更多信息,请查看以下内容:无痛线程


El *_*boi 6

科特林

如果您使用 Kotlin,则可以使用协程

fun doSomeNetworkStuff() {
    GlobalScope.launch(Dispatchers.IO) {
        // ...
    }
}
Run Code Online (Sandbox Code Playgroud)


Adn*_*aki 5

当应用程序尝试在其主线程上执行网络操作时会抛出此异常。如果您的任务耗时超过 5 秒,则需要强制关闭。

运行您的代码AsyncTask

class RetrieveFeedTask extends AsyncTask<String, Void, Boolean> {

    protected RSSFeed doInBackground(String... urls) {
       // TODO: Connect
    }

    protected void onPostExecute(RSSFeed feed) {
        // TODO: Check this.exception
        // TODO: Do something with the feed
    }
}
Run Code Online (Sandbox Code Playgroud)


bpr*_*r10 5

我们还可以使用RxJava将网络操作移至后台线程。它也相当简单。

webService.doSomething(someData)
          .subscribeOn(Schedulers.newThread())-- This for background thread
          .observeOn(AndroidSchedulers.mainThread()) -- for callback on UI
          .subscribe(result -> resultText.setText("It worked!"),
              e -> handleError(e));
Run Code Online (Sandbox Code Playgroud)

你可以用 RxJava 做更多的事情。这里有一些 RxJava 的链接。随意挖掘。

Android 中的 RxJava 异步任务

http://blog.stablekernel.com/replace-asynctask-asynctaskloader-rx-observable-rxjava-android-patterns/


小智 5

You can also resolve this issue by using Strict Mode using the below code. It's also an alternative to resolving this issue.

StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
Run Code Online (Sandbox Code Playgroud)

But the best practice would be to use AsyncTask.


归档时间:

查看次数:

1152959 次

最近记录:

5 年,11 月 前