如何修复android.os.NetworkOnMainThreadException?

amodi 发布于 2018-11-18 android 最后更新 2018-11-18 08:28 82 浏览

我在运行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();
它显示下面的错误:
android.os.NetworkOnMainThreadException
我该如何解决这个问题?
已邀请:

zsed

赞同来自:

您必须在清单标记后的manifest.xml中简单地添加以下行

<uses-permission android:name="android.permission.INTERNET"/>
并在活动文件中在绑定语句后添加以下代码
if (android.os.Build.VERSION.SDK_INT > 9) {
   StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
   StrictMode.setThreadPolicy(policy);
}

ab_non

赞同来自:

对我来说就是这样:

<uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="10" />
我测试我的应用程序的设备是4.1.2,这是SDK版本16! 确保目标版本与Android目标库相同。如果您不确定目标库是什么,请右键单击您的项目 - >构建路径 - > Android,它应该是勾选的那个。 此外,正如其他人所提到的,包括访问Internet的正确权限:
<uses-permission android:name="android.permission.INTERNET"/>

bsequi

赞同来自:

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

mneque

赞同来自:

把你的代码放在里面:

new Thread(new Runnable(){
    @Override
    public void run() {
        try {
            // Your implementation
        }
        catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}).start();
要么:
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
    }
}

ksequi

赞同来自:

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

For Example:
new Thread(new Runnable(){
    @Override
    public void run() {
        // Do network action in this function
    }
}).start();
并将其添加到AndroidManifest.xml
<uses-permission android:name="android.permission.INTERNET"/>

yvitae

赞同来自:

虽然上面有一个巨大的解决方案池,但没有人提到com.koushikdutta.ionhttps://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
    }
});

ehic

赞同来自:

我以一种简单的方式解决了这个问题...... 我在oncreate StrictMode.enableDefaults();之后添加并解决了这个问题。 要么 使用ServiceAsyncTask来解决这个问题 注意:

Do not change SDK version
Do not use a separate thread
更多信息,请访问check this

sunde

赞同来自:

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);
    }
});
  1. 通过指定(Schedulers.io()),RxAndroid将在另一个线程上运行getFavoriteMusicShows()
  2. 通过使用AndroidSchedulers.mainThread(),我们希望在UI线程上观察此Observable,即我们希望在UI线程上调用onNext()回调

aut_ea

赞同来自:

还有另一种解决此问题的非常方便的方法 - 使用rxJava的并发功能。您可以在后台执行任何任务,并以非常方便的方式将结果发布到主线程,因此这些结果将被传递到处理链。 第一个经过验证的答案建议是使用AsynTask。是的,这是一个解决方案,但现在已经过时,因为有新的工具。

String getUrl() {
    return "SomeUrl";
}
private Object makeCallParseResponse(String url) {
    return null;
    //
}
private void processResponse(Object o) {
}
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
        }
    });
与AsyncTask相比,此方法允许任意次数切换调度程序(例如,在一个调度程序上获取数据并在另一个调度程序上处理这些数据(例如,Scheduler.computation())。您还可以定义自己的调度程序。 要使用此库,请在build.gradle文件中包含以下行:
   compile 'io.reactivex:rxjava:1.1.5'
   compile 'io.reactivex:rxandroid:1.2.0'
最后一个依赖项包括对.mainThread()调度程序的支持。 有an excellent ebook for rx-java

zamet

赞同来自:

由于Android正在处理单个线程,因此不应对主线程执行任何网络操作。有各种方法可以避免这种情况。 使用以下方法执行网络操作

  • Asysnctask:对于不花费太多时间的小型操作。
  • 意图服务:用于需要花费大量时间的网络操作。
  • 使用Volley和Retrofit等自定义库进行处理 复杂的网络运营
永远不要使用StrictMode.setThreadPolicy(策略),因为它会冻结你的UI,并不是一个好主意。

isit

赞同来自:

使用以下代码执行繁重的任务。

// Your package here
import java.util.List;
import org.apache.http.NameValuePair;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.os.AsyncTask;
import android.view.View.OnSystemUiVisibilityChangeListener;
public class AsyncRequest extends AsyncTask<String, Integer, String> {
Context context;
    ProgressDialog pDialog;
// Three Constructors
    public AsyncRequest(Activity a, String m, List<NameValuePair> p) {
        context = a;
        method = m;
        parameters = p;
    }
public AsyncRequest(Activity a) {
        this.caller = (OnAsyncRequestComplete) a;
        context = a;
    }
public String doInBackground(String... urls) {
//Perform your task here
        return result;
    }
public void onPreExecute() {
        pDialog = new ProgressDialog(context);
        pDialog.setMessage("Please wait..");
        pDialog.setCancelable(false);
        pDialog.show();
    }
public void onProgressUpdate(Integer... progress) {
        // You can implement some progressBar and update it in this record.
        //   setProgressPercent(progress[0]);
    }
public void onPostExecute(String response) {
        if (pDialog != null && pDialog.isShowing()) {
            pDialog.dismiss();
        }
        // Get the result here
    }
protected void onCancelled(String response) {
if (pDialog != null && pDialog.isShowing()) {
            pDialog.dismiss();
        }
    }
}

amodi

赞同来自:

我使用新的Thread解决了这个问题。

Thread thread = new Thread(new Runnable() {
@Override
    public void run() {
        try  {
            //Your code goes here
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
});
thread.start(); 

nquis

赞同来自:

你实际上可以开始一个新线程,我以前遇到过这个问题并通过这种方式解决了它。

aad

赞同来自:

我们还可以使用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));
你可以用RxJava做更多的东西。这里有一些RxJava的链接。随意挖掘。 RxJava Async task in Android http://blog.stablekernel.com/replace-asynctask-asynctaskloader-rx-observable-rxjava-android-patterns/

zipsum

赞同来自:

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

if (android.os.Build.VERSION.SDK_INT > 9) {
    StrictMode.ThreadPolicy policy = 
        new StrictMode.ThreadPolicy.Builder().permitAll().build();
    StrictMode.setThreadPolicy(policy);
}
建议不要这样做:使用AsyncTask接口。 Full code for both the methods

vvel

赞同来自:

Android不允许单独的进程进入主活动线程,并且HTTP连接是一个独立的线程。这就是你得到“android.os.NetworkOnMainThreadException”的原因。 在向用户显示webview之前,您可能需要检查实际的Internet连接,因为如果没有Internet,Web视图将向用户显示找不到页面的错误,通常您不显示该内容。 要检查Internet可用性,可以使用ping命令,但是如果可以在Wi-Fi服务器上禁用Wi-Fi ping,则在这种情况下,您可以使用HTTP连接来检查请求的状态。 如果您在向用户显示webview之前检查自己的webview URL链接,这可能是正确的方法。在这种情况下,您可以使用Android的严格模式,但不允许所有策略,因为您不需要它。 您应该只为严格模式提供网络允许策略。只需将以下行添加到您的代码中,您就不会收到此错误。

StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitNetwork().build();
StrictMode.setThreadPolicy(policy);

umodi

赞同来自:

  1. 不要使用strictMode(仅在调试模式下)
  2. 请勿更改SDK版本
  3. 不要使用单独的线程
使用Service或AsyncTask 另请参阅Stack 溢出问题: android.os.NetworkOnMainThreadException sending an email from Android

malias

赞同来自:

发生NetworkOnMainThread异常是因为您在默认线程(即UI线程)上调用了一些网络操作。 根据不允许的Android版本Android 3(Honeycomb),您应该在主线程之外调用网络操作。 您可以使用AsyncTask,IntentService或创建自己的线程并在run方法中调用。 有关更多信息,请访问Connecting to the Network

nipsa

赞同来自:

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

// normal method
private void normal() {
    doSomething(); // do something in background
}
@Background
protected void doSomething() 
    // run your networking code here
}
请注意,虽然它提供了简单性和可读性的好处,但它有其缺点。

lnon

赞同来自:

2017答案: 关于这个问题已经有很多很好的答案了,但是自从这些答案发布以来,已经出现了许多优秀的图书馆。这是一种新手指南。 我将介绍几个用于执行网络操作的用例和一个或两个解决方案。

通过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)

从Square改造 对于具有多个端点的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
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);
}
FinancesApiBuilder
public class FinancesApiBuilder {
    public static FinancesApi build(String baseUrl){
        return new Retrofit.Builder()
                    .baseUrl(baseUrl)
                    .addConverterFactory(GsonConverterFactory.create())
                    .build()
                    .create(FinancesApi.class);
    }
}
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
    }
}
如果您的API要求发送API密钥或其他标头(如用户令牌等),则Retrofit会使这一过程变得简单(有关详细信息,请参阅此极好的答案:https://stackoverflow.com/a/42899766/1024412)。

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

离子 对于这种类型的访问,这是一个很棒的库。 请阅读msysmilu的好答案(https://stackoverflow.com/a/28559884/1024412)

通过HTTP 加载图像

排球 Volley也可以用于ReST API,但由于需要更复杂的设置,我更喜欢使用Square上面的Retrofit(http://square.github.io/retrofit/) 假设您正在构建社交网络应用,并希望加载朋友的个人资料照片。 的build.gradle 将此行添加到模块级别buid.gradle:
implementation 'com.android.volley:volley:1.0.0'
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;
    }
}
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"/>
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());

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

uet

赞同来自:

该错误是由于在主线程中执行长时间运行操作,您可以使用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
    }
});

godio

赞同来自:

您无法在Honeycomb上的UI线程上执行网络I/O。从技术上讲,它可以在早期版本的Android上,但它是一个非常糟糕的主意,因为它会导致您的应用程序停止响应,并可能导致操作系统因为行为不当而导致您的应用程序被杀。您需要运行后台进程或使用AsyncTask在后台线程上执行网络事务。 Android开发者网站上有一篇关于Painless Threading的文章,这是对此的一个很好的介绍,它将为您提供比这里实际提供的更好的答案深度。

set

赞同来自:

简单来说, 不要在UI线程中进行网络工作 例如,如果您执行HTTP请求,那就是网络操作。 解:

  1. 您必须创建新的主题
  2. 或使用AsyncTask class
办法: 把你所有的作品都放进去
  1. 新线程的run()方法
  2. 或AsyncTask类的doInBackground()方法。
但: 当您从Network响应中获取某些内容并希望在视图中显示它时(如在TextView中显示响应消息),您需要返回UI线程。 如果你不这样做,你将得到ViewRootImpl$CalledFromWrongThreadException。 如何?
  1. 使用AsyncTask时,从onPostExecute()方法更新视图
  2. 或调用runOnUiThread()方法并更新run()方法内的视图。

weos

赞同来自:

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

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

sest

赞同来自:

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

yut

赞同来自:

这种情况发生在Android 3.0及更高版本中。从Android 3.0及更高版本开始,他们限制使用网络操作(访问Internet的功能)在主线程/ UI线程中运行(从创建活动产生的内容和活动中的恢复方法)。 这是为了鼓励使用单独的线程进行网络操作。有关如何以正确方式执行网络活动的更多详细信息,请参阅AsyncTask

oenim

赞同来自:

您应该几乎总是在线程上运行网络操作或作为异步任务。但是,如果您更了解并愿意接受后果,并且必须在主线程上执行网络操作,则可以覆盖默认行为: 加:

StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy); 
在你的班上, 和 在android manifest.xml文件中添加此权限:
<uses-permission android:name="android.permission.INTERNET"/>
后果: 您的应用程序将(在互联网连接不稳定的区域)变得无法响应并锁定,用户感知缓慢并且必须执行强制终止,并且您冒着活动管理器杀死您的应用并告诉用户该应用已停止的风险。 Android提供了一些关于良好编程实践的好技巧,以设计响应性: http://developer.android.com/reference/android/os/NetworkOnMainThreadException.html

jautem

赞同来自:

基于网络的操作无法在主线程上运行。您需要在子线程上运行所有基于网络的任务或实现AsyncTask。 这是您在子线程中运行任务的方式:

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

hid

赞同来自:

您不能在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);
        }
}
}
注意:不要忘记在Android清单文件中添加Internet权限。它会像魅力一样工作。 :)

lillo

赞同来自:

您可以使用KOTLINANKO。 Kotlin是Android的新官方语言,您可以在这里找到更多关于它的信息 https://kotlinlang.org/docs/tutorials/kotlin-android.html Anko支持Android中的Kotlin库,这里有一些doc https://github.com/Kotlin/anko 该解决方案非常有用,只有少量代码由@AntonioLeiva编写 https://antonioleiva.com/anko-background-kotlin-android/

doAsync {
    var result = runLongTask()
    uiThread {
        toast(result)
    }
}
虽然很简单,但是当您在UI Thread上运行后台作业时会发生NetworkOnMainThread,因此您需要做的一件事就是在后台运行您的longTask job。您可以在Android应用中使用此方法和Kotlin与Anko一起执行此操作。

equia

赞同来自:

如何修复android.os.NetworkOnMainThreadException 什么是NetworkOnMainThreadException: 在Android中,我们必须在UI线程(主线程)上执行所有UI操作。如果我们在主线程上执行后台操作或某些网络操作,那么我们冒这个异常的风险,应用程序将不会响应。 如何解决: 要避免此问题,您必须使用另一个线程进行后台操作或网络操作,例如使用asyncTask并使用某些库进行网络操作,如Volley,AsyncHttp等。

set

赞同来自:

当应用程序尝试在其主线程上执行网络操作时,将引发此异常。在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
    }
}
如何执行任务: 在MainActivity.java文件中,您可以在oncreate()方法中添加此行
new RetrieveFeedTask().execute(urlToRssFeed);
不要忘记将其添加到AndroidManifest.xml文件中:
<uses-permission android:name="android.permission.INTERNET"/>

gquia

赞同来自:

    **Use like this in Your Activity**
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 inten=new Intent(getApplicationContext(),ComposeMail.class);
            //intent.putParcelableArrayListExtra("valuesList", value);
startActivity(inten);
}
            }).start();
        }
    });

est_ut

赞同来自:

如果执行任务花费太多时间,则会在主线程上执行任何繁重的任务,从而发生此异常。 为避免这种情况,我们可以使用线程或执行器来处理它

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

uid

赞同来自:

永远不要在UI线程上进行任何长时间的工作,长时间运行的工作可以是与服务器的通信,读/写文件等。这些任务应该在后台线程上,这就是创建ServiceAsyncTaskThreads的原因。您可以禁用StrictMode,以防止崩溃但从未建议过。 我建议你在调试模式下至少利用StrictMode。使用下面的代码来获取在主线程上减慢应用程序速度的任何问题的日志。

StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
            .detectAll()
            .penaltyLog()
            .build());
你可以设置不同的处罚 -
penaltyLog() // to print log
penaltyDeath() // This will crash you App(so costly penalty)
penaltyDialog() // Show alert when something went lazy on Main thread
有很多关于https://developer.android.com/reference/android/os/StrictMode.html的内容

xnemo

赞同来自:

当应用程序尝试在其主线程上执行网络操作时,将引发此异常。 如果您的任务花了五秒钟以上,则需要关闭一个力量。 在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
    }
}

cea

赞同来自:

顶级answer of spektom非常适合。 如果您正在编写AsyncTask内联而不是作为类扩展,并且除此之外,如果需要从AsyncTask中获取响应,则可以使用get()方法,如下所示。

RSSFeed feed = new RetreiveFeedTask().execute(urlToRssFeed).get();
(从他的例子。)

podio

赞同来自:

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

  • 作为非静态内部类创建的AsyncTask具有对封闭的Activity对象,其上下文以及该活动创建的整个View层次结构的隐式引用。此引用可防止在AsyncTask的后台工作完成之前对Activity进行垃圾回收。如果用户的连接速度很慢,和/或下载量很大,则这些短期内存泄漏可能会成为问题 - 例如,如果方向发生多次更改(并且您没有取消正在执行的任务),或者用户导航远离活动。
  • AsyncTask具有不同的执行特性,具体取决于它执行的平台:API级别4之前AsyncTasks在单个后台线程上串行执行;从API级别4到API级别10,AsyncTasks在最多128个线程的池上执行;从API级别11开始,AsyncTask在单个后台线程上串行执行(除非您使用重载的executeOnExecutor方法并提供备用执行程序)。当在Gingerbread上同时执行时,在ICS上串行运行的代码可能会中断,例如,如果您有无意的执行顺序依赖项。
如果您想避免短期内存泄漏,在所有平台上都有明确定义的执行特性,并且有基础来构建非常强大的网络处理,您可能需要考虑:
  1. 使用一个能为您做好工作的库 - 在this question
  2. 中对网络库进行了很好的比较
  3. 改为使用ServiceIntentService,也许使用PendingIntent通过活动的onActivityResult方法返回结果。

IntentService方法 下行方面:
  • AsyncTask更多的代码和复杂性,尽管没有您想象的那么多
  • 将队列请求排队并在单个后台线程上运行它们。您可以通过将IntentService替换为等效的Service实现(可能类似于this one)来轻松控制。
  • 嗯,我现在想不出任何其他人
向上方面:
  • 避免短期内存泄漏问题
  • 如果您的活动在网络操作正在进行时重新启动,它仍然可以通过其onActivityResult方法接收下载结果
  • 比AsyncTask更好的平台,可以构建和重用强大的网络代码。示例:如果您需要进行重要上传,可以从AsyncTask中的PLACEHOLDER_FOR_CODE_11进行,但如果用户上下文 - 从应用程序切换出来进行电话呼叫,系统可能会在上传完成之前终止应用程序。使用有效的Service杀死应用程序的可能性较小。
  • 如果您使用自己的IntentService并发版本(就像我上面链接的那样),您可以通过Executor来控制并发级别。

实施摘要 您可以非常轻松地实现IntentService以在单个后台线程上执行下载。 步骤1:创建IntentService以执行下载。您可以通过Intent extra来告诉它下载什么,并将其传递给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);
        }
    }
}
第2步:在清单中注册服务:
<service
        android:name=".DownloadIntentService"
        android:exported="false"/>
步骤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);
第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);
}
包含完整的Android-Studio / gradle项目的github项目可用于here

lquia

赞同来自:

在主线程上执行网络操作时抛出android.os.NetworkOnMainThreadException。您最好在AsyncTask中执行此操作以删除此异常。这样写:

    new AsyncTask<Void,String,String>(){
@Override
        protected Void doInBackground(Void... params) {
            // Perform your network operation.
            // Get JSON or XML string from the server.
            // Store in a local variable (say response) and return.
            return response;
        }
protected void onPostExecute(String results){
            // Response returned by doInBackGround() will be received
            // by onPostExecute(String results).
            // Now manipulate your jason/xml String(results).
        }
}.execute();
}

xminus

赞同来自:

只是明确说明一些事情: 主线程基本上是UI线程。 所以说你不能在主线程中进行网络操作意味着你不能在UI线程中进行网络操作,这意味着你不能在其他线程内的runOnUiThread(new Runnable() { ... }块中进行网络操作。 (我只是想知道为什么我在主线程以外的其他地方得到了这个错误。我只是有一个长期头痛的时刻。这就是为什么;这个线程帮助了;希望这个评论会帮助其他人。)

nodio

赞同来自:

您不应该在主线程(UI线程)上执行任何耗时的任务,例如任何网络操作,文件I / O或SQLite数据库操作。因此,对于这种操作,您应该创建一个工作线程,但问题是您无法直接从工作线程执行任何与UI相关的操作。为此,您必须使用Handler并传递Message。 为简化所有这些操作,Android提供了多种方式,例如AsyncTaskAsyncTaskLoaderCursorLoaderIntentService。因此,您可以根据您的要求使用其中任何一种。

gcum

赞同来自:

您还可以使用以下代码使用严格模式来解决此问题。它也是解决此问题的替代方案。

StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
但最好的做法是使用AsyncTask。

punde

赞同来自:

主线程是UI线程,你不能在主线程中进行操作,这可能会阻止用户Interaction.You可以通过两种方式解决这个问题 强制像这样在mainthread中执行任务

StrictMode.ThreadPolicy threadPolicy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(threadPolicy );
或者创建一个简单的处理程序并根据需要更新主线程。
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);
并停止使用线程
newHandler.removeCallbacks(runnable);
有关详细信息,请查看此信息。 https://android-developers.googleblog.com/2009/05/painless-threading.html

equia

赞同来自:

已经解释了新的ThreadAsyncTask解决方案。 理想情况下,AsyncTask应用于短期操作。正常的Thread不适合Android。 使用HandlerThreadHandler查看备用解决方案 HandlerThread

Handy class for starting a new thread that has a looper. The looper can then be used to create handler classes. Note that start() must still be called.
处理器:
A Handler allows you to send and process Message and Runnable objects associated with a thread's MessageQueue. Each Handler instance is associated with a single thread and that thread's message queue. When you create a new Handler, it is bound to the thread / message queue of the thread that is creating it -- from that point on, it will deliver messages and runnables to that message queue and execute them as they come out of the message queue.
解:
  1. 创建HandlerThread
  2. HandlerThread上致电start()
  3. 通过从HanlerThread获取Looper来创建Handler
  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);
使用这种方法的优点:
  1. 为每个网络操作创建新的Thread/AsyncTask非常昂贵。 Thread/AsyncTask将被销毁,并为下一次网络操作重新创建。但是使用HandlerHandlerThread方法,您可以使用Handler将多个网络操作(作为Runnable任务)提交到单个HandlerThread

oenim

赞同来自:

您无法在主线程或UI线程上调用网络。在Android上如果你想呼叫网络有两种选择 -

  1. 调用asynctask,它将运行一个后台线程来处理网络操作。
  2. 您可以创建自己的可运行线程来处理网络操作。
我个人更喜欢asynctask。有关详细信息,请参阅this link

eea

赞同来自:

仅针对Honeycomb SDK或更高版本的应用程序抛出此操作。针对早期SDK版本的应用程序可以在其主事件循环线程上进行联网。 The error is the SDK warning!

要回复问题请先登录注册