It work as expected, to display the text file from internet, for android:minSdkVersion="9" or older. But fail with android:minSdkVersion="10" or higher. It's a strange and interesting issue for me.
After investigated into the logcat, I found that it's Caused by: android.os.NetworkOnMainThreadException!
android.os.NetworkOnMainThreadException is a exception that is thrown when an application attempts to perform a networking operation on its main thread.
This is only thrown for applications targeting the Honeycomb SDK or higher (actually it fail in my exercise with API level 10). Applications targeting earlier SDK versions are allowed to do networking on their main event loop threads, but it's heavily discouraged.
The solution is to move the internet accessing code to a background thread, AsyncTask in my exercise.
package com.exercise.AndroidInternetTxt;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.widget.TextView;
public class AndroidInternetTxt extends Activity {
TextView textMsg, textPrompt;
final String textSource = "http://sites.google.com/site/androidersite/text.txt";
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
textPrompt = (TextView)findViewById(R.id.textprompt);
textMsg = (TextView)findViewById(R.id.textmsg);
textPrompt.setText("Wait...");
new MyTask().execute();
/*
URL textUrl;
try {
textUrl = new URL(textSource);
BufferedReader bufferReader
= new BufferedReader(new InputStreamReader(textUrl.openStream()));
String StringBuffer;
String stringText = "";
while ((StringBuffer = bufferReader.readLine()) != null) {
stringText += StringBuffer;
}
bufferReader.close();
textMsg.setText(stringText);
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
textMsg.setText(e.toString());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
textMsg.setText(e.toString());
}
textPrompt.setText("Finished!");
*/
}
private class MyTask extends AsyncTask<Void, Void, Void>{
String textResult;
@Override
protected Void doInBackground(Void... params) {
URL textUrl;
try {
textUrl = new URL(textSource);
BufferedReader bufferReader
= new BufferedReader(new InputStreamReader(textUrl.openStream()));
String StringBuffer;
String stringText = "";
while ((StringBuffer = bufferReader.readLine()) != null) {
stringText += StringBuffer;
}
bufferReader.close();
textResult = stringText;
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
textResult = e.toString();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
textResult = e.toString();
}
return null;
}
@Override
protected void onPostExecute(Void result) {
textMsg.setText(textResult);
textPrompt.setText("Finished!");
super.onPostExecute(result);
}
}
}
Download the files.
Another un-recommended approach: StrictMode.setThreadPolicy and StrictMode.ThreadPolicy.Builder
More example:
- Load Bitmap from internet in background thread using AsyncTask
This comment has been removed by the author.
ReplyDeleteYou can fix this error by
ReplyDeleteadd two line
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
setContentView(R.layout.main);
hello manh hoang,
ReplyDeleteYes.
I already have a post: StrictMode.setThreadPolicy and StrictMode.ThreadPolicy.Builder
Thank you very much manh_hoang.
ReplyDeleteIt was very helpfull for me.
Thank you very much manh_hoang.
ReplyDeleteIt was helpful for me too.
FYI, this workaround using permitAll() on StrictMode is heavily discouraged. It is OK for small apps, I suppose, but it may cause your app to be unresponsive (or even crash) because the UI thread will be blocked by heavy operations which should instead be performed in a AsyncTask.
ReplyDeleteAdditionally, you can visit the following Android Developers blog entry on threading issues, very clear on how to circumvent the issue properly :
http://android-developers.blogspot.be/2009/05/painless-threading.html
@Android Er...
ReplyDeleteI have tried to use this code as inspiration on my project to debug this very problem. I have come across a problem on my end though. I used the "new MyTask().execute();" and the MyTask extends AsyncTask lines, reorganized original code and have this one pesky error. On the new MyTask it says it cannot be resolved to a type and wants me to create a .java file. I downloaded your zip file to see if you had one , but it was not there. how do I fix this? I am very new to Java and understand it wants a new file, but the code I need to execute is below in my setOnClickListener. I am a dude in small town Nebraska with nobody to mentor me, so I have to ask for the help of people like you. Thanks...
JJ
hello JJ,
ReplyDeleteBetter you can post your code.
I was unable to fit the code in this comment. It exceeded the limit. So I posted to your google+ account. If you have a way of posting it on this blog so others might benefit, feel free. Thanks.
ReplyDeleteJJ
My Result:
ReplyDeleteHello Android!
Finished!
Thank you very much. It was very helpful for me.
ReplyDeleteA very helpful link to understand the NetworkOnMainThread Exception.
ReplyDelete1. Make Manifest file changes
2. Inner class to extend AsyncTask and override the methods to code the functionality
Hello,
ReplyDeleteThe link to download the files is not available anymore. Please help. :/
package com.example.cctv_app;
ReplyDeleteimport java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.Socket;
import java.net.URL;
import com.example.cctv_app.*;
import android.os.AsyncTask;
import android.os.Bundle;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
public class MainActivity extends Activity {
EditText textOut;
TextView textIn;
Socket socket = null;
DataOutputStream dataOutputStream = null;
DataInputStream dataInputStream = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textOut = (EditText) findViewById(R.id.textout);
Button buttonSend = (Button) findViewById(R.id.send);
textIn = (TextView) findViewById(R.id.textin);
buttonSend.setOnClickListener(buttonSendOnClickListener);
}
@SuppressLint("ShowToast")
Button.OnClickListener buttonSendOnClickListener = new Button.OnClickListener() {
@Override
public void onClick(View arg0) {
new MyTask().execute();
/* try{
socket = new Socket("10.0.2.2",9000);
dataOutputStream = new DataOutputStream(socket.getOutputStream());
String s=textOut.getText().toString();
dataOutputStream.writeUTF(s);
dataInputStream = new DataInputStream(socket.getInputStream());
//data=dataInputStream.readUTF();
textIn.setText(dataInputStream.readUTF());
//Toast.makeText(getApplicationContext(), data, Toast.LENGTH_LONG).show();
}catch(Exception e)
{
e.printStackTrace();
}
*/
}
};
private class MyTask extends AsyncTask{
String textResult="";
@Override
protected Void doInBackground(Void... params) {
// URL textUrl;
try {
socket = new Socket("10.80.248.127",8888);
dataOutputStream = new DataOutputStream(socket.getOutputStream());
String s=textOut.getText().toString();
dataOutputStream.writeUTF(s);
dataInputStream = new DataInputStream(socket.getInputStream());
String data=dataInputStream.readUTF();
textIn.setText(data);
//Toast.makeText(getApplicationContext(), data, Toast.LENGTH_LONG).show();
}catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
textResult = e.toString();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
textResult = e.toString();
}
return null;
}
@Override
protected void onPostExecute(Void result) {
//textMsg.setText(textResult);
//textPrompt.setText("Finished!");
super.onPostExecute(result);
}
}
}
thank you..... manh hoang
ReplyDeleteHi,
ReplyDeletewhy this code is actually twice implemented (in onClick and in doInBackground)?
The right way is ONLY in doInBackground?
Thank you
hello Aurelian,
ReplyDeleteYes, the onClick one is used to show the error.