如何修复android.os.NetworkOnMainThreadException?

时间:2011-06-14 12:02:00

标签: java android networkonmainthread thread-exceptions

在为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

如何解决此问题?

63 个答案:

答案 0 :(得分:2423)

当应用程序尝试在其主线程上执行网络操作时,抛出此异常。在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"/>

答案 1 :(得分:626)

您几乎应该始终在线程上运行网络操作或作为异步任务。

可以删除此限制,如果您愿意接受后果,则覆盖默认行为。

添加:

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

答案 2 :(得分:391)

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

Thread thread = new Thread(new Runnable() {

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

thread.start(); 

答案 3 :(得分:148)

接受的答案有一些重要的缺点。除非您确实知道您在做什么,否则不建议使用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. 改为使用ServiceIntentService,也许使用PendingIntent通过活动的onActivityResult方法返回结果。
  3. IntentService方法

    向下侧:

    • AsyncTask更多的代码和复杂性,尽管没有您想象的那么多
    • 将对请求进行排队并在单个后台线程上运行它们。您可以通过将IntentService替换为等效的Service实现来轻松控制此操作,可能与this one类似。
    • 嗯,我现在想不出任何其他人

    向上侧:

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

    实施摘要

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

    步骤1:创建IntentService以执行下载。您可以通过Intent额外信息告诉它要下载什么,然后传递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对象,服务将使用该对象返回结果:

    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

答案 4 :(得分:139)

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

在Android开发者网站上有一篇关于Painless Threading的文章,这是对此的一个很好的介绍,它将为您提供比这里实际提供的更好的答案深度。

答案 5 :(得分:71)

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

    另请参阅Stack Overflow问题:

    android.os.NetworkOnMainThreadException sending an email from Android

答案 6 :(得分:66)

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

  

例如:

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

并将其添加到AndroidManifest.xml

<uses-permission android:name="android.permission.INTERNET"/>

答案 7 :(得分:56)

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

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

答案 8 :(得分:49)

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

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

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

答案 9 :(得分:46)

将您的代码放入:

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
    }
}

答案 10 :(得分:43)

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

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

@Background
protected void doSomething() 
    // run your networking code here
}

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

答案 11 :(得分:42)

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

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

答案 12 :(得分:39)

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

答案 13 :(得分:38)

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

为简化所有这些事项,Android提供了多种方式,例如AsyncTaskAsyncTaskLoaderCursorLoaderIntentService。因此,您可以根据自己的要求使用其中任何一种。

答案 14 :(得分:37)

顶部answer of spektom效果很好。

如果您正在编写AsyncTask内联而不是作为一个类进行扩展,并且除此之外,如果需要从AsyncTask中获取响应,则可以使用{ {1}}方法如下。

get()

(从他的例子开始。)

答案 15 :(得分:31)

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

The error is the SDK warning!

答案 16 :(得分:26)

对我来说就是这样:

<uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="10" />

我正在测试我的应用程序的设备是4.1.2,它是SDK Version 16!

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

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

<uses-permission android:name="android.permission.INTERNET"/>

答案 17 :(得分:23)

明确说明一些事情:

主线程基本上是UI线程。

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

(我只是有一个很长的头脑,试图弄清楚为什么我在主线程以外的地方得到了这个错误。这就是为什么;这个帖子有帮助;希望这个评论会帮助其他人。)

答案 18 :(得分:21)

如果执行任务执行太多时间,则会因主线程执行任何繁重任务而发生此异常。

为避免这种情况,我们可以使用线程执行者

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

答案 19 :(得分:20)

在您的活动中使用此

    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();
        }
    });

答案 20 :(得分:16)

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

我将介绍几个用于执行网络操作的用例和一个解决方案,或者每个用例。

通过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访问

让我们说你正在建立一个情绪化的天气&#34;应用程序查找用户的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/

答案 21 :(得分:15)

简单来说,

不要在网络中进行网络工作

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

<强>解决方案:

  1. 您必须创建新的主题
  2. 使用AsyncTask class
  3. <强>方式:

    将所有作品放入

    1. run()新主题的方法
    2. doInBackground() AsyncTask类的方法。
    3. <强>可是:

      当您从网络响应中获得某些内容并希望在您的视图中显示它时(如在TextView中显示响应消息),您需要返回到UI 主题。

      如果你不这样做,你将获得ViewRootImpl$CalledFromWrongThreadException

      如何?

      1. 使用AsyncTask时,请从onPostExecute()方法
      2. 更新视图
      3. run()方法中调用runOnUiThread()方法和更新视图。

答案 22 :(得分:10)

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

答案 23 :(得分:9)

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

理想情况下,

AsyncTask应用于短期操作。普通Thread不适合Android。

使用HandlerThreadHandler

查看备用解决方案

<强> HandlerThread

  

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

<强>处理程序:

  

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

解决方案:

  1. 创建HandlerThread

  2. start()

  3. 上致电HandlerThread
  4. Handler

  5. 获取Looper来创建HanlerThread
  6. Runnable对象

  7. 中嵌入与网络操作相关的代码
  8. Runnable任务提交至Handler

  9. 示例代码段,其地址为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是很昂贵的。 {@ 1}}将被销毁,并为下一次网络操作重新创建。但是,使用Thread/AsyncTaskHandler方法,您可以使用HandlerThread向单个HandlerThread提交许多网络操作(作为Runnable任务)。

答案 24 :(得分:9)

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

根据具体情况,您应该选择一些方法

Java Thread或Android HandlerThread

  

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

     

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

AsyncTask

  

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

线程池实施ThreadPoolExecutorScheduledThreadPoolExecutor ...

  

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

     

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

FutureTask

  

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

AsyncTaskLoaders

  

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

IntentService

  

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

JobScheduler

  

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

RxJava

  

使用可观察序列编写异步和基于事件的程序的库。

Coroutines(Kotlin)

  

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

在这里阅读更多:
8 ways to do asynchronous processing in Android and counting
The Evolution of Android Network Access
Using a Thread Pool in Android
Managing Threads and Custom Services

答案 25 :(得分: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);
    }
});
  1. 通过指定(Schedulers.io()),RxAndroid将在另一个主题上运行getFavoriteMusicShows()

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

答案 26 :(得分:7)

这很有效。刚刚让Dr.Luiji的答案变得更简单了。

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

答案 27 :(得分:7)

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

答案 28 :(得分:7)

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

答案 29 :(得分:6)

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

示例:假设您要从网址下载图片: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权限。它会像魅力一样工作。 :)

答案 30 :(得分:6)

您可以使用KOTLINANKO

Kotlin Android的新官方语言更多关于它的信息,你可以在这里找到 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)
    }
}

简单,NetworkOnMainThreadUI Thread上运行后台作业时发生longTask job,因此您需要做的一件事就是在后台运行ol { padding-left: 0; } ol>li { list-style-type: none; counter-increment: list; position: relative; padding-left: 30px; } ol>li:before { content: counter(list) "."; position: absolute; /* right: calc(100% - 25px); this is the same as "left: 5px" */ right: calc(100% - 20px); /* this will probably look better */ }。您可以在Android应用中使用此方法和 Kotlin Anko 进行此操作。

答案 31 :(得分:6)

还有另一种解决此问题的非常方便的方法 - 使用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

答案 32 :(得分:5)

在Android上,网络操作无法在主线程上运行。您可以使用ThreadAsyncTask(短期任务),Service(长期任务)来进行网络操作。当应用程序尝试在其主线程上执行联网操作时,将引发android.os.NetworkOnMainThreadException。如果您的任务花费了五秒钟以上的时间,则需要强制关闭。

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
    }
}

OR

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

不推荐这样做。 但是出于调试目的,您也可以使用以下代码禁用严格模式:

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

答案 33 :(得分:5)

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

强制在主线程中执行此任务

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);

有关详细信息,请查看以下内容: Painless threading

答案 34 :(得分:4)

当应用程序尝试在其主线程上执行网络操作时,抛出此异常。 如果你的任务花了五秒钟以上,就需要关闭它。

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
    }
}

答案 35 :(得分:4)

您还可以使用以下代码使用严格模式解决此问题。它也是解决这个问题的另一种选择。

&array[3][0]

但最好的做法是使用AsyncTask。

答案 36 :(得分:4)

科特林

如果您使用的是Kotlin,则可以使用coroutine

fun doSomeNetworkStuff() {
    GlobalScope.launch(Dispatchers.IO) {
        // ...
    }
}

答案 37 :(得分:4)

如何修复android.os.NetworkOnMainThreadException

什么是NetworkOnMainThreadException:

在Android中,我们必须在UI线程(主线程)上执行所有UI操作。如果我们在主线程上执行后台操作或某些网络操作,那么我们会冒这个异常的风险,并且应用程序不会响应。

如何修复它:

要避免此问题,您必须使用另一个线程进行后台操作或网络操作,例如使用asyncTask并使用某些库进行网络操作,如Volley,AsyncHttp等。

答案 38 :(得分:4)

在主线程上执行网络操作时抛出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();
}

答案 39 :(得分:3)

我们还可以使用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/

答案 40 :(得分:3)

我以一种简单的方式解决了这个问题...

我在oncreate StrictMode.enableDefaults();后添加并解决了这个问题。

或者

使用ServiceAsyncTask来解决此问题

注意:

Do not change SDK version
Do not use a separate thread

更多信息,check this

答案 41 :(得分:2)

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

使用以下方式执行网络操作

  • Asysnctask :适用于不需要花费太多时间的小型操作。
  • 意向服务:对于需要花费大量时间的网络操作。
  • 使用排球改造等自定义库进行处理 复杂的网络运营

永远不要使用StrictMode.setThreadPolicy(策略),因为它会冻结您的用户界面并不是一个好主意。

答案 42 :(得分:2)

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

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

答案 43 :(得分:2)

我有一个类似的问题,我只是在您的活动的oncreate方法中使用了以下内容。

//allow strict mode
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);

效果很好。

答案 44 :(得分:2)

使用AsycTask

在后台线程中执行此操作

Java

class NetworkThread extends AsyncTask<String, Void, String> {

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

    protected void onPostExecute(String result) {
        // TODO: do something with the feed
    }
}

在需要的地方致电

new NetworkThread().execute("Your URL here");

科特林

internal class MyNetworkTask : AsyncTask<String, Void, RSSFeed>() {

    override fun doInBackground(vararg urls: String): RSSFeed? {
        try {
             // download
             // prepare RSSFeeds
             return RSSFeeds
         } catch (e: Exception) {
            //handle exception
            return null
        }
    }

    override fun onPostExecute(feed: RSSFeed) {
        // TODO: check this.exception
        // TODO: do something with the feed
    }
}

致电科特林

MyNetworkTask().execute(url)

答案 45 :(得分:1)

我将返回值的网络访问函数转换为挂起函数,如下所示:

final = np.zeros(shape=(80, 10))
final[:,1:9] = np.random.randint(97, size=(80, 8))+1
final[:,9] = 99

然后修改我使用该函数的位置以适应此:


suspend fun isInternetReachable(): Boolean {
 ...
 ...
 return result

}

答案 46 :(得分:1)

Android 不允许在主线程上运行长时间运行的操作。 因此,只需使用不同的线程并在需要时将结果发布到主线程即可。

new Thread(new Runnable() {
        @Override
        public void run() {
            /*
            // run operation here
            */
            //after getting result
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    //post result to main thread
                }
            });
        }
    }).start();

答案 47 :(得分:1)

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

https://stackoverflow.com/questions/58767733/android-asynctask-api-deprecating-in-android-11-what-are-the-alternatives

专门为我工作的人是mayank1513对上述链接上找到的可运行线程的java 8实现的回答,代码如下

new Thread(() -> {
        // do background stuff here
        runOnUiThread(()->{
            // OnPostExecute stuff here
        });
    }).start();

不过,您可以先在代码的某些部分定义线程,然后再在类似的地方启动

线程定义

Thread thread = new Thread(() -> {
            // do background stuff here
            runOnUiThread(()->{
                // OnPostExecute stuff here
            });
        });

线程调用

thread.start();

希望这可以避免有人看到不推荐使用的AsyncTask的麻烦

答案 48 :(得分:1)

这些答案需要更新,以使用更现代的方式连接到Internet上的服务器并处理一般的异步任务,例如您可以找到在Google Drive API sample中使用任务的示例。在这种情况下,应使用相同的命令。我将使用OP的原始代码来演示这种方法。

首先,您需要定义一个非主线程执行程序,并且只需要执行一次:

        private val mExecutor: Executor = Executors.newSingleThreadExecutor()

然后在该执行器中处理您的逻辑,该执行器将在主线程之外运行

        Tasks.call (mExecutor, Callable<String> {

                val url = URL(urlToRssFeed)
                val factory = SAXParserFactory.newInstance()
                val parser = factory.newSAXParser()
                val xmlreader = parser.getXMLReader()
                val theRSSHandler = RssHandler()
                xmlreader.setContentHandler(theRSSHandler)
                val is = InputSource(url.openStream())
                xmlreader.parse(is)
                theRSSHandler.getFeed()
                // complete processing and return String or other object
                // e.g. you could return Boolean indicating a success or failure
                return@Callable someResult
        }).continueWith{
            // it.result here is what your asynchronous task has returned
            processResult(it.result)
        }

continueWith 子句将在异步任务完成后执行,并且您可以通过 it.result 访问该任务返回的值。 / p>

答案 49 :(得分:1)

理想情况下,AsyncTasks应该用于简短的操作(几秒钟 最多。)-developer-android

使用newCachedThreadPool是不错的选择。您还可以考虑其他选项,例如newSingleThreadExecutornewFixedThreadPool

    ExecutorService myExecutor = Executors.newCachedThreadPool();
    myExecutor.execute(new Runnable() {
        @Override
        public void run() {
            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);
        }
    });

ThreadPoolExecutor是一个帮助程序类,可简化此过程。这个 类管理一组线程的创建,设置它们的 优先级,并管理如何在这些线程之间分配工作。 随着工作量的增加或减少,班级旋转或破坏 更多线程来适应工作量。

有关Android线程的更多信息,请参见this

答案 50 :(得分:1)

如果您在kotlin和anko工作,则可以添加

 doAsync {
   method()
}

答案 51 :(得分:1)

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

答案 52 :(得分:1)

出现NetworkOnMainThread异常是因为您在默认线程(即UI线程)上调用了一些网络操作。 根据不允许的Android版本Android 3(Honeycomb),您应该在主线程之外调用网络操作。

您可以使用AsyncTask,IntentService或创建自己的线程并在run方法内部调用。 有关详情,请访问 Connecting to the Network

答案 53 :(得分:0)

您可以使用Kotlin-coroutines

 class YoutActivity : AppCompatActivity, CoroutineScope {

      override fun onCreate(...) {
         launch {  yourHeavyMethod() }
      }

      suspend fun yourHeavyMethod() {
         async{ yourNetworkCall() }.await()
         ...
         ...
      }

 } 
  

您可以遵循this指南。

答案 54 :(得分:0)

科特林版本

internal class RetrieveFeedTask : AsyncTask<String, Void, RSSFeed>() {

    override fun doInBackground(vararg urls: String): RSSFeed? {

        try {
             // download
             // prepare RSSFeeds
             return RSSFeeds

         } catch (e: Exception) {

            //handle exception
            return null
        }
    }

    override fun onPostExecute(feed: RSSFeed) {
        // TODO: check this.exception
        // TODO: do something with the feed
    }
}

通话示例

RetrieveFeedTask().execute(url)

答案 55 :(得分:0)

不同的选择:

  1. 使用普通的java runnable线程来处理网络任务,并可以使用runOnUIThread()来更新UI

  2. 如果您想在获得网络响应后更新用户界面,可以使用intentservice / async任务

答案 56 :(得分:0)

Android Jetpack引入了WorkManager,它解决了Oreo中后台服务限制以及Lolipop下方的Alarm Manager和Lolipop上方的JobScheduler的使用的问题。

请使用WorkManager在后台线程上运行任务,即使用户关闭了应用程序,该任务仍将继续运行。

答案 57 :(得分:0)

自2018年起,我建议在Kotlin中使用RxJava进行网络提取。下面是一个简单的例子。

Single.fromCallable {
        // Your Network Fetching Code
        Network.fetchHttp(url) 
    }
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe {
        // What you need to do with your result on the view 
        result -> view.updateScreen(result) 
    }

答案 58 :(得分:0)

这是一个使用 OkHttpFutureExecutorServiceCallable 的简单解决方案:

final OkHttpClient httpClient = new OkHttpClient();
final ExecutorService executor = newFixedThreadPool(3);

final Request request = new Request.Builder().url("http://example.com").build();

Response response = executor.submit(new Callable<Response>() {
   public Response call() throws IOException {
      return httpClient.newCall(request).execute();
   }
}).get();

答案 59 :(得分:0)

永远不要在UI线程上进行任何长时间的工作,长时间运行的工作可以是与服务器的通信,读/写文件等。这些任务应该在后台线程上,这就是为什么Service,{{1} },AsyncTask已创建。您可以禁用Threads,以防止崩溃但从未建议过。

我建议你在调试模式下至少利用StrictMode。使用下面的代码来获取在主线程上减慢App的任何问题的日志。

StrictMode

您可以设置不同的处罚 -

StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
            .detectAll()
            .penaltyLog()
            .build());

关于https://developer.android.com/reference/android/os/StrictMode.html

的内容非常多

答案 60 :(得分:-4)

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

// 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();
        }
    }
}

答案 61 :(得分:-5)

在清单标记

之后,您必须在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);
}

答案 62 :(得分:-5)

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);