android.os の NetworkOnMainThreadException。
2022-02-08 02:49:18
android testを使用してWebサーバーのWebサービスにアクセスする場合、以下のコードでMainActivityのメインスレッドでWebサービスにアクセスされます。
package com.example.myandroidpro;
import java.io.File;
import org.ksoap2.SoapEnvelope;
import org.ksoap2.serialization.SoapObject;
import org.ksoap2.serialization.SoapSerializationEnvelope;
import org.ksoap2.transport.HttpTransportSE;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.os.Bundle;
import android.os.Environment;
import android.os.StrictMode;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget;
Toast; import android.widget;
public class MainActivity extends Activity {
private static String NAMESPACE = "http://service.cxf.test/";
// webService address
private static String URL = "http://192.168.1.119:8080/CxfWebService/services/HelloService/";
private String method_name = null;
private Button activity_main_btn1;
@SuppressLint("NewApi") @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
StrictMode.ThreadPolicy policy=new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
File rootDirectory = Environment.getRootDirectory();//Get the phone root directory
File storageDirectory = Environment.getExternalStorageDirectory();//Get the root directory of SD card
for(File file : rootDirectory.listFiles()){
System.err.println(file.isDirectory()+","+file.getName());
}
findVIew();
activity_main_btn1.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
// send webservice request
sayHi("zxn");
}
});
}
private void findVIew() {
activity_main_btn1 = (Button) findViewById(R.id.activity_main_btn1);
}
private String sayHi(String name) {
String result = null;
// (1) Specify the namespace of the webservice and the method name to call
method_name = "sayHi";
SoapObject soapObj = new SoapObject(NAMESPACE, method_name);
/**
* (2) Set the values of the parameters of the calling method, which can be omitted if there are no parameters. Note that the parameters must correspond to the variable names in the @WebParam of the service declaration
*/
soapObj.addProperty("name", name);
// (3) Generate SOAP request information for calling the Webservice method. This information is described by the SoapSerializationEnvelope object
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(
SoapEnvelope.VER11);
// envelope.bodyOut = rpc;
envelope.dotNet = false;
envelope.setOutputSoapObject(soapObj);
// (4) Create HttpTransportsSE object. You can specify the URL of the WSDL document of the WebService through the constructor of the AndroidHttpTransport class
HttpTransportSE ht = new HttpTransportSE(URL);
try {
// (5) Call the WebService method using the call method
ht.call(null, envelope);
// (6) Use the getResponse method to get the return result of the WebService method
if (envelope.getResponse() ! = null) {
System.out.println(envelope.getResponse());
result = String.valueOf(envelope.getResponse());
Toast.makeText(MainActivity.this, result, Toast.LENGTH_SHORT)
.show();
}
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
}
androidバージョン4.3で、メインスレッドでネットワークにアクセスすると、以下のような例外が発生します。
<span style="background-color: rgb(255, 204, 255);">05-15 02:00:05.769: W/System.err(2269): android.os. NetworkOnMainThreadException
05-15 02:00:05.799: W/System.err(2269): at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1133)</span>
05-15 02:00:05.799: W/System.err(2269): at libcore.io.BlockGuardOs.connect(BlockGuardOs.java:84)
05-15 02:00:05.810: W/System.err(2269): at libcore.io.IoBridge.connectErrno(IoBridge.java:144)
05-15 02:00:05.810: W/System.err(2269): at libcore.io.IoBridge.connect(IoBridge.java:112)
05-15 02:00:05.869: D/dalvikvm(2269): GC_FOR_ALLOC freed 345K, 14% free 2674K/3076K, paused 48ms, total 52ms
05-15 02:00:05.869: W/System.err(2269): at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:192)
05-15 02:00:05.880: W/System.err(2269): at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:459)
05-15 02:00:05.880: W/System.err(2269): at java.net.Socket.connect(Socket.java:842)
05-15 02:00:05.889: W/System.err(2269): at libcore.net.http.HttpConnection.<init>(HttpConnection.java:76)
05-15 02:00:05.889: W/System.err(2269): at libcore.net.http.HttpConnection.<init>(HttpConnection.java:50)
05-15 02:00:05.899: W/System.err(2269): at libcore.net.http.HttpConnection$Address.connect(HttpConnection.java:340)
05-15 02:00:05.899: W/System.err(2269): at libcore.net.http.HttpConnectionPool.get(HttpConnectionPool.java:87)
05-15 02:00:05.899: W/System.err(2269): at libcore.net.http.HttpConnection.connect(HttpConnection.java:128)
05-15 02:00:05.899: W/System.err(2269): at libcore.net.http.HttpEngine.openSocketConnection(HttpEngine.java:316)
05-15 02:00:05.899: W/System.err(2269): at libcore.net.http.HttpEngine.connect(HttpEngine.java:311)
05-15 02:00:05.909: W/System.err(2269): at libcore.net.http.HttpEngine.sendSocketRequest(HttpEngine.java:290)
05-15 02:00:05.909: W/System.err(2269): at libcore.net.http.HttpEngine.sendRequest(HttpEngine.java:240)
05-15 02:00:05.909: W/System.err(2269): at libcore.net.http.HttpURLConnectionImpl.connect(HttpURLConnectionImpl.java:81)
05-15 02:00:05.909: W/System.err(2269): at libcore.net.http.HttpURLConnectionImpl.getOutputStream(HttpURLConnectionImpl.java:197)
05-15 02:00:05.919: W/System.err(2269): at org.ksoap2.transport.ServiceConnectionSE.openOutputStream(ServiceConnectionSE.java:126)
05-15 02:00:05.919
理由
Android.os.NetworkOnMainThreadException は、メインスレッドでネットワークにアクセスするなと言っています。これは、アンドロイド 3.0 から、プログラムがメインスレッドでネットワークにアクセスせず、ネットワークへのアクセスを別スレッドにするために必須となっています。
解決策
開発では、ネットワークへのアクセスがメインスレッドをブロックしないように、ネットワークへのアクセスを別スレッドや非同期スレッドAsyncTaskに置くのが一般的です。
まず、AndroidManifest.xml ファイルの manifest ノードに、以下の設定を追加します。
<uses-permission android:name="android.permission.INTERNET"/>
1. これらの強制的なポリシーに関する問題を無視したい場合は、以下のように
StrictMode.ThreadPolicy policy=new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
を追加し、メソッドに @SuppressLint("NewApi") を追加してリトライすると、OKです。
2. ウェブアクセスを別スレッドにする。
package com.example.myandroidpro;
import java.io.File;
import org.ksoap2.SoapEnvelope;
import org.ksoap2.serialization.SoapObject;
import org.ksoap2.serialization.SoapSerializationEnvelope;
import org.ksoap2.transport.HttpTransportSE;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Looper;
import android.os;
import android.os.StrictMode;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget;
Toast; import android.widget;
public class MainActivity extends Activity {
private static String NAMESPACE = "http://service.cxf.test/";
// webService address
private static String URL = "http://192.168.1.119:8080/CxfWebService/services/HelloService/";
private String method_name = null;
private Button activity_main_btn1;
private int ANDROID_ACCESS_CXF_WEBSERVICES = 001;
private Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
String result = (String) msg.getData().get("result");
String obj = (String) msg.obj;//
activity_main_btn1.setText("The result of the request is: "+result);
}
};
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
File rootDirectory = Environment.getRootDirectory();//Get the phone root directory
File storageDirectory = Environment.getExternalStorageDirectory();//Get the root directory of SD card
for(File file : rootDirectory.listFiles()){
System.err.println(file.isDirectory()+","+file.getName());
}
findVIew();
activity_main_btn1.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
Thread accessWebServiceThread = new Thread(new WebServiceHandler());
accessWebServiceThread.start();
}
});
}
class WebServiceHandler implements Runnable{
@Override
public void run() {
Looper.prepare();
String result = sayHi("zxn");
Message message = new Message();
Bundle bundle = new Bundle();
bundle.putString("result", result);
message.what = ANDROID_ACCESS_CXF_WEBSERVICES;//set the message label
message.obj = "zxn";
message.setData(bundle);//message content
handler.sendMessage(message);//send the message
Looper.loop();
}
}
private void findVIew() {
activity_main_btn1 = (Button) findViewById(R.id.activity_main_btn1);
}
private String sayHi(String name) {
String result = null;
// (1) Specify the namespace of the webservice and the method name to call
method_name = "sayHi";
SoapObject soapObj = new SoapObject(NAMESPACE, method_name);
/**
* (2) Set the value of the parameter to call the method, if there is no parameter, you can omit it. Note that the parameters must correspond to the variable names inside the @WebParam of the service declaration
*/
soapObj.addProperty("name", name);
// (3) Generate SOAP request information for calling the Webservice method. This information is described by the SoapSerializationEnvelope object
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(
SoapEnvelope.VER11);
// envelope.bodyOut = rpc;
envelope.dotNet = false;
envelope.setOutputSoapObject(soapObj);
// (4) Create HttpTransportsSE object. You can specify the URL of the WSDL document of the WebService through the constructor of the AndroidHttpTransport class
HttpTransportSE ht = new HttpTransportSE(URL);
try {
// (5) Call the WebService method using the call method
ht.call(null, envelope);
// (6) Use the getResponse method to get the return result of the WebService method
if (envelope.getResponse() ! = null) {
System.out.println(envelope.getResponse());
result = String.valueOf(envelope.getResponse());
Toast.makeText(MainActivity.this, result, Toast.LENGTH_SHORT)
.show();
}
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
}
MainActivityの対応するレイアウトは以下の通りです。
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<LinearLayout android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<TextView
android:id="@+id/activity_main_tv1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/hello_world" />
<Button
android:id="@+id/activity_main_btn1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/test_for_cxf_webservice" />
</LinearLayout>
</RelativeLayout>
3. 3. ネットワークアクセスを非同期タスクAsyncTaskに以下のコードで記述します。
package com.example.myandroidpro;
import java.io.File;
import org.ksoap2.SoapEnvelope;
import org.ksoap2.serialization.SoapObject;
import org.ksoap2.serialization.SoapSerializationEnvelope;
import org.ksoap2.transport.HttpTransportSE;
import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Environment;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget;
public class MainActivity extends Activity {
private static String NAMESPACE = "http://service.cxf.test/";
// webService address
private static String URL = "http://192.168.1.119:8080/CxfWebService/services/HelloService/";
private String method_name = null;
private Button activity_main_btn1;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
File rootDirectory = Environment.getRootDirectory();//Get the phone root directory
File storageDirectory = Environment.getExternalStorageDirectory();//Get the root directory of SD card
for(File file : rootDirectory.listFiles()){
System.err.println(file.isDirectory()+","+file.getName());
}
findVIew();
activity_main_btn1.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
accessWSAction();
}
private void accessWSAction() {
new AsyncTask<String, Void, Object>() {
// The onPostExecute method will be called by the UI thread after the doInBackground execution is complete.
// The result of the background calculation will be passed to the UI thread via this method and displayed to the user in the interface.
protected void onPostExecute(Object result) {
super.onPostExecute(result);
activity_main_btn1.setText("The result of the request is: "+result);//you can update the UI
}
//this method runs in the background thread, so you can't update the UI in this thread, the UI thread is the main thread
protected Object doInBackground(String... params) {
String result = sayHi("zxn");
// activity_main_btn1.setText("Request result is: "+result);
return result;
}
}.execute();
}
});
}
private void findVIew() {
activity_main_btn1 = (Button) findViewById(R.id.activity_main_btn1);
}
private String sayHi(String name) {
String result = null;
// (1) Specify the namespace of the webservice and the method name to call
method_name = "sayHi";
SoapObject soapObj = new SoapObject(NAMESPACE, method_name);
/**
* (2) Set the value of the parameter to call the method, if there is no parameter, you can omit it. Note that the parameters must correspond to the variable names inside the @WebParam of the service declaration
*/
soapObj.addProperty("name", name);
// (3) Generate SOAP request information for calling the Webservice method. This information is described by the SoapSerializationEnvelope object
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(
SoapEnvelope.VER11);
// envelope.bodyOut = rpc;
envelope.dotNet = false;
envelope.setOutputSoapObject(soapObj);
// (4) Create HttpTransportsSE object. You can specify the URL of the WSDL document of the WebService through the constructor of the AndroidHttpTransport class
HttpTransportSE ht = new HttpTransportSE(URL);
try {
// (5) Call the WebService method using the call method
ht.call(null, envelope);
// (6) Use the getResponse method to get the return result of the WebService method
if (envelope.getResponse() ! = null) {
System.out.println(envelope.getResponse());
result = String.valueOf(envelope.getResponse());
// Toast.makeText(MainActivity.this, result, Toast.LENGTH_SHORT)
// .show();
}
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
}
関連
-
デフォルトのアクティビティが見つからない場合の対処法
-
Androidで発生した問題、解決策とヒント
-
アンドロイドプロジェクトのパッケージングにgradleを使用する際の問題点
-
エラーが発生しました。ArrayAdapter は、リソース ID が TextView である必要があります。
-
例外「指定された子にはすでに親がいます」の解決方法。removeViewを呼び出す必要があります" の解決方法(ソースコード付き例)
-
repo: コマンドが見つかりません
-
Android Get set image.setImageResource(R.drawable.xxx) リソース
-
アンドロイドシェイプ、グラデーション、角丸、ボーダーラインの設定
-
アンドロイドスタジオ学習入門
-
Android TextViewは、テキスト内容が表示省略記号を超えているかどうかを判断する
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
AndroidエミュレーターのADBサーバーがACKしない問題
-
RuntimeException: アクティビティを開始できません ComponentInfo solution
-
Android: インポートモジュールエラー Android リソースのリンクに失敗しました
-
ArrayAdapter は、リソース ID が TextView であることが必要です。
-
アンドロイドスタジオのエラーを解決する --> Error:(1, 0) id 'com.android.application' を持つプラグインが見つかりません。
-
アンドロイドのエリプサイズを使用する
-
Androidのカラーグラデーション実装のまとめ
-
Android studio 制約レイアウト ConstraintLayout
-
CursorIndexOutOfBoundsException:インデックス -1 が要求されました。
-
AndroidManifest.xmlの最も完全な詳細な説明