Android app crashes due to NetworkOnMainThreadException [duplicate] - android

This question already has answers here:
How can I fix 'android.os.NetworkOnMainThreadException'?
(66 answers)
Closed 7 years ago.
I want to develop an app that allows me to upload data from form of an android app as a text file in server
here is the mainactivity class
package com.example.incrediblemachine.sendtest;
import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends Activity {
EditText msgTextField;
Button sendButton;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//make message text field object
msgTextField = (EditText) findViewById(R.id.msgTextField);
//make button object
sendButton = (Button) findViewById(R.id.sendButton);
}
public void send(View v)
{
//get message from message box
String msg = msgTextField.getText().toString();
//check whether the msg empty or not
if(msg.length()>0) {
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost("http://ramsproject.16mb.com/sendorder.php");
try {
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2);
nameValuePairs.add(new BasicNameValuePair("id", "01"));
nameValuePairs.add(new BasicNameValuePair("message", msg));
httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
httpclient.execute(httppost);
msgTextField.setText(""); //reset the message text field
Toast.makeText(getBaseContext(),"Sent",Toast.LENGTH_SHORT).show();
}catch (IllegalStateException e)
{
e.printStackTrace();
}
catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
} else {
//display message if text field is empty
Toast.makeText(getBaseContext(),"All fields are required",Toast.LENGTH_SHORT).show();
}
}
}
It comes up with an exception at line 53
httpclient.execute(httppost);
the exception says android.app.NetworkOnMainThreadException
How do i solve this

Just use a thread.
Thread thread = new Thread(new Runnable(){
#Override
public void run() {
try {
//Your code goes here
} catch (Exception e) {
e.printStackTrace();
}
}
});
thread.start();
call the httpClient in this thread.

You can't do your network calls in your MainThread. You should use an asynctask for your network operations. You can find more information about it from the link below:
https://developer.android.com/reference/android/os/AsyncTask.html
Also i recommand you to use a network library to handle your network operations. You can find a good library for your network operations from the link below:
http://square.github.io/retrofit/

This exception that is thrown when an application attempts to perform a networking operation on its main thread.
Applications targeting the Honeycomb SDK or higher are allowed to do networking on their main event loop threads to avoide sluggishness on unresponsive situatons related to networs. you can reffer to Documentation.
To resolve this you have options like :
1.Using AsyncTasks
2. Threads
3. Handlers

I would like to provide a solution for you here. For this i would like to point few points before you understand the solution.
All android components(Activity,Service,BroadcastReceiver,Fragment and anything that visually shows data) run in the UI Thread or Main Thread, to understand this read further.
Every Android Application run on its own process and have a unique userID for it. When ever an android application is installed it is given a unique user ID. Whenever the application runs it is given a separate Memory space and path for program execution. This process consists of its own memory called Heap. The process is like a separate environment given to your application to run code or process code.
A thread on the other hand is a sub process or lightweight process. It is spawned inside the process. When ever a thread is created it is given some part of memory (stack). A process can spawn many number of threads.
A thread can not access another threads memory (stack) , it is private to the particular thread. But they can access the Process memory (heap memory). Think heap memory as a global memory.
Whenever a process is created for your application a single thread is created, which is mandatory. This thread is called a main thread. In android it maybe also referred as UI thread. Because this threads processes all the UI components that you see(Like activity,Fragment and Services(even though service is run on the background, it is run on UI Thread), etc).
Android framework is created in such a way that they wanted to handle all the UI operations on the Main thread giving it high priority to process UI components. Because the UI is the one shown to the user and the user will not like an application if it is frozen without processing the UI.
This is the reason you get a "NetworkOnMainThread" exception. Because Android restricts running long running operations like network access, file access, database access and those processings run on the UI Thread. Because it will take much time to process restricting the UI to be responsive, as it doesn't give an opportunity for the UI components to process.
I hope you understand why you get such exceptions now. Long running operations should not restrict UI thread operation. so it should be moved from UI thread to another new thread(Move the code where you create a HttpClient until you receive a response from it). Android also offers another alternative for this. You can create an AsyncTask, which handles the thread creation process for you. You can just write you code and pass the result to the UI thread. Learn more about it.
Notes: All threads access the process memory. But a process cannot access another process's memory unless it has the same USER ID. Means unless it is from one of your application. This can be done using AIDL interface.
I hope this solution helped you to understand the exception you get and solve them.

Related

How to make an app that syncs via internet for Android

I need a bit of help phrased in easy to understand terms. I've tried asking this question on multiple forums, but keep getting answers back that assume some knowledge even though I specified that I have only rudimentary skills in Android building and Java.
The user Skynet was very helpful when I asked my initial question here, but the research he/she prompted me to do proved difficult to follow up on.
https://stackoverflow.com/questions/28403243/how-to-make-an-app-that-syncs-via-internet
I want to make an app with a textview that updates via internet everytime the user open the app.
What is the best way to do this? And what would I have to do to do it?
Thank you in advance!
To get an idea of how new to this I am, here's an app I've published: https://play.google.com/store/apps/details?id=theveshtheva.debatebreaker
EDIT: I'm trying something but it doesn't seem to work. Could someone tell me what I'm doing wrong?
The webpage I'm trying to pull data from is here:
http://ktjdaily.blogspot.com/2015/02/menu-of-day.html
Here's my activity java file:
package theveshtheva.practice;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import android.widget.TextView;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.HttpContext;
public class onlinetext extends ActionBarActivity {
private String HTML;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_onlinetext);
/*FROM HERE*/
TextView outtext = (TextView) findViewById(R.id.textView);
try {
getHTML();
} catch (Exception e) {
e.printStackTrace();
}
outtext.setText("" + HTML);
/*TO HERE*/
}
private void getHTML() throws IOException
{
HttpClient httpClient = new DefaultHttpClient();
HttpContext localContext = new BasicHttpContext();
HttpGet httpGet = new HttpGet("http://ktjdaily.blogspot.com/2015/02/menu-of-day.html"); //URL!
HttpResponse response = httpClient.execute(httpGet, localContext);
String result = "";
BufferedReader reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
String line;
while ((line = reader.readLine()) != null) {
result += line + "\n";
HTML = result;
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_onlinetext, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
And here's the Manifest file, where I've set permissions:
<?xml version="1.0" encoding="utf-8" ?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="theveshtheva.practice">
<uses-permission android:name="android.permission.INTERNET" />
<application android:allowBackup="true" android:icon="#drawable/ic_launcher" android:label="#string/app_name" android:theme="#style/AppTheme">
<activity android:name=".onlinetext" android:label="#string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
There are HTTP apis already in Android that do this. There's like an Earthquake monitor sample application that pulls XML via HTTP in a background service.
Start there.
I feel like there is a lot of questions on how to sync android apps with online services or backend systems in general. So basically, I will try to expose here some ways you may have of doing so and I will try to keep it as simple as possible:
1)The world outside your mobile application
Ok, so you want to make an app that sends and retrieves information from through the internet...fine! But first of all, before even thinking about your app, have you thought about your server? the online service that holds the info your app should manipulate? So, yes! Your server/service should be ready and working when you start to think about writing an application that will do any online sync. By the way, a reasonable advice would be to start facing the term "application" as your whole service environment , including mobile apps and everything, not just one single mobile application per say.
If you have your own online service good to go or you just need to use 3rd party online services that are also ready, then that's the end of step 1.
2)Communicating with the outside world
Here you already have your functional online service. Now you need to set ways of communicating with it. Think as the "communication part" as a different project. Don't think it as just a bridge between your mobile app and your backend system. Think it as a bridge for any application from any environment to your system. A unique way that apps can reach your system and your system can reach them, exchanging valuable information for what they concern. We have some options here, but I will stick with the RESTApi. I won't describe here what is a RESTApi and how you actually write code around it(I guess that must be one of your biggest concerns), because someone already did in this epic SO question.
What you really need to understand here is the whole concept and then later you can checkout some frameworks(there are a lot) to actually implement it(you'll see that is the easiest part). To end the step 2, here is a REALLY simple diagram to show it (not the best, I know):
3) Finally, your android app
As using RESTApi , we're going to handle http requests. In order to do so, we have many ways of doing it in our android application. I will provide some code using the built-in HttpClient for better understanding : RestClient.java . This class is a real basic rest client that will do POST and GET http requests by just:
RestClient client = new RestClient();
client.execute("http://youronlineservice.com:3430/api/somegetrequest",RequestMethod.GET);
client.execute("http://youronlineservice.com:3430/api/somepostrequest",RequestMethod.POST);
Now, when dealing with the android environment, be careful with NetworkOnMainThreadException:
The exception that is thrown when an application attempts to perform a networking operation on its main thread.
Therefore, I strong recommend the use of AsyncTask when dealing with simple http requests, because:
AsyncTask enables proper and easy use of the UI thread. This class allows to perform background operations and publish results on the UI thread without having to manipulate threads and/or handlers.
AsyncTask is designed to be a helper class around Thread and Handler and does not constitute a generic threading framework. AsyncTasks should ideally be used for short operations (a few seconds at the most.) If you need to keep threads running for long periods of time, it is highly recommended you use the various APIs provided by the java.util.concurrent package such as Executor, ThreadPoolExecutor and FutureTask.
An asynchronous task is defined by a computation that runs on a background thread and whose result is published on the UI thread. An asynchronous task is defined by 3 generic types, called Params, Progress and Result, and 4 steps, called onPreExecute, doInBackground, onProgressUpdate and onPostExecute.
For ending, as you may be wondering, when you do a http request for your api you have to handle the response that will come. As you will figure out, there will be various types you can treat responses depending on the format you designed your api to work.
Mainly, you'll probably work with XML or JSON. But don't worry! There are plenty of stuff on how working with these formats in your android applications, including some awesome frameworks that you better discover yourself to see what fits you best.
After you're done with this, you may want to check some other stuff to increase the sync experience in your app, such as:
http://developer.android.com/training/sync-adapters/creating-sync-adapter.html
http://developer.android.com/reference/android/app/Service.html
And keep in mind that the best references you can get are here: http://developer.android.com/training/index.html
Hope it can help you and others!

httpResponse = httpClient.execute(httpGet);

My android app keeps on crashing.
I'm trying to connect to a webservice via post call.
But my app keeps on crashing every time it tries to call the webservice.
import android.app.Activity;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import java.io.IOException;
public class PostActivity extends Activity {
//static String response = null;
public void loadPost() throws IOException {
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpEntity httpEntity = null;
HttpResponse httpResponse = null;
String blogFeedUrl = "http://localhost/medapp/public/mobile/post";
HttpGet httpGet = new HttpGet(blogFeedUrl);
httpResponse = httpClient.execute(httpGet); // <-- this is where the application crashes
}
}
From the code you have posted and related imports in the same, depending on the O.S(Esp Honeycomb and onwards), your application would crash due to the NetworkOnMainThreadException. You are attempting the network operation on the main thread, not in a background thread or Asyctask.
In your logcat(if you post that it'l help), NetworkOnMainThreadException will be thrown:
E/AndroidRuntime(673): java.lang.RuntimeException: Unable to start activity
ComponentInfo{com.example/com.example.ExampleActivity}: android.os.NetworkOnMainThreadException
The explanation as to why this occurs is well documented on the Android developer's site:
A NetworkOnMainThreadException 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.
Applications targeting earlier SDK versions are allowed to do
networking on their main event loop threads, but it's heavily
discouraged.
Go through:
Why the app would crash or work depending on O.S.
Try AsyncTask to avoid NetworkOnMainThread
Why should you not use the Strict Mode alternative as your solution and only to debug(i'd suggest avoid that also actually, you know what is the problem now):
Critical to fix it, not by setting Thread policies

jsoup not working on android

I have a problem with jsoup on android. I have seen the other posts and tried solutions that were suggested there ( re-adding the jars, calling android fix tool, etc.)
I have added the jsoup jar to my android project (using build path), and added the required
internet permission to my manifest.
<uses-permission android:name="android.permission.INTERNET" />
but when I am trying to run my application I am getting
Could not find method org.jsoup.Jsoup.connect, referenced from method com.example.test.MainActivity.onCreate
I have tried to use the android fix tool but it did not solve the problem.
All I have is a main activity and I am trying to call
Document doc = Jsoup.connect("http://en.wikipedia.org/").get();
attached is part of my code
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
try {
Document doc = Jsoup.connect("http://en.wikipedia.org/").get();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
You are trying to run your connection in your main thread. Use AsyncTask and it will work.
I.E.
public class JsoupParser extends AsyncTask...
Why you have to use AsyncTask for network connections in android?
AsyncTask is an abstract helper class that enables you to use the UI thread correctly, while performing background operations in a different thread, without having to really handle threads or controllers. Since android is implemented using a single thread model, each time you launch an application, a new thread will be created.
Imagine you have a single thread model where you at a button click will parse a website using Jsoup. This would have worked fine in earler android versions, though you would have had a non-responsive screen until the network operation is done. The AsyncTask will run in the background enabling your screen to still be responsive while another thread takes care of the network communication.
Take a look in the API:
AsyncTask
NetworkOnMainThreadException
Delete all statements like:
System.out.println(something);
It worked for me, realizing this took me 2 hours.
In you normal activity
use this
public static int SDK_INT = android.os.Build.VERSION.SDK_INT;
and before fetching Document
write this inside try block
if (SDK_INT >= 10) {
ThreadPolicy tp = ThreadPolicy.LAX;
StrictMode.setThreadPolicy(tp);
}
it worked for me

Android HTTP Client Problems

I'm hoping someone can find this problem. I had an app that was fully working in server communications. Unfortunately, I somehow lost my Eclipse workspace when moving to the Windows 8 CP. I still had the .apk, and using Dex2jar and jd-gui, I was able to salvage a lot of code. I've got it all back into working condition, but this. I'm attempting to send a URL to a server, and get back a string response. Here's the code:
import org.apache.http.client.HttpClient;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.DefaultHttpClient;
public class login extends Activity{
<code>
public void pushLogin(View paramView){
try{
HttpClient client = new DefaultHttpClient();
HttpGet request = new HttpGet(loginFinal);
ResponseHandler<String> responseHandler = new BasicResponseHandler();
errorTextView.setText(loginFinal);
//code gets here
String response = client.execute(request, responseHandler);
//does not get here
errorTextView.setText(response);
}
My TextView always contains the string loginFinal, I cannot get it to display the response. To check this, I moved the errorTextView.setText(loginFinal); to the line after attempting to get the String response. It didn't run at that point either. I'm tearing my hair out, and I'm sure it's something simple. I've got the internet permission, I even found my original code for this portion of the app on this site as I posted it asking a separate question. This code is, as far as I can tell, identical. The only thing I can think of that changed is I moved my build target from Froyo to Honeycomb, as I decided I want to focus on tablets.
The best part is that LogCat does absolutely nothing when I press the button, triggering pushLogin. It doesn't seem to be triggering the client.execute(request, responseHandler) at all.
You are probably call pushLogin() on UI thread, Note that the thread policy has been changed since API Level 11 (HONEYCOMB), which in short, does not allow network operation (include HttpClient and HttpUrlConnection) get executed on UI thread, otherwise you get NetworkOnMainThreadException. The correct strategy is to call pushLogin() on background thread (AsycnTask as a good example).
Hope this help.

AsyncTask, must it take such a performance penalty hit...?

I'm developing a small app that reads in specific html-pages, re-formats them and then shows them in a WebView. If I run my code in the GUI thread, the performance hit is close to negligible compared to simply letting the WebView show the original html-page. But if I'm a good boy and do like I'm told, I'm supposed to use an AsyncTask to run the code in the background so as not to freeze up the GUI during those 3-5 seconds my code does its job. Problem is... if I do so, the code takes more than 10 times as long to finish. A page takes 60+ seconds to show, which is unacceptable.
Tracking down the problem, TraceView shows me that my AsyncTask is (at default priority) run in roughly 10 ms chunks, around 4 times per second. I need to set my thread priority to MAX_PRIORITY to get close to acceptable loading times, but even then it takes 3-4 times longer than when I run in the GUI thread.
Am I doing something wrong, or is this just the way it works? And must it work this way...?
Here's compilable code as requested:
package my.ownpackage.athome;
import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.StrictMode;
import android.webkit.WebView;
import android.webkit.WebViewClient;
public class AndroidTestActivity extends Activity
{
WebView webview;
//...
private class HelloWebViewClient extends WebViewClient
{
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url)
{
AndroidTestActivity.this.fetch(view, url);
return true;
}
}
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// To allow to connect to the web and pull down html-files, reset strict mode
// see http://stackoverflow.com/questions/8706464/defaulthttpclient-to-androidhttpclient
if (android.os.Build.VERSION.SDK_INT > 9)
{
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
}
// webview init etc...
fetch(webview, "http://www.example.com");
}
// This one calls either the AsyncTask or does it all manually in the GUI thread
public void fetch(WebView view, String url)
{
//** Use these when run as AsyncTask in background - SLOW!
//** Takes 30+ seconds at default thread priority, with MAX_PRIORITY 15+ seconds
// AsyncTask<Void, String, String> fx = new FilterX(url, view, this);
// fx.execute(); // running as AsyncTask takes roughly ten times longer than just plain load!
//** Use these when not running as AsyncTask - FAST! takes ~5 seconds
FilterX fx = new FilterX(url, view, this);
fx.onPreExecute();
final String str = fx.doInBackground();
fx.onPostExecute(str);
}
}
class FilterX extends AsyncTask<Void, String, String>
{
WebView the_view = null;
// other stuff...
FilterX(final String url, final WebView view, final Activity activity)
{
the_view = view;
// other initialization
// same code in both cases
}
protected void onPreExecute()
{
// same code in both cases
}
protected String doInBackground(Void... v)
{
// same in both cases...
return new String(); // just to make it compile
}
protected void onPostExecute(final String string)
{
the_view.loadUrl(string);
// same in both cases...
}
}
To run exactly the same code in my FilterX class when run as AsyncTask as when run on the GUI thread, I stripped all ProgressBar stuff, and then I get the following timings:
30+ seconds to load a page at default thread priority
15+ seconds to load a page at MAX_PRIORITY
5+ seconds to load a page when run in the GUI thread
You're not the only one observing this behaviour. The slowdown by factor 10 is probably a result of Android using a Linux cgroup (scheduling class) for threads of priority BACKGROUND or below. All these threads have to live with 10% CPU time altogether.
The good news is you don't have to live with the Thread priority settings from java.lang.Thread. You can assign your Thread a pthread (Linux thread) priority from the definitions in android.os.Process. There, you not only have Process.THREAD_PRIORITY_BACKGROUND, but also constants to adjust the priority a bit.
Currently, Android uses the background thread cgroup for all threads with priority THREAD_PRIORITY_BACKGROUND or worse, and THREAD_PRIORITY_BACKGROUND is 10 while THREAD_PRIORITY_DEFAULT is 0 and THREAD_PRIORITY_FOREGROUND is -2.
If you go for THREAD_PRIORITY_BACKGROUND + THREAD_PRIORITY_MORE_FAVORABLE (aka 9) your thread will be lifted out of the background cgroup with the 10% limitation, while not being important enough to interrupt your User Interface threads too often.
I believe there are background tasks which need a bit of computational power but which are at the same time not important enough to de facto block the UI (by consuming too much CPU in a separate thread) and Android currently has no obvious priority to assign to these, so in my view, this is one of the best priorities you can assign to such a task.
If you can use a HandlerThread it's easy to achieve:
ht = new HandlerThread("thread name", THREAD_PRIORITY_BACKGROUND + THREAD_PRIORITY_MORE_FAVORABLE);
ht.start();
h = new Handler(ht.getLooper());
If you want to go with AsyncTask, you can still do
protected final YourResult doInBackground(YourInputs... yis) {
Process.setThreadPriority(THREAD_PRIORITY_BACKGROUND + THREAD_PRIORITY_MORE_FAVORABLE);
...
}
but be aware that the underlying implementation may reuse the same Thread object for different tasks, for the next AsyncTask, or whatever. It seems that Android simply resets the priority after doInBackground() returns, though.
Of course, if your UI really consumes CPU and you want more power for your task at the same time, taking it away from the UI, you can set another priority, maybe up to Process.THREAD_PRIORITY_FOREGROUND.
AsyncTask runs at a lower priority to help making sure the UI thread will remain responsive.
Despite the performance hit, you do want to do this in the background. Play nice, and others will play nice with you.
Since I don't know what this is for, I can't suggest an alternative. My first reaction was that it's odd that you're trying to reformat HTML on a phone device. It's a phone, not a quad-core with oodles of RAM. Is it possible to do the reformatting in a web service and display the result on the phone?
u need to call final String str = fx.execute. you should not call doinbackground directly from ui thread.

Categories

Resources