Android HTTP Client Problems - android

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.

Related

Android app crashes due to NetworkOnMainThreadException [duplicate]

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.

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

Http Request in AsyncTask Causes OutofMemory Error on Multiple Screen Rotations

I am a new Android programmer. My first major task was to create an Http Post request which runs in an AsyncTask in a fragment.
I have spent well over a hundred hours learning the ins and outs of AsyncTask and its many flaws and quirks. I have read hundreds of pages, performed hundreds of Google searches and read tens of thousands of words in an attempt to solve this issue. I have examined EVERY. SINGLE. TINY. ASPECT. of my code, removing and replacing it tiny piece by tiny piece, often line by line, and debugging, attempting to figure out what is going on here. All I have discovered is a burning dislike for Android and the methodologies behind it.
I create an activity. Lets call it "Login". I then create a fragment. Let's call it "LoginTaskFragment". When a user taps a button, the fragment runs the AsyncTask, which executes a request to a url. If the response takes a long while (I add a sleep into the script on the server side to simulate this), and the user rotates the screen over and over again, at some point, the app will crash, returning an Out of Memory error.
This happens if I run the task in a UI-less fragment or UI fragment. It happens even though I call setRetainInstance(true). I have checked and I am 100 percent positive that the AsyncTask is NOT being re-run on screen rotation. Now, if I remove the Http Post request entirely, I do not have the issue (or perhaps the memory leak is too small to have an effect, even after over a hundred rotations, which I've tried). The problem still occurs even if I call asyncTask.cancel(false) ... or true ... in onStop. Using the WeakReference trick mentioned often alongside AsyncTasks in many tutorials makes no difference whatsoever.
I am also using the savedInstanceState Bundle in the activity to save certain pertinent data in the activity itself, and I am not entirely clear if this affects the fragment's asynctask lifetime. But my understanding is not.
Honestly, I feel that this is ridiculous and should not be an issue. At all. Since Android happily destroys your objects on screen rotation, it should happily be responsible with GC as well, but of course, we all know, it's not. It seems to be a patchwork, bandaid-ed joke.
Here is some code where I initialize the fragment in the activity:
LoginTaskFragment loginFieldsTask = new LoginTaskFragment();
getSupportFragmentManager().beginTransaction().add(loginFieldsTask,"loginFieldsTask").commit();
Here is the relevant fragment code. If I strip out EVERYTHING, and just leave this, I have the problem, regardless of anything else in my code:
...
protected JsonObject doInBackground(Void... params) {
String postUrl="<some nice url here>";
ArrayList<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2);
nameValuePairs.add(new BasicNameValuePair("username", "un"));
nameValuePairs.add(new BasicNameValuePair("password", "pw"));
HttpParams httpParameters = new BasicHttpParams();
HttpConnectionParams.setConnectionTimeout(httpParameters, 10000);
HttpConnectionParams.setSoTimeout(httpParameters, 30000);
DefaultHttpClient httpClient = new DefaultHttpClient(httpParameters);
HttpPost httpPost = new HttpPost(postUrl);
try {
httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
HttpResponse response = httpClient.execute(httpPost);
httpClient.getConnectionManager().shutdown();
BufferedReader reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent(), "UTF-8"));
String json = reader.readLine();
JsonElement jElement = new JsonParser().parse(json);
JsonObject jObject = jElement.getAsJsonObject();
return jObject;
} catch (ClientProtocolException e) {
httpClient.getConnectionManager().shutdown();
} catch (IOException e) {
httpClient.getConnectionManager().shutdown();
} catch (Exception e) {
httpClient.getConnectionManager().shutdown();
}
return null;
}
I know that if I set the socket timeout to a low number, it DOES seem to kill the thread and I can rotate to my heart's content. But I would like to leave the timeout at 30 seconds as in the code above to allow for older phone network connectivity problems.
My understanding is that since the thread is in a fragment, it SHOULD NOT BE RECREATED when the screen rotates. And this seems to be true. onCreate is definitely not being called on rotation.
This is the line at which everything hinges on, of course:
HttpResponse response = httpClient.execute(httpPost);
I can't believe no one has had this exact problem, but after over a hundred hours searching and slamming my head against the wall, I've had enough. I need someone better than me at this to tell me what's going on.
Edit: Adding android:configChanges="orientation|keyboardHidden|screenSize" is not a good idea, and is heavily discouraged for this use as bad practice. See [Handling the Configuration Change Yourself here]. In fact, this is the whole point of using a UI-less fragment in the first place. The AsyncTask fragment is NEVER destroyed until the task within is complete. It is thus never recreated despite the fact that underlying activity IS being recreated over and over.
If you dont want to recreate your async task in each rotation ( config change ) then in your manifest file
android:configChanges="orientation|keyboardHidden|screenSize"
<activity
android:name="com.app.MainActivity"
android:configChanges="orientation|keyboardHidden|screenSize" >
OR
When you use dinamic fragments, you must use a frame layout, and put the fragment inside it.
<com.myproyect.TopMenu
android:id="#+id/menu"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
<!-- this was the problem
<fragment
android:id="#+id/fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
class="com.myproyect.HomeFragment"
android:layout_below="#id/menu"
/> -->
<FrameLayout android:id="#+id/fragment"
android:layout_width="match_parent" android:layout_height="match_parent"
android:layout_below="#id/menu"/>
<LinearLayout
...
>
</LinearLayout>
</RelativeLayout>
And instantiate the fragment inside the FrameLayout.
fragmentTransaction.replace(R.id.fragment, f);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
You can use
getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
in your fragment class to limit the rotation so that it will not re-execute the code when the rotation occurs.

Android Ice Cream Sandwhich versus Gingerbread HTTP Post

Fairly new to Android and created/tested my app using Android 2.3.5 (Gingerbread). I have multiple database connections I used HTTP Post (but did not use AsyncTask) and everything worked great. I then tested it on Android 4.0.3 (Ice Cream Sandwhich) and I'm not able to connect to the database, therefore my app does not work.
Wondering what do I need to consider to allow this working app to run on Ice Cream Sandwhich? I did move the database connection out of the UI Thread (but not AsyncTask) and it still does not connect.
Here is my class I created outside of my UI Thread:
public class InputsRecapGetTask {
public InputsRecapGetTask(InputsRecap activity,
ProgressDialog progressDialog) {
this.activity = activity;
this.progressDialog = progressDialog;
getDatabase();
}
public void getDatabase() {
// TODO Auto-generated method stub
progressDialog.show();
// create new default httpClient
HttpClient httpclient = new DefaultHttpClient();
// create new http post with url to php file as pararmenter
HttpPost httppost = new HttpPost(
"http://test.com/returnBBD.php");
// assign input text to strings
user = Login.userStatic;
Did you examine the logs? IIRC, Android 4 requires that http requests are not done from the main thread. There must be a message telling this.
On the other hand, please keep in mind that
if you turn the screen, the Activity that created the AsyncTask may
be removed from the screen (forever) and replaced by another
Activity; it (the 1st Activity) will receive the result, but will not show anything;
in Android 4, all AsyncTasks are by default serviced by a single
thread; this guarantees that responses arrive in the order the
requests are made, but also means that the 2nd request will start only after the
1st one finishes (or times out).
According to MVC, the data retrieval must be done by the model, not by the controller (Activity) whose lifetime is that of a View.

Categories

Resources