'안드로이드'를 어떻게 고치죠?Network On Main Thread Exception'?
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 장 api에 。
| | Android Developers
이 예외는 응용 프로그램이 메인 스레드에서 네트워킹 작업을 수행하려고 할 때 발생합니다.에서 코드를 실행합니다.
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에는 응답성을 고려하여 설계하기 위한 좋은 프로그래밍 방법에 대한 몇 가지 유용한 팁이 있습니다.Network On Main Thread Exception | 안드로이드 개발자
는 이 를 새로운 해서 풀었습니다.Thread
.
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
try {
//Your code goes here
} catch (Exception e) {
e.printStackTrace();
}
}
});
thread.start();
받아들여진 답변에는 몇 가지 중대한 단점이 있다.실제로 무엇을 하고 있는지 모르는 한 네트워킹에 비동기 태스크를 사용하는 것은 권장되지 않습니다.다음과 같은 단점이 있습니다.
- 비정적 내부 클래스로 작성된 AsyncTask에는 포함된 Activity 개체, 해당 컨텍스트 및 해당 액티비티에 의해 생성된 View 계층 전체에 대한 암묵적인 참조가 있습니다.이 참조는 비동기 태스크의 백그라운드 작업이 완료될 때까지 활동이 가비지 수집되는 것을 방지합니다.사용자의 접속이 느리거나 다운로드가 많은 경우, 예를 들어 방향이 여러 번 바뀌거나(실행 작업을 취소하지 않거나) 사용자가 액티비티에서 벗어나는 경우 등) 이러한 단기 메모리 누수가 문제가 될 수 있습니다.
- 비동기 태스크API 레벨4 이전의 AsyncTasks는 단일 백그라운드스레드 상에서 시리얼로 실행됩니다.API "4" API "10" "AsyncTasks" "128" "AsyncTasks" "128" "AsyncTasks" "AsyncTasks" "unl" "Overloaded ess "를 "
executeOnExecutor
방법을 지정하고 대체 실행자를 지정합니다.ICS 상에서 시리얼로 동작하고 있는 코드는, Gingerbread 상에서 동시에 실행했을 때에 파손되는 경우가 있습니다.예를 들어, 부주의로 실행순서의 의존관계가 있는 경우 등입니다.
단기 메모리 누수를 방지하고 모든 플랫폼에서 실행 특성을 명확하게 정의하며 매우 견고한 네트워크 처리를 구축하기 위한 기반이 있는 경우 다음 사항을 고려할 수 있습니다.
- 이 작업을 훌륭하게 수행할 수 있는 라이브러리를 사용하는 경우 - 이 질문에는 네트워킹 libs의 훌륭한 비교가 포함되어 있습니다.
- 「」의
Service
★★★★★★★★★★★★★★★★★」IntentService
""를 하여""를 사용합니다.PendingIntent
onActivityResult
★★★★★★ 。
Intent Service 접근법
단점:
- 이 다 more more more more more more more more more more more more more more more more more
AsyncTask
- 요청을 큐잉하고 단일 백그라운드 스레드에서 실행합니다.이를 쉽게 제어할 수 있습니다.
IntentService
Service
아마 이것과 같은 구현입니다. - 음, 사실 지금은 다른 생각이 안 나네요
업사이드:
- 단기 메모리 누수 문제를 방지합니다.
- 가 재개된 경우에도 결과를 할 수 .
onActivityResult
- 견고한 네트워킹 코드를 구축하여 재사용하는 데 AsyncTask보다 뛰어난 플랫폼입니다.업로드를 할 에는 :에서 할 수 .
AsyncTask
anActivity
그러나 사용자가 전화를 받기 위해 앱에서 컨텍스트를 전환하면 업로드가 완료되기 전에 시스템이 앱을 종료할 수 있습니다.액티브한 어플리케이션을 종료할 가능성이 낮다.Service
. - 인
IntentService
) 동시성 할 수Executor
.
구현 개요
해서 '실행할 수 요.IntentService
단일 백그라운드 스레드에서 다운로드를 쉽게 수행할 수 있습니다.
1: 「」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 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 개발자 사이트에는 Painless Threading에 대한 기사가 게재되어 있습니다.이것은 좋은 소개입니다.또, 이 사이트에서 리얼하게 제공되는 것보다 훨씬 상세한 답변을 얻을 수 있습니다.
이 문제에는 두 가지 해결책이 있습니다.
기본 UI 스레드에서 네트워크 호출을 사용하지 마십시오.여기에는 비동기 작업을 사용합니다.
setContentView(R.layout.activity_main) 뒤에 다음 코드를 MainActivity 파일에 씁니다.
if (162 . os )Build.VERSION.SDK_INT > 9) {StrictMode}ThreadPolicy policy = new StrictMode.스레드 정책Builder().permitAll().build(); StrictMode.setThreadPolicy(정책), }
그리고 아래의 Import 스테이트먼트를 당신의 Java 파일로 보냅니다.
import android.os.StrictMode;
다른 스레드에서 네트워크 작업을 수행합니다.
예를 들어 다음과 같습니다.
new Thread(new Runnable(){
@Override
public void run() {
// Do network action in this function
}
}).start();
AndroidManifest.xml 파일에 추가합니다.
<uses-permission android:name="android.permission.INTERNET"/>
- strict Mode 사용 안 함(디버깅모드만)
- SDK 버전 변경 안 함
- 개별 스레드 사용 안 함
서비스 또는 비동기 태스크 사용
Stack Overflow 질문을 참조하십시오.
Android.os.Android에서 이메일을 보내는 NetworkOnMainThreadException
strict 모드를 디세블로 하려면 , 다음의 코드를 사용합니다.
if (android.os.Build.VERSION.SDK_INT > 9) {
StrictMode.ThreadPolicy policy =
new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
}
이는 권장하지 않습니다.AsyncTask
인터페이스입니다.
주 스레드에서는 네트워크 기반 작업을 실행할 수 없습니다.하위 스레드에서 모든 네트워크 기반 작업을 실행하거나 Async Task를 구현해야 합니다.
하위 스레드에서 태스크를 실행하는 방법은 다음과 같습니다.
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() {
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
}
}
이것은 Android 3.0 이상에서 발생합니다.Android 3.0 이상부터는 네트워크 조작(인터넷에 접속하는 기능)을 메인 스레드에서 실행하는 것을 제한하고 있습니다.UI 스레드(액티비티의 작성 시 및 재개 시 메서드에서 생성되는 것).
이것은, 네트워크 조작에 개별의 스레드를 사용하는 것을 장려하기 위해서입니다.네트워크 액티비티를 올바르게 실행하는 방법의 상세한 것에 대하여는, 「비동기 태스크」를 참조해 주세요.
Android Annotations를 사용할 수도 있습니다.백그라운드 스레드에서 모든 메서드를 실행할 수 있습니다.
// normal method
private void normal() {
doSomething(); // do something in background
}
@Background
protected void doSomething()
// run your networking code here
}
단, 단순성과 가독성의 이점을 제공하지만 단점도 있습니다.
이 오류는 메인 스레드에서 장시간 실행 중인 작업을 실행했기 때문에 발생합니다.AsynTask 또는 Thread를 사용하면 문제를 쉽게 해결할 수 있습니다.이 라이브러리는 비동기식으로 체크아웃할 수 있습니다.HTTP Client를 통한 처리 개선.
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
}
});
네트워크 작업, 파일 I/O 또는 SQLite 데이터베이스 작업과 같이 주 스레드(UI 스레드)에 대해 시간이 많이 걸리는 작업을 수행하지 마십시오.따라서 이러한 작업을 수행하려면 작업자 스레드를 생성해야 하지만 문제는 작업자 스레드에서 UI 관련 작업을 직접 수행할 수 없다는 것입니다.'어울리지 않다', '어울리지 않다'를 사용해야 합니다.Handler
을 하다Message
것을 단순화하기 위해 합니다. 를 들어, 안드로이드는 안드로이드와 같은 다양한 방법을 제공합니다.AsyncTask
,AsyncTaskLoader
,CursorLoader
★★★★★★★★★★★★★★★★★」IntentService
따라서 필요에 따라 이 중 하나를 사용할 수 있습니다.
Spektom의 상위 답변은 완벽합니다.
「 」를 있는 는,AsyncTask
되지 않는 , 「되지 않는 것」이라고 하는 것 외에, 「클래스로서 확장되지 않는 것」이라고 하는 응답이 는, 「클래스로서 확장되지 않는 것.게다가, 그 때문에, 응답의 취득이 필요한 경우는,AsyncTask
, 을할 수 있습니다.get()
을 사용하다
RSSFeed feed = new RetreiveFeedTask().execute(urlToRssFeed).get();
(그의 예에서).
이는 Honeycomb SDK 이상을 대상으로 하는 애플리케이션에만 적용됩니다.이전 SDK 버전을 대상으로 하는 애플리케이션은 메인 이벤트 루프 스레드에서 네트워킹을 수행할 수 있습니다.
저는 이렇게 생각했어요.
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="10" />
앱을 테스트하고 있던 디바이스는 SDK Version 16인 4.1.2였습니다.
대상 버전이 Android 대상 라이브러리와 동일한지 확인하십시오.타겟 라이브러리가 불분명한 경우 [프로젝트]-> [빌드 패스]-> [안드로이드]를 우클릭하면 해당 라이브러리가 선택됩니다.
또한 다른 사용자가 언급했듯이 인터넷에 액세스하기 위한 올바른 권한을 포함합니다.
<uses-permission android:name="android.permission.INTERNET"/>
액티비티에서 사용
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();
}
});
간단히 설명하자면 다음과 같습니다.
메인 스레드는 기본적으로 UI 스레드입니다.
따라서 메인 스레드에서 네트워킹 작업을 수행할 수 없다는 것은 UI 스레드에서 네트워킹 작업을 수행할 수 없다는 것을 의미합니다. 즉, 다른 스레드 내의 블록에서도 네트워킹 작업을 수행할 수 없다는 것을 의미합니다.
(왜 메인 스레드 이외의 장소에서 에러가 발생하고 있는지를 알아내려고 머리를 긁는 시간이 길었습니다.이것이 그 이유입니다.이 스레드는 도움이 되었습니다.그리고 이 코멘트가 다른 사람에게 도움이 되기를 바랍니다.)
이 예외는 메인 스레드에서 수행되는 작업이 너무 많은 시간이 걸리는 경우 해당 태스크로 인해 발생합니다.
이를 피하기 위해 스레드 또는 실행자를 사용하여 처리할 수 있습니다.
Executors.newSingleThreadExecutor().submit(new Runnable() {
@Override
public void run() {
// You can perform your task here.
}
});
이 질문에는 이미 많은 훌륭한 답변들이 있지만, 그 답변들이 게시된 이후 많은 훌륭한 도서관들이 나오고 있다.이것은 일종의 신참 안내서입니다.
네트워크 조작을 실행하기 위한 몇 가지 사용 사례와 각각 한두 가지 솔루션에 대해 설명하겠습니다.
REST over HTTP
일반적으로 JSON이지만 XML 또는 다른 것일 수 있습니다.
풀 API 액세스
사용자가 주가, 금리, 환율 등을 추적할 수 있는 앱을 만들고 있다고 가정해 보겠습니다.다음과 같은 JSON API가 있습니다.
http://api.example.com/stocks // ResponseWrapper<String> object containing a
// list of strings 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)
사각형으로부터의 개조
이는 여러 엔드포인트가 있는 API에 매우 적합한 선택이며 Amazon Ion Java 또는 Balley(웹 사이트:개조).
finance API에서는 어떻게 사용합니까?
파일 build.gradle
모듈 레벨의 build.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
Finances Api.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);
}
클래스 파이낸스 ApiBuilder
public class FinancesApiBuilder {
public static FinancesApi build(String baseUrl){
return new Retrofit.Builder()
.baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(FinancesApi.class);
}
}
클래스 파이낸스 플래그먼트스니펫
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은 이를 쉽게 만듭니다(자세한 내용은 Retrofit의 Add Header Parameter에 대한 이 멋진 답변을 참조하십시오).
일회성 REST API 액세스
사용자의 GPS 위치를 검색하여 해당 지역의 현재 온도를 확인하고 분위기를 알려주는 "기상 좋은 날씨" 앱을 만들고 있다고 가정해 봅시다.이러한 유형의 앱은 API 엔드포인트를 선언할 필요가 없으며 하나의 API 엔드포인트에 액세스할 수 있어야 합니다.
이온
이 라이브러리는 이런 종류의 접근을 위한 훌륭한 라이브러리입니다.
안드로이드를 수정하는 방법에 대한 msysmilu의 훌륭한 답변을 읽어주세요.Network On Main Thread Exception'?
HTTP를 통한 이미지 로드
발리
REST API에서도 Balley를 사용할 수 있지만 설정이 복잡하기 때문에 위와 같이 Retrofit from Square를 선호합니다.
소셜 네트워킹 앱을 만들고 있는데 친구 프로필 사진을 로드하려고 합니다.
파일 build.gradle
모듈 레벨의 build.gradle 파일에 다음 행을 추가합니다.
implementation 'com.android.volley:volley:1.0.0'
파일 이미지Fetch.java
발리에는 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());
피카소
피카소는 광장에서 온 또 다른 훌륭한 도서관이다.몇 가지 좋은 예에 대해서는 웹사이트를 참조해 주세요.
한마디로 말해서
UI 스레드에서 네트워크 작업 안 함
예를 들어 HTTP 요청을 수행하는 경우 이는 네트워크액션입니다
솔루션:
- 새 스레드를 작성해야 합니다.
- 또는 AsyncTask 클래스를 사용합니다.
방법:
모든 작품을 안에 담다
run()
- 또는,
doInBackground()
AsyncTask " " " 입니다.
단,
네트워크 응답에서 얻은 정보를 뷰에 표시하려면(TextView에서 응답 메시지 표시 등) UI 스레드로 돌아가야 합니다.
하면 지, 않, 신, 신, 신, 신, if, if, if, if, if, if, if, if, if ifViewRootImpl$CalledFromWrongThreadException
.
사용법
- 중 AsyncTask에서 를 합니다.
onPostExecute()
- 또는 메서드를 호출하여 내부 보기를 업데이트하십시오.
run()
★★★★★★ 。
하여 코드 할 수 있습니다.main thread
ANR, NetworkOnMainThreadException, IlgulateStateException(예를 들어 장시간 UI를 잠글 수 있기 때문에 메인 스레드상의 데이터베이스에 액세스할 수 없습니다.
상황에 따라 몇 가지 방법을 선택해야 합니다.
Java 스레드는 일회성으로 실행 메서드를 실행한 후 다이됩니다.
Handler Thread는 looper가 있는 새 스레드를 시작하기 위한 편리한 클래스입니다.
비동기 태스크(API 레벨 30에서는 권장되지 않음)
AsyncTask는 스레드 및 핸들러에 관한 도우미 클래스가 되도록 설계되었으며 범용 스레드 프레임워크는 구성되지 않습니다.비동기 태스크는 짧은 작업(최대 몇 초)에 사용하는 것이 이상적입니다.스레드를 장시간 실행해야 하는 경우 실행자, 스레드풀 Executor, FutureTask 등 java.util.concurrent 패키지에서 제공되는 다양한 API를 사용하는 것이 좋습니다.
메인 스레드가 UI 컴포넌트를 독점하고 있기 때문에 일부 View에 액세스할 수 없기 때문에 Handler가 구하러 오는 것입니다.
스레드 풀을 세밀하게 제어하는 Executor Service를 구현하는 ThreadPoolExecutor 클래스(코어 풀 크기, 최대 풀 크기, 킵 얼라이브 시간 등)
스케줄 완료ThreadPoolExecutor - ThreadPoolExecutor를 확장하는 클래스입니다.일정 지연 후 또는 주기적으로 작업을 스케줄링할 수 있습니다.
FutureTask는 비동기 처리를 수행하지만 결과가 아직 준비되지 않았거나 처리가 완료되지 않은 경우 get()을 호출하면 스레드가 차단됩니다.
AsyncTaskLoader는 AsyncTask에 고유한 많은 문제를 해결합니다.
이것은 Android에서 장시간 실행되는 처리를 위한 사실상의 선택이며, 큰 파일을 업로드 또는 다운로드하는 것이 좋은 예입니다.사용자가 앱을 종료해도 업로드 및 다운로드가 계속될 수 있으며, 이러한 작업이 진행되는 동안 사용자가 앱을 사용할 수 없도록 차단하고 싶지 않습니다.
실제로 JobInfo를 사용하여 서비스를 생성하고 작업을 생성해야 합니다.서비스를 실행할 시기에 대한 기준을 지정하는 작성기.
관찰 가능한 시퀀스를 사용하여 비동기 및 이벤트 기반 프로그램을 구성하기 위한 라이브러리입니다.
코루틴(코틀린)
이것의 주요 요점은 비동기 코드를 동기 코드와 매우 비슷하게 만든다는 것이다.
여기서, 여기서, 여기서, 여기서, 여기서 더 읽어보세요.
★★★Thread
및 AsyncTask 솔루션에 대해서는 이미 설명했습니다.
AsyncTask
단시간 운용에 사용하는 것이 이상적입니다.인 ★★★★Thread
안드로이드
핸들러 스레드
루퍼가 있는 새 스레드를 시작하기 위한 편리한 클래스입니다.그런 다음 looper를 사용하여 핸들러 클래스를 만들 수 있습니다.:
start()
여전히 호출해야 합니다..계속 호출해야 합니다.
핸들러:
핸들러를 사용하면 스레드의 MessageQueue와 연관된 Message 및 Runnable 개체를 보내고 처리할 수 있습니다.각 처리기 인스턴스는 단일 스레드 및 해당 스레드의 메시지 대기열과 연결됩니다.새 핸들러를 작성하면 핸들러는 작성 중인 쓰레드의 스레드/메시지 큐에 바인드됩니다.이 시점부터 메시지 큐에 메시지와 실행 가능이 배달되고 메시지 큐에서 나올 때 실행됩니다.
솔루션:
만들다 만들기
HandlerThread
콜 불러
start()
에에HandlerThread
만들다 만들기
Handler
얻어냄으로써를 얻음으로써Looper
부터에서HanlerThread
Embed 당신의 네트워크 작업 관련 코드네트워크 조작에 다음 위치에 포함 코드를 관련.
Runnable
object물건제출하다를 제출하다.
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);
이 접근방식을 사용하는 장점:
- 새로운신규 작성을 만드는 것
Thread/AsyncTask
각 네트워크 작동을 위하여 비싸다.각 네트워크 운용에는 비용이 많이 듭니다.Thread/AsyncTask
는 파기되어 다음 네트워크 조작용으로 재작성됩니다. ,가 있으면Handler
★★★★★★★★★★★★★★★★★」HandlerThread
다수의 한 태스크로서)을, 1개의 「실행 가능한 태스크 「실행 가능한 태스크」에 할 수 .HandlerThread
를 사용하여Handler
풀이 도 언급하지 .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
}
});
이거 되는구나.방금 박사님을 만들었어요Luiji의 대답은 조금 더 간단하다.
new Thread() {
@Override
public void run() {
try {
//Your code goes here
} catch (Exception e) {
e.printStackTrace();
}
}
}.start();
메인 스레드는 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);
상세한 것에 대하여는, 여기를 봐 주세요.무통 스레드화
RxAndroid
이 문제에 대한 또 다른 더 나은 대안으로, 스레드를 만들고 안드로이드 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);
}
});
「 」를 지정해 .
(Schedulers.io())
는 RxAndroid 를 실행합니다.getFavoriteMusicShows()
른른른른른른른「」를 사용해 .
AndroidSchedulers.mainThread()
UI 에서 이 , 의 UI를 .onNext()
UI ui ui ui ui ui ui ui 。
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'
마지막 의존관계에는 .main 지원이 포함됩니다.스레드() 스케줄러
RxJava를 위한 훌륭한 전자책이 있습니다.
언급URL : https://stackoverflow.com/questions/6343166/how-can-i-fix-android-os-networkonmainthreadexception
'source' 카테고리의 다른 글
vuex를 사용하여 항목을 삭제하는 방법 (0) | 2022.08.03 |
---|---|
POSIX 소켓을 플러시하는 방법이 있습니까? (0) | 2022.08.03 |
롬복은 어떻게 작동하나요? (0) | 2022.08.01 |
문자열이 null과 동일한지 확인하는 방법 (0) | 2022.08.01 |
String.split()을 여러 딜리미터와 함께 사용합니다. (0) | 2022.08.01 |