I looked up my error online and people are telling to run the networking stuff on another thread or asyncTask but i have no clue how to fix this...
So everything works, app launches but then crashed and tells me "android.os.NetworkOnMainThreadException"
Here is my code:
public class Activity2 extends AppCompatActivity {
private static final String TAG = Activity2.class.getSimpleName();
private TextView fileContent;
String endstring = "";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_2);
fileContent = (TextView) findViewById(R.id.content_from_server);
try {
loadstuff();
} catch (IOException e) {
e.printStackTrace();
}
}
private void loadstuff() throws IOException {
URL url = new URL("http://ipaddress/login.php"); // URL to your application
Map<String,Object> params = new LinkedHashMap<>();
params.put("username", "test"); // All parameters, also easy
params.put("password", "test");
StringBuilder postData = new StringBuilder();
// POST as urlencoded is basically key-value pairs, as with GET
// This creates key=value&key=value&... pairs
for (Map.Entry<String,Object> param : params.entrySet()) {
if (postData.length() != 0) postData.append('&');
postData.append(URLEncoder.encode(param.getKey(), "UTF-8"));
postData.append('=');
postData.append(URLEncoder.encode(String.valueOf(param.getValue()), "UTF-8"));
}
// Convert string to byte array, as it should be sent
byte[] postDataBytes = postData.toString().getBytes("UTF-8");
// Connect, easy
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
// Tell server that this is POST and in which format is the data
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
conn.setRequestProperty("Content-Length", String.valueOf(postDataBytes.length));
conn.setDoOutput(true);
conn.getOutputStream().write(postDataBytes);
// This gets the output from your server
Reader in = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"));
for (int c; (c = in.read()) >= 0;)
endstring = endstring + (char)c;
fileContent.setText(endstring);
}
}
This exception occurs from API 11 or Android version 3.0, such as the real name, the process of discussion of chain messages in the main process (hence the name MainThread), in previous histories this operation is allowed although it is not recommended, depending on the time the process is needed, ANR (Application Not Responding).
The ideal solution is called this way because it is the form indicated by the android community, to implement this solution we must implement an inheritance of the class AsyncTask, this class allows to perform operations in the background
You can use too some library like retrofit, coroutine etc..
let me know if you resolved this issue :)
Hi like Henrique says you need to use an AsyncTask, its a class inside your class something like this
public class NameOfTask extends AsyncTask<Void, Void, Boolean>{
#Override
protected Boolean doInBackground(Void... voids) {
/*your code goes here*/
return true;
}
#Override
protected void onPostExecute(final Boolean success) {
/*If you need to do something after the task*/
}
#Override
protected void onCancelled() {
//if cancel you may need to do something in here
}
}
And calling you just need to call the class that you created.
something like this:
NameOfTask task = new NameOfTask();
task.execute((Void)null);
public class Activity2 extends AppCompatActivity {
private static final String TAG = Activity2.class.getSimpleName();
private TextView fileContent;
String endstring = "";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_2);
fileContent = (TextView) findViewById(R.id.content_from_server);
new AsyncLoadStuff().execute()
}
private void loadstuff() throws IOException {
URL url = new URL("http://ipaddress/login.php"); // URL to your application
Map<String,Object> params = new LinkedHashMap<>();
params.put("username", "test"); // All parameters, also easy
params.put("password", "test");
StringBuilder postData = new StringBuilder();
// POST as urlencoded is basically key-value pairs, as with GET
// This creates key=value&key=value&... pairs
for (Map.Entry<String,Object> param : params.entrySet()) {
if (postData.length() != 0) postData.append('&');
postData.append(URLEncoder.encode(param.getKey(), "UTF-8"));
postData.append('=');
postData.append(URLEncoder.encode(String.valueOf(param.getValue()), "UTF-8"));
}
// Convert string to byte array, as it should be sent
byte[] postDataBytes = postData.toString().getBytes("UTF-8");
// Connect, easy
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
// Tell server that this is POST and in which format is the data
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
conn.setRequestProperty("Content-Length", String.valueOf(postDataBytes.length));
conn.setDoOutput(true);
conn.getOutputStream().write(postDataBytes);
// This gets the output from your server
Reader in = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"));
for (int c; (c = in.read()) >= 0;)
endstring = endstring + (char)c;
fileContent.setText(endstring);
}
}
You can do something like this ...
//Its may be a inner class
// LoadStuff inside this class, it will be executed on separated class
private class AsyncLoadStuff extends AsyncTask<String, String, String> {
#Override
protected String doInBackground(String... params) {
try {
loadstuff();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(String result) {
//put load wait
}
}
Related
I have cleaned and rebuild my code as well but still the issue is not solved.
Below is the code:
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
String result = null;
String stringUrl = "https://www.ecowebhosting.co.uk/";
DownloadTask downloadTask = new DownloadTask();
downloadTask.execute(stringUrl);
}
public class DownloadTask extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... urls) {
String result = "";
URL url;
HttpURLConnection httpURLConnection = null;
try {
url = new URL(urls[0]);
//It is like opening a browser
httpURLConnection = (HttpURLConnection) url.openConnection();
InputStream in = httpURLConnection.getInputStream();
InputStreamReader reader = new InputStreamReader(in);
int data = reader.read();
while (data != -1) {
char currentChar = (char) data;
result = result + currentChar;
data = reader.read();
}
return result;
} catch (Exception e) {
e.printStackTrace();
return "Failed";
}
}
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
Log.i("Results",s);
}
}
}
The code is running fine but nothing is printed in the logs. The following is the log:
AsyncTask is an asynchronous process. So when you call Log.i("Result:", result);, the AsyncTask is not finished and result is still empty.
You should print your result from onPostExecute() method.
You can look on this page.
Here is some examples on how to implement an AsyncTask correctly:
https://www.upwork.com/hiring/mobile/why-you-should-use-asynctask-in-android-development/
How to use AsyncTask correctly in Android
Best
You only have to change code inside your doInBackGround
public class DownloadTask extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... urls) {
String result;
String inputLine;
try {
URL myUrl = new URL(urls[0]);
HttpURLConnection connection =(HttpURLConnection)
myUrl.openConnection();
connection.setReadTimeout(150000);
connection.setConnectTimeout(15000);
connection.setRequestMethod("GET");
connection.connect();
InputStreamReader streamReader = new InputStreamReader(connection.getInputStream());
//Create a new buffered reader and String Builder
BufferedReader reader = new BufferedReader(streamReader);
StringBuilder stringBuilder = new StringBuilder();
//Check if the line we are reading is not null
while((inputLine = reader.readLine()) != null){
stringBuilder.append(inputLine);
}
//Close our InputStream and Buffered reader
reader.close();
streamReader.close();
//Set our result equal to our stringBuilder
result = stringBuilder.toString();
} catch (Exception e) {
e.printStackTrace();
return "error";
}
return result;
}
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
Log.i("Results",s);
}
}
I've class with methods
class Wrapper {
public static String AuthIn(String Login, String Password){
String response = HTTPRequest.POST(client, GetAuthUrl(), RequestBuilder.AuthInVk(login, password));
System.out.println(response);
}
public static String GetInfoUser(){
String response = HTTPRequest.GET(client, "http://site1.com");
System.out.println(response);
}
}
When i call this methods in MainActivity class and get error message "Main thread ..... etc"
How write Wrapper class in AsyncTask ?
Here is a nice example taken from codexpedia, for more details please check their site.
public class MainActivity extends AppCompatActivity {
TextView tvWeatherJson;
Button btnFetchWeather;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tvWeatherJson = (TextView) findViewById(R.id.tv_weather_json);
btnFetchWeather = (Button) findViewById(R.id.btn_fetch_weather);
btnFetchWeather.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
new FetchWeatherData().execute();
}
});
}
private class FetchWeatherData extends AsyncTask<Void, Void, String> {
#Override
protected String doInBackground(Void... params) {
// These two need to be declared outside the try/catch
// so that they can be closed in the finally block.
HttpURLConnection urlConnection = null;
BufferedReader reader = null;
// Will contain the raw JSON response as a string.
String forecastJsonStr = null;
try {
// Construct the URL for the OpenWeatherMap query
// Possible parameters are avaiable at OWM's forecast API page, at
// http://openweathermap.org/API#forecast
URL url = new URL("http://api.openweathermap.org/data/2.5/forecast/daily?q=94043&mode=json&units=metric&cnt=7&appid=2de143494c0b295cca9337e1e96b00e0");
// Create the request to OpenWeatherMap, and open the connection
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod("GET");
urlConnection.connect();
// Read the input stream into a String
InputStream inputStream = urlConnection.getInputStream();
StringBuffer buffer = new StringBuffer();
if (inputStream == null) {
// Nothing to do.
return null;
}
reader = new BufferedReader(new InputStreamReader(inputStream));
String line;
while ((line = reader.readLine()) != null) {
// Since it's JSON, adding a newline isn't necessary (it won't affect parsing)
// But it does make debugging a *lot* easier if you print out the completed
// buffer for debugging.
buffer.append(line + "\n");
}
if (buffer.length() == 0) {
// Stream was empty. No point in parsing.
return null;
}
forecastJsonStr = buffer.toString();
return forecastJsonStr;
} catch (IOException e) {
Log.e("PlaceholderFragment", "Error ", e);
// If the code didn't successfully get the weather data, there's no point in attemping
// to parse it.
return null;
} finally{
if (urlConnection != null) {
urlConnection.disconnect();
}
if (reader != null) {
try {
reader.close();
} catch (final IOException e) {
Log.e("PlaceholderFragment", "Error closing stream", e);
}
}
}
}
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
tvWeatherJson.setText(s);
Log.i("json", s);
}
}
}
If you want to pass data into the async task doInBackground or onPostExcute and more check this stackoverflow comment : what-arguments-are-passed-into-asynctaskarg1-arg2-arg3
Keep in mind that your AsyncTask won't stop even when the activity has destroyed. A better way to create a network call from an activity is with an Handler Or just use an asyncHttp client lib such as ok-http , google volley :)
You always must perform network request form other thread than UI thread. So you can create abstarct class (network dispatcher) which extend AsyncTask or Thread or Runnable and add abstarct method which will be called in run/doInBackground/etc. Next implement abstarct method in your method. But it a little improvement to your boilerplate code. Also you can use JavaRx (AndroidRx) to perform networking method. Also you can use Retrofit with JavaRx.
EDIT
I see you edit your question. If you want use AsyncTask you should implement it and perform request in doInBackgroud
I'm trying to read something on a web page and store it in a var called "finalresult". I read the text, i used HttpURLConnection, and i did it in doInBacgorund from AsyncTask.
I'll show you my code :
public class MainActivity extends AppCompatActivity {
public String finalresult = "";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
class MyRemote extends AsyncTask<Void, Void, String> {
URL url;
HttpURLConnection connection = null;
#Override
protected String doInBackground(Void... params) {
try
{
//Create connection
url = new URL("My url bla bla");
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Language", "en-US");
connection.setUseCaches(false);
connection.setDoInput(true);
connection.setDoOutput(true);
//Send request
DataOutputStream wr = new DataOutputStream(connection.getOutputStream());
wr.flush();
wr.close();
//Get Response
InputStream is = connection.getInputStream();
BufferedReader rd = new BufferedReader(new InputStreamReader(is));
String line;
StringBuffer response = new StringBuffer();
while ((line = rd.readLine()) != null) {
response.append(line);
response.append('\r');
}
rd.close();
finalresult = response.toString();
} catch (Exception e) {
e.printStackTrace();
} finally
{
if (connection != null) {
connection.disconnect();
}
}
return null;
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
}
}
And when i want to use the "finalresult" var in the Main Activity Class I CAN'T, because it's empty. HOW CAN I GET THAT RESULT IN MY MAIN ACTIVITY CLASS?
Txh.
By the way, i'm a beginner.
Please take a look at Android's documentation for AsyncTask. Also, I'm not sure if you're missing a bracket or something, but note that your MyRemote class declaration cannot be inside the onCreate() method.
The reason why your finalResult variable is empty is because you never actually used the MyRemote class that you implemented.
So you need
new MyRemote().execute();
in your onCreate() method. Also, keep in mind that because this request is asynchronous it would make sense to use your finalResult variable in the onPostExecute() method.
Additionally, it's not a great idea to hardcode the URL the way you did with
url = new URL("My url bla bla");
Instead it should be passed in as a parameter to the execute() method. Again, take a look at the documentation and it should become a lot clearer.
I am totally new in java and android.. I am sure I did it wrong on the code, please help me fix it
I try to send the content of a tweet as a String from an android application to this online parser: http://demo.ark.cs.cmu.edu/parse, and I want to retrieve the result of the parsing, here is my code:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.test);
String Tobetag = urlEncode(contentTweet);
new Analyser().execute();
}
private String urlEncode(String s){
try {
return URLEncoder.encode(s,"UTF-8").replace("+", "%20");
}
catch ( UnsupportedEncodingException e) {
throw new RuntimeException(s,e);
}
}
private class Analyser extends AsyncTask<Integer, Integer, Integer>
{
private String mUrl = "http://demo.ark.cs.cmu.edu/parse?sentence=";
#Override
protected Integer doInBackground(Integer... params) {
// TODO Auto-generated method stub
try
{
DefaultHttpClient client = new DefaultHttpClient();
HttpGet request = new HttpGet();
request.setURI(new URI(mUrl + mTobetag));
HttpResponse response = client.execute(request);
InputStream in = response.getEntity().getContent();
BufferedReader reader = new BufferedReader( new InputStreamReader(in) );
String result = reader.readLine();
System.out.println("Top");
System.out.println(result);
System.out.println("Bottom");
in.close();
}
catch(Exception e)
{
Log.e("Twitter", "doInBackground_" + e.toString());
}
return new Integer(1);
}
protected void onProgressUpdate(Integer... progress) {
}
#Override
protected void onPostExecute(Integer i) {
}
}
I ran the code, no error reported but I didn't get the parse result, I only have this:
What can I do to get the result I wanted?
P.S. Also I am not sure I used the urlencoder right, it turn the slashes of the tweet content into %2F, but when I use the online parser by a browser, it shows that it doesn't change the slashed at all, please help
You are reading only the first line of the response, if you want to read the entire response you can do it like this:
String result = "";
for(String line;(line=br.readLine())!=null;){
result += line;
}
This will get you the entire http://demo.ark.cs.cmu.edu/parse page as a response, if you want the response to be only a JSON object, use this URL instead http://demo.ark.cs.cmu.edu/parse/api/v1/parse?sentence=....
After being confused about how to do so (as can be seen here and here, I am now successfully connecting to my server app and the appropriate RESTful method with this code:
public void onFetchBtnClicked(View v){
if(v.getId() == R.id.FetchBtn){
Toast.makeText(getApplicationContext(), "You mashed the button, dude.", Toast.LENGTH_SHORT).show();
new CallAPI().execute("http://10.0.2.2:28642/api/Departments/GetCount?serialNum=4242");
}
}
public static class CallAPI extends AsyncTask<String, String, String> {
#Override
protected String doInBackground(String... params) {
String urlString=params[0]; // URL to call
String resultToDisplay = "";
InputStream in = null;
// HTTP Get
try {
URL url = new URL(urlString);
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
in = new BufferedInputStream(urlConnection.getInputStream());
} catch (Exception e ) {
System.out.println(e.getMessage());
return e.getMessage();
}
return resultToDisplay;
}
protected void onPostExecute(String result) {
Log.i("FromOnPostExecute", result);
}
} // end CallAPI
I realize I need to assign something (other than an empty string at initialization) to resultToDisplay, but what? What part of "in" do I need to access/covert to a string?
UPDATE
The "manual" way is working for me, but the fancypants apache io utils "not so much" (well, it compiles...). This is my code:
try {
URL url = new URL(urlString);
HttpURLConnection urlConnection = (HttpURLConnection)url.openConnection();
in = new BufferedInputStream(urlConnection.getInputStream());
resultToDisplay = getStringFromInputStream(in);
total = IOUtils.toString(in);
resultToDisplay's assignment works (I get, "18"). total's assignment does not (I get, "").
Note: The "getStringFromInputStream()" method is from Raghunandan's link.
UPDATE 2
This works just dandy (using WIllJBD's idea to use apache commons' IOUtils):
new CallWebAPI().execute("http://10.0.2.2:28642/api/Departments/GetCount?serialNum=4242");
. . .
private class CallWebAPI extends AsyncTask<String, String, String> {
#Override
protected String doInBackground(String... params) {
String urlString=params[0]; // URL to call
String result = "";
// HTTP Get
try {
URL url = new URL(urlString);
HttpURLConnection urlConnection =
(HttpURLConnection)url.openConnection();
InputStream inputStream = urlConnection.getInputStream();
if (null != inputStream)
result= IOUtils.toString(inputStream);
} catch (Exception e ) {
System.out.println(e.getMessage());
return e.getMessage();
}
return result;
}
#Override
protected void onPostExecute(String result) {
Log.i("RenameTheWashingtonFootballTeamTheRedskinPeanuts", result);
}
}
...and so apparently it is not necessary to add anything like "compile files('libs/commons-io-2.4.jar')" to the dependencies section of build.gradle, as seemingly was at least necessary at one time, according to this. If anybody can verify such a[m,pp]endments to build.gradle are no longer needed, I'd be gradleful.
UPDATE 4
I just noticed that I inadvertently removed the "#Override" from the onPostExecute() method, but it made no difference - it worked fine without it, and it works fine once I restored it. So what's the advantage of [not] having it - is it just superfluous fluff?
why not use something like IOUtils?
InputStream inputStream = urlConnection.getInputStream();
if (inputStream != null)
String content = IOUtils.toString(inputStream);
http://commons.apache.org/proper/commons-io/apidocs/org/apache/commons/io/IOUtils.html
now you can parse the string into Json or XML, using one of many libraries.