java - 해결 - unable to create service android os networkonmainthreadexception




android.os.NetworkOnMainThreadException을 어떻게 수정합니까? (20)

  1. strictMode를 사용하지 마십시오 (디버그 모드에서만).
  2. SDK 버전을 변경하지 마십시오.
  3. 별도의 스레드를 사용하지 마십시오.

서비스 또는 AsyncTask 사용

참고 항목 Stack Overflow question :

android.os.NetworkOnMainThreadException Android에서 이메일 보내기

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

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


간단히 말해서,

UI 스레드에서 네트워크 작업 금지

예를 들어, HTTP 요청을하는 경우 네트워크 작업입니다.

해결책:

  1. 새 스레드를 만들어야합니다.
  2. 또는 AsyncTask 클래스를 사용하십시오.

방법:

모든 일을 안에 담아 라.

  1. 새 스레드의 run() 메소드
  2. 또는 AsyncTask 클래스의 doInBackground() 메소드.

그러나:

네트워크 응답에서 무언가를 얻었을 때 (TextView의 응답 표시 메시지와 같이)보기에 표시 하려면 UI 스레드로 돌아 가야합니다 .

그렇게하지 않으면 ViewRootImpl$CalledFromWrongThreadException 합니다.

어떻게?

  1. AsyncTask를 사용하는 동안 onPostExecute() 메서드에서 뷰를 업데이트하십시오.
  2. 또는 runOnUiThread() 메서드를 호출하고 run() 메서드 내에서 뷰를 업데이트합니다.

내부에 코드 삽입 :

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

네트워크 기반 작업은 주 스레드에서 실행할 수 없습니다. 자식 스레드에서 모든 네트워크 기반 작업을 실행하거나 AsyncTask를 구현해야합니다.

이것은 자식 스레드에서 작업을 실행하는 방법입니다.

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

다른 스레드에서 네트워크 작업 수행

예 :

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

AndroidManifest.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);
}

AsyncTask 인터페이스를 사용하십시오.

두 가지 방법에 대한 전체 코드


받아 들여진 응답에는 몇몇 뜻 깊은 아래쪽이있다. 자신이하는 일을 정말로 알지 못한다면 네트워킹에 AsyncTask를 사용하는 것은 바람직하지 않습니다. 다운면의 일부는 다음과 같습니다.

  • 비 정적 인 내부 클래스로서 생성 된 AsyncTask는 그 액티비티 객체, 그 컨텍스트, 그리고 그 액티비티에 의해 생성 된 전체 View 계층에 대한 암시적인 참조를 갖는다. 이 참조는 AsyncTask의 백그라운드 작업이 완료 될 때까지 Activity가 가비지 수집되지 않도록합니다. 사용자 연결이 느리고 다운로드가 큰 경우 이러한 단기 메모리 누수가 문제가 될 수 있습니다. 예를 들어 방향이 여러 번 변경되고 (실행중인 작업을 취소하지 않은 경우) 사용자가 탐색하는 경우 활동에서 멀리 떨어진다.
  • AsyncTask는 실행되는 플랫폼에 따라 다른 실행 특성을가집니다. API 레벨 4 이전에는 AsyncTask가 단일 백그라운드 스레드에서 연속적으로 실행됩니다. API 레벨 4에서 API 레벨 10까지, AsyncTasks는 최대 128 개의 스레드 풀에서 실행됩니다. API 레벨 11부터 AsyncTask는 하나의 백그라운드 스레드에서 순차적으로 실행됩니다 (오버로드 된 executeOnExecutor 메소드를 사용하고 대체 실행 프로그램을 제공하지 않는 한). ICS에서 순차적으로 실행될 때 잘 동작하는 코드는 예기치 않은 실행 순서 종속성이있는 경우 Gingerbread에서 동시에 실행될 때 중단 될 수 있습니다.

단기 메모리 누수를 피하고 모든 플랫폼에서 잘 정의 된 실행 특성을 갖고 정말로 강력한 네트워크 처리를 구축 할 기반이 있다면 다음을 고려할 수 있습니다.

  1. 이 작업을 잘 수행하는 라이브러리를 사용하면 이 질문 에 네트워킹 라이브러리를 잘 비교할 수 있습니다.
  2. Service 또는 IntentService 대신 사용하며, PendingIntent 를 사용하여 Activity의 onActivityResult 메소드를 통해 결과를 반환 할 수 있습니다.

IntentService 접근 방식

아래쪽 :

  • AsyncTask 보다 더 많은 코드와 복잡성, 생각만큼 많이는 아니지만
  • 요청을 큐에 넣고 단일 백그라운드 스레드에서 실행합니다. IntentService 를 동등한 Service 구현으로 대체하여 쉽게 제어 할 수 있습니다.
  • 음, 지금 당장 다른 사람들을 생각할 수는 없어.

상향식 :

  • 단기 메모리 누수 문제를 피하십시오.
  • 네트워크 작업이 진행중인 동안 활동이 다시 시작되면 onActivityResult 메소드를 통해 다운로드 한 결과를받을 수 있습니다
  • 강력한 네트워킹 코드를 빌드하고 재사용하기위한 AsyncTask보다 향상된 플랫폼. 예 : 중요한 업로드를해야하는 경우 Activity AsyncTask 에서 수행 할 수 있지만 사용자 컨텍스트가 전화 통화를 위해 앱에서 전환되면 업로드가 완료되기 전에 앱이 종료 될 수 있습니다 . 활성 Service 응용 프로그램을 종료 할 가능성적습니다 .
  • 위에 링크 된 IntentService 의 동시 버전을 사용하는 경우 Executor 를 통해 동시성 수준을 제어 할 수 있습니다.

구현 요약

IntentService 를 구현하여 단일 백그라운드 스레드에서 다운로드를 매우 쉽게 수행 할 수 있습니다.

1 단계 : IntentService 를 만들어 다운로드를 수행합니다. Intent 추가 기능을 통해 다운로드 할 내용을 알 수 있고 결과를 Activity 로 반환하는 데 사용할 PendingIntent 를 전달할 수 있습니다.

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 단계 : 서비스가 결과를 반환하는 데 사용할 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 .


Thread 사용하여이 문제를 해결했습니다.

Thread thread = new Thread(new Runnable() {

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

thread.start(); 

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

이 오류는 주 스레드에서 장기 실행 작업을 실행하기 때문에 발생합니다. AsynTask 또는 Thread 를 사용하여 문제를 쉽게 해결할 수 있습니다. 더 나은 처리를 위해이 라이브러리 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
    }
});

이것은 Android 3.0 이상에서 발생합니다. 안드로이드 3.0 이상에서는 네트워크 작업 (인터넷에 액세스하는 기능)을 사용하여 기본 스레드 / UI 스레드 (활동의 작성 및 재개 메소드에서 생성되는 것)에서 실행되지 않도록 제한했습니다.

이것은 네트워크 작업을 위해 별도의 스레드를 사용하도록 장려하는 것입니다. 네트워크 활동을 올바른 방법으로 수행하는 방법에 대한 자세한 내용은 AsyncTask 를 참조하십시오.



spektom 의 최고 대답은 완벽하게 작동합니다.

AsyncTask 인라인으로 작성하고 클래스로 확장하지 않는 경우, AsyncTask 에서 응답을 얻을 필요가있는 경우 아래와 같이 get() 메소드를 사용할 수 있습니다.

RSSFeed feed = new RetreiveFeedTask().execute(urlToRssFeed).get();

(그의 예에서.)


Android 특수 효과 사용은 옵션입니다. 백그라운드 스레드에서 모든 메소드를 간단하게 실행할 수 있습니다.

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

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

단순성과 가독성의 이점을 제공하기는하지만 단점이 있습니다.


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. specifiying함으로써 (Schedulers.io()), RxAndroid가 실행됩니다 getFavoriteMusicShows()다른 스레드에서.

  2. 사용하여 AndroidSchedulers.mainThread()우리는 UI 스레드에서이 관찰 가능한 관찰 할, 즉, 우리는 우리의 원하는 onNext()콜백은 UI 스레드에서 호출 할


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

그러나이 제한을 없애고 결과를 기꺼이 받아들이는 경우 기본 동작을 무시할 수 있습니다.

더하다:

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

StrictMode.setThreadPolicy(policy); 

수업 시간에,

android manifest.xml 파일에이 권한을 추가하십시오.

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

결과 :

앱이 (불안정한 인터넷 연결 영역에서) 반응이 없어져 잠기면 사용자는 느려지고 강제 종료해야하며 액티비티 관리자가 앱을 종료하고 앱이 중지되었다고 사용자에게 알릴 위험이 있습니다.

안드로이드는 응답 성을 위해 좋은 프로그래밍 기법에 대한 좋은 팁을 가지고있다 : http://developer.android.com/reference/android/os/NetworkOnMainThreadException.html


Android의 UI 스레드에서 네트워크 작업을 구현할 수 없습니다. AsyncTask 클래스를 사용하여 API 요청 보내기, URL에서 이미지 다운로드, AsyncTask의 콜백 메소드 사용과 같은 네트워크 관련 작업을 수행해야합니다. 그러면 onPostExecute menthod의 결과를 얻을 수 있으며 UI 스레드에있게됩니다. UI에 웹 서비스 또는 그와 유사한 데이터를 채울 수 있습니다.

예 : URL ( https://www.samplewebsite.com/sampleimage.jpg 에서 이미지를 다운로드한다고 가정 해보십시오.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 매니페스트 파일에 인터넷 권한을 추가하는 것을 잊지 마십시오. 그것은 매력처럼 작동합니다. :)


New ThreadAsynTask 솔루션은 이미 설명되었습니다.

AsyncTask짧은 작업에 이상적으로 사용되어야합니다. ThreadAndroid의 경우 보통 은 바람직하지 않습니다.

HandlerThreadHandler 사용하여 대체 솔루션을 살펴보십시오.Handler

HandlerThread

루퍼가있는 새 스레드를 시작하기위한 편리한 클래스입니다. 그러면 루퍼를 사용하여 핸들러 클래스를 만들 수 있습니다. start()아직 호출해야 한다는 점에 유의하십시오 .

매니저:

Handler를 사용하면 스레드의 MessageQueue와 관련된 Message 및 Runnable 객체를 보내고 처리 할 수 ​​있습니다. 각 Handler 인스턴스는 단일 스레드 및 해당 스레드의 메시지 큐와 연관됩니다. 새로운 Handler를 만들면, 그 핸들러를 생성하고있는 스레드의 스레드 / 메시지 큐에 바인딩됩니다. 그 시점부터 메시지와 실행 파일을 해당 메시지 큐에 전달하고 메시지에서 나오는대로 실행합니다 열.

해결책:

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

이 접근법을 사용하는 장점 :

  1. Thread/AsyncTask각 네트워크 작업에 대해 새로 만들기 는 비용이 많이 듭니다. 은 Thread/AsyncTask파괴와 다음 네트워크 작업에 다시 생성됩니다. 그러나 사용 HandlerHandlerThread접근 방식 HandlerThread을 사용하여 여러 네트워크 작업 (Runnable 작업)을 단일 작업으로 제출할 수 있습니다 Handler.

기본 (UI) 스레드에서 네트워크 리소스에 액세스하면이 예외가 발생합니다. 이 문제를 피하기 위해 별도의 스레드 또는 AsyncTask를 사용하여 네트워크 리소스에 액세스하십시오.


위의 솔루션 풀이 있지만 아무도 언급하지 않았습니다 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
    }
});




thread-exceptions