반응형

'Android.OS.NetworkOnMaintHreadException'을 어떻게 수정할 수 있습니까?


질문

 

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

이 문제를 어떻게 수정할 수 있습니까?


답변

 

참고 : API 레벨 30에서 ASYNCTASK을 사용하지 못했습니다. Asynctask |안드로이드 개발자들

이 예외는 응용 프로그램이 기본 스레드에서 네트워킹 작업을 수행하려고 시도 할 때 Throw됩니다.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"/>


답변

거의 항상 스레드 또는 비동기 작업으로 네트워크 작업을 실행해야합니다.

그러나이 제한을 제거 할 수 있으며 결과를 기꺼이 받아들이면 기본 동작을 무시할 수 있습니다.

추가하다:

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

StrictMode.setThreadPolicy(policy);

수업에서,

그리고

Android Manifest.xml 파일 에이 권한을 추가하십시오.

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

결과:

앱이 (반점이있는 인터넷 연결 영역에서) 응답하지 않고 잠그고 사용자가 느리게 인식하고 강제로 킬을 수행해야하며 앱을 죽이고 앱이 중지되었음을 사용자에게 알리고있는 활동 관리자에게 위험에 처하게됩니다.

Android는 응답 성을위한 디자인에 좋은 프로그래밍 관행에 대한 좋은 팁을 가지고 있습니다. NetworkOnMaintHreadException |안드로이드 개발자들



답변

나는 새로운 스레드를 사용 하여이 문제를 해결했습니다.

Thread thread = new Thread(new Runnable() {

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

thread.start(); 


답변

받아 들여지는 답변은 약간의 유동가가 있습니다.당신이 무엇을하고 있는지 정말로 알지 못하면 네트워킹을 위해 asynctask를 사용하는 것이 좋습니다.아래쪽 부분은 다음과 같습니다.

비 정적 인 내부 클래스로 작성된 Asynctask는 묶음 활동 개체, 컨텍스트 및 해당 활동에 의해 생성 된 전체보기 계층 구조에 대한 암시 적 참조가 있습니다. 이 참조는 Asynctask의 배경 작업이 완료 될 때까지 활동이 가비지가 수집되지 않도록합니다. 사용자의 연결이 느리고 / 또는 다운로드가 크면이 단기 메모리 누수가 문제가 될 수 있습니다. 예를 들어 방향이 여러 번 변경되면 (그리고 실행 작업을 취소하지 않음) 사용자 또는 사용자 활동에서 멀리 탐색하십시오. Asynctask는 실행되는 플랫폼에 따라 실행되는 다양한 실행 특성을 가지고 있습니다. API 레벨 4 ASYNCTASKS가 단일 배경 스레드에서 직렬 실행하기. API 레벨 4에서 API 레벨 10을 통해 ASYNCTASKS는 최대 128 개의 스레드의 풀에서 실행됩니다. API 레벨 11 Onwords Asynctask는 단일 백그라운드 스레드에서 직렬로 실행됩니다 (오버로드 된 ExecuteOnexutor 메서드를 사용하고 대체 실행 프로그램을 제공하지 않는 한). ICS에서 연속적으로 실행할 때 잘 작동하는 코드는 진저 브레드에서 동시에 실행될 때 실행될 때 부주의 한 순서 종속성이있는 경우 SAY를 즉시 실행할 수 있습니다.

단기 메모리 누수를 피하고 싶다면 모든 플랫폼에서 잘 정의 된 실행 특성을 잘 정의하고 정말로 강력한 네트워크 처리를 빌드 할 수있는 기본 사항을 고려할 수 있습니다.

  1. Using a library that does a nice job of this for you - there's a nice comparison of networking libs in this question, or
  2. Using a Service or IntentService instead, perhaps with a PendingIntent to return the result via the Activity's onActivityResult method.

IntentService 접근법

단점 :

Asynctask보다 더 많은 코드와 복잡성이 있지만, 당신이 생각하는만큼 많이 아닙니다. 대기열 요청을하고 단일 배경 스레드에서이를 실행합니다.INTESTARVICE를 동등한 서비스 구현으로 대체하여이를 쉽게 제어 할 수 있습니다. 음, 나는 다른 사람들을 생각할 수 없다.

Upsides :

단기 메모리 누수 문제를 피한다 네트워크 작업이 기동되는 동안 활동이 다시 시작되면 OnactivityResult 메서드를 통해 다운로드의 결과를 계속받을 수 있습니다. asynctask보다 더 나은 플랫폼은 강력한 네트워킹 코드를 구축하고 재사용합니다.예 : 중요한 업로드를 수행 해야하는 경우 활동에서 Asynctask에서 수행 할 수 있지만 사용자 컨텍스트가 앱에서 전화를 걸려면 업로드가 완료되기 전에 시스템이 앱을 죽일 수 있습니다.활성 서비스로 응용 프로그램을 죽일 가능성이 적습니다. 위의 intentservice의 자신의 동시 버전을 사용하는 경우 (위에 연결된 것과 같이) 실행 프로그램을 통해 동시성 수준을 제어 할 수 있습니다.

구현 요약

단일 배경 스레드에서 다운로드를 쉽게 수행하려면 IntentService를 구현할 수 있습니다.

1 단계 : 다운로드를 수행하려면 IntEnterVICE를 만듭니다.인재 엑스트라를 통해 다운로드 할 것을 알려주고 결과를 반환하는 데 사용하기 위해 사용하기 위해 사용하는 것이 좋습니다.

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 reuse, 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 단계 : 서비스에서 서비스를 호출하여 서비스가 결과를 반환하는 데 사용할 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 프로젝트는 여기에서 사용할 수 있습니다.



답변

Honeycomb의 UI 스레드에서 네트워크 I / O를 수행 할 수 없습니다.기술적으로 이전 버전의 Android 버전에서는 가능하지만 앱이 응답을 중지시키는 것에 따라 실제로 나쁜 생각이므로 OS가 나쁘게 작동하는 것을 위해 앱을 죽이는 결과를 초래할 수 있습니다.백그라운드 프로세스를 실행하거나 Asynctask를 사용하여 배경 스레드에서 네트워크 트랜잭션을 수행해야합니다.

Android 개발자 사이트에 대한 고통없는 스레딩에 대한 기사가 있습니다. 이는이 모든 것을 소개하는 좋은 소개이며 현실적으로 여기에서 제공 될 수있는 것보다 훨씬 더 나은 깊이를 제공 할 것입니다.



답변

이 문제의 두 가지 솔루션이 있습니다.

  1. Don't use a network call in the main UI thread. Use an async task for that.

  2. Write the below code into your MainActivity file after setContentView(R.layout.activity_main);:

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

아래의 import 문을 Java 파일로 표시합니다.

import android.os.StrictMode;
출처:https://stackoverflow.com/questions/6343166/how-can-i-fix-android-os-networkonmainthreadexception
반응형