Android to remain logged in with cookies for fetching json data - java

This has been asked in different ways so far, but I am unable to find a solution to this particular issue.
Short Version:
I am seeking a way to fetch json from a URL that requires authentication. And rather than authenticating every time, I want it to store the received cookies so that it doesn't have to re-login, and on subsequent connections remain logged in.
Long version:
Basically, I want the app to store the user's username and password (as internal private strings with shared preferences). Then after that, it would call a login url to authenticate and remain logged in(get the cookies). Once this is done, I want the program to fetch json data from different urls (that require a user to be logged in via cookies for example). I want this to remain in place even after the app is paused or destroyed.
It can be considered as an idea similar to a chrome plugin that can simply fetch data from a website once its logged in.
I reckon the solution to this would be useful for many developers who are new to android.

try this it stores username pass and session into shared pref
app_preferences = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
userid=app_preferences.getLong("userid",0);
username=app_preferences.getString("username", "");
password=app_preferences.getString("password", "");
session=app_preferences.getString("session", "");
class task extends AsyncTask<String, integer, Boolean>{
//httpreqclass htrq= new httpreqclass();
#Override
protected void onPreExecute() {
// TODO Auto-generated method stub
showProgressDialog();
}
#Override
protected Boolean doInBackground(String... params) {
String usr=params[0];
String p=params[1];
String data[]=new String[2];
String ur= "http://192.168.1.45/Android.asmx/Login";
// TODO Auto-generated method stub
data= postData(usr,p,ur);
boolean sucess=false;
try {
JSONObject jso = new JSONObject(data[0]);
sucess =jso.getBoolean("isSucceeded");
if (sucess) {
SharedPreferences.Editor editor = app_preferences.edit();
JSONObject jsr= jso.getJSONObject("result");
Long a= jsr.getLong("Id");
editor.putLong("userid", a);
editor.putString("username", usr);
editor.putString("password", p);
editor.putString("session", data[1]);
editor.commit(); // Very important
}
}catch (Exception e){
}
return sucess;
}
#Override
protected void onPostExecute(Boolean result) {
// TODO Auto-generated method stub
here put code what you want to do next
}
}
public String[] postData(String u, String p,String url) {
String asp = null,data = null;
String[] rtrn=new String[2];
//Log.e("i entrd here", "");
try {
HttpClient httpclient = new DefaultHttpClient(getHttpParams());
HttpPost httppost = new HttpPost();
HttpResponse response;
List<NameValuePair> params = new ArrayList<NameValuePair>();
params.add(new BasicNameValuePair("EmailId", u));
params.add(new BasicNameValuePair("PassWord", p));
UrlEncodedFormEntity ent = new UrlEncodedFormEntity(params,HTTP.UTF_8);
httppost.setEntity(ent);
response = httpclient.execute(httppost);
Header[] headers;
headers = response.getHeaders("Set-Cookie");
//Header atha= respone.getFirstHeader("PHPSESSID");
List<Cookie> cookies = ((AbstractHttpClient) httpclient).getCookieStore().getCookies();
if (cookies.isEmpty()) {
Log.d("TAG","no cookies received");
} else {
for (int i = 0; i < cookies.size(); i++) {
if(cookies.get(i).getName().contentEquals("ASP.NET_SessionId")) {
asp = cookies.get(i).getValue();
}
}
Log.e("this is the cookiee", asp);
}
HttpEntity entity = response.getEntity();
InputStream is = entity.getContent();
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
StringBuilder sb = new StringBuilder();
String line = null;
while ((line = reader.readLine()) != null) {
sb.append(line + "\n");
}
is.close();
Log.e("", sb.toString());
rtrn[0]=sb.toString();
rtrn[1]=asp;
} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return rtrn;
}
private HttpParams getHttpParams() {
HttpParams htpp = new BasicHttpParams();
HttpConnectionParams.setConnectionTimeout(htpp, 3000);
HttpConnectionParams.setSoTimeout(htpp, 5000);
return htpp;
}
you can refer the code and make the application as per your logic
and note when the next time onwards when you send a request to the server do not forget to add the session/cookie in the header

Just to not leave the question unanswered and explain how I solved the problem, here is my answer.
I resorted to use the Loopj Android Async Http Client library, which is being used by major apps like Instagram and Pinterest.
Keeping the cookies persistent is pretty simple this way. All you need is:
AsyncHttpClient myClient = new AsyncHttpClient(); // a client instance
PersistentCookieStore myCookieStore = new PersistentCookieStore(this);
myClient.setCookieStore(myCookieStore); // setting the cookie store

Related

Sending HTTPS post request in android using HTTPClient for unverified certificates

I have written this piece of code for sending the POST request to a localhost server running nodejs having a certificate generated using openssl command. But when I am trying to send the post request, I can see in android log the issue with the trust anchor and POST request on https is not working but is working if I remove the certificate from nodejs server and send request with http. I know this is because my certificate is not verified from any well known CA like verisign. So, how can I send the request to this https server? I also tried installing the certificate in my android phone but it didn't solved my problem either. I can post the source code of HttpClient.java as well.
public class MainActivity extends AppCompatActivity {
Button encAndSendBtn;
TextView companyName, modelNumber, specification;
public MainActivity() throws MalformedURLException {
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
encAndSendBtn = (Button) findViewById(R.id.encAndSend);
companyName = (TextView) findViewById(R.id.company);
modelNumber = (TextView) findViewById(R.id.modNum);
specification = (TextView) findViewById(R.id.spec);
}
public void onclickbutton(View view) {
encSend scv = new encSend();
scv.execute();
}
private class encSend extends AsyncTask {
String companyNameS = companyName.getText().toString();
String modelNumberS = modelNumber.getText().toString();
String specificationS = specification.getText().toString();
#Override
protected Object doInBackground(Object[] objects) {
JSONObject jsonObjSend = new JSONObject();
JSONObject encrptObjSend = new JSONObject();
try {
jsonObjSend.put("Company", companyNameS);
jsonObjSend.put("Model Number", modelNumberS);
jsonObjSend.put("Specification", specificationS);
String finalData = jsonObjSend.toString();
Log.i("data", finalData);
String key = "HelloWorld321#!";
String encrypt;
try {
CryptLib cryptLib = new CryptLib();
String iv = "1234123412341234";
encrypt = cryptLib.encryptSimple(finalData, key, iv);
encrptObjSend.put("encrptedtext", encrypt);
} catch (Exception e) {
e.printStackTrace();
}
Log.i("Encrypted data", encrptObjSend.toString());
JSONObject header = new JSONObject();
header.put("deviceType", "Android"); // Device type
header.put("deviceVersion", "2.0"); // Device OS version
header.put("language", "es-es"); // Language of the Android client
encrptObjSend.put("header", header);
} catch (JSONException e) {
e.printStackTrace();
}
JSONObject jsonObjRecv = HttpClient.SendHttpPost("https://192.168.43.59:443/api/aes", encrptObjSend);
return "success";
}
}
}
Update:
public class HttpClient {
private static final String TAG = "HttpClient";
public static JSONObject SendHttpPost(String URL, JSONObject jsonObjSend) {
try {
DefaultHttpClient httpclient = new DefaultHttpClient();
HttpPost httpPostRequest = new HttpPost(URL);
StringEntity se;
se = new StringEntity(jsonObjSend.toString());
// Set HTTP parameters
httpPostRequest.setEntity(se);
httpPostRequest.setHeader("Accept", "application/json");
httpPostRequest.setHeader("Content-type", "application/json");
httpPostRequest.setHeader("Accept-Encoding", "gzip"); // only set this parameter if you would like to use gzip compression
long t = System.currentTimeMillis();
HttpResponse response = (HttpResponse) httpclient.execute(httpPostRequest);
Log.i(TAG, "HTTPResponse received in [" + (System.currentTimeMillis()-t) + "ms]");
// Get hold of the response entity (-> the data):
HttpEntity entity = response.getEntity();
if (entity != null) {
// Read the content stream
InputStream instream = entity.getContent();
Header contentEncoding = response.getFirstHeader("Content-Encoding");
if (contentEncoding != null && contentEncoding.getValue().equalsIgnoreCase("gzip")) {
instream = new GZIPInputStream(instream);
}
// convert content stream to a String
String resultString= convertStreamToString(instream);
instream.close();
resultString = resultString.substring(1,resultString.length()-1); // remove wrapping "[" and "]"
// Transform the String into a JSONObject
JSONObject jsonObjRecv = new JSONObject(resultString);
// Raw DEBUG output of our received JSON object:
Log.i(TAG,"<JSONObject>\n"+jsonObjRecv.toString()+"\n</JSONObject>");
return jsonObjRecv;
}
}
catch (Exception e)
{
// More about HTTP exception handling in another tutorial.
// For now we just print the stack trace.
e.printStackTrace();
}
return null;
}
private static String convertStreamToString(InputStream is) {
/*
* To convert the InputStream to String we use the BufferedReader.readLine()
* method. We iterate until the BufferedReader return null which means
* there's no more data to read. Each line will appended to a StringBuilder
* and returned as String.
*
* (c) public domain: http://senior.ceng.metu.edu.tr/2009/praeda/2009/01/11/a-simple-restful-client-at-android/
*/
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
StringBuilder sb = new StringBuilder();
String line = null;
try {
while ((line = reader.readLine()) != null) {
sb.append(line + "\n");
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return sb.toString();
}
}
You should use an always-ok delegate to avoid server certificate validation. Of course you must use https connection. Check this link, for example: http://www.nakov.com/blog/2009/07/16/disable-certificate-validation-in-java-ssl-connections/

Why doesn't the function get data from php in android?

I want to get response after post data but it fails. I want to create a login system, I have successfully submited data to php file, everything is working fine now I want to get response from same function but I'm unable to know where the issue is.
Here is the Java function:
public class PostDataGetRes extends AsyncTask<String, String, String> {
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected String doInBackground(String... strings) {
try {
postRData();
} catch (NullPointerException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(String lenghtOfFile) {
// do stuff after posting data
}
}
public void postRData() {
String result = "";
InputStream isr = null;
final String email = editEmail.getText().toString();
final String pass = editPass.getText().toString();
// Create a new HttpClient and Post Header
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost("http://website.com/appservice.php");
try {
// Add your data
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2);
nameValuePairs.add(new BasicNameValuePair("id", email));
nameValuePairs.add(new BasicNameValuePair("stringdata", pass));
httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
// Execute HTTP Post Request
HttpResponse response = httpclient.execute(httppost);
resultView.setText("Inserted");
HttpEntity entity = response.getEntity();
isr = entity.getContent();
//convert response to string
try{
BufferedReader reader = new BufferedReader(new InputStreamReader(isr,"iso-8859-1"),8);
StringBuilder sb = new StringBuilder();
String line = null;
while ((line = reader.readLine()) != null) {
sb.append(line + "\n");
}
isr.close();
result=sb.toString();
}
catch(Exception e){
Log.e("log_tag", "Error converting result "+e.toString());
}
//parse json data
try {
String s = "";
JSONArray jArray = new JSONArray(result);
for(int i=0; i<jArray.length();i++){
JSONObject json = jArray.getJSONObject(i);
s = s +
"Name : "+json.getString("first_name")+"\n\n";
//"User ID : "+json.getInt("user_id")+"\n"+
//"Name : "+json.getString("first_name")+"\n"+
//"Email : "+json.getString("email")+"\n\n";
}
resultView.setText(s);
} catch (Exception e) {
// TODO: handle exception
Log.e("log_tag", "Error Parsing Data "+e.toString());
}
} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
} catch (IOException e) {
// TODO Auto-generated catch block
}
resultView.setText("Done");
}
And here is php code:
if($id){
$query = mysql_query("SELECT first_name FROM users where email = '$id' ");
while($row=mysql_fetch_assoc($query)){
$selectedData[]=$row;
}
print(json_encode($selectedData));
}
Please help me I have tried so far but could not achieve any results. Please help me how can I get response from php file after query execution.
At first be sure you get correct JSON object from your website - try printing it as Toast.makeText(). As far the web browsers keep the html comments away, android gets it in response.
AsyncTask objects and classes aren't designed to be made the way u provided and also you can't make any UI operations in doInBackground(). AsyncTask is made in a way to not to block GUI.
Here is a not much different example how it uses methods you have in AsyncTask class:
class Logging extends AsyncTask<String,String,Void>{
JSONObject json=null;
String output="";
String log=StringCheck.buildSpaces(login.getText().toString());
String pas=StringCheck.buildSpaces(password.getText().toString());
String url="http://www.mastah.esy.es/webservice/login.php?login="+log+"&pass="+pas;
protected void onPreExecute() {
Toast.makeText(getApplicationContext(), "Operation pending, please wait", Toast.LENGTH_SHORT).show();
}
#Override
protected Void doInBackground(String... params) {
HttpClient client = new DefaultHttpClient();
HttpGet request = new HttpGet(url);
request.addHeader("User-Agent", "User-Agent");
HttpResponse response;
try {
response = client.execute(request);
BufferedReader br = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
String line="";
StringBuilder result = new StringBuilder();
while ((line = br.readLine()) != null) {
result.append(line);
}
output=result.toString();
} catch (ClientProtocolException e) {
Toast.makeText(getApplicationContext(), "Connection problems", Toast.LENGTH_LONG).show();
} catch (IOException e) {
Toast.makeText(getApplicationContext(), "Conversion problems", Toast.LENGTH_LONG).show();
}
return null;
}
#Override
protected void onPostExecute(Void w) {
try {
json = new JSONObject(output);
if(json.getInt("err")==1){
Toast.makeText(getApplicationContext(), json.getString("msg"), Toast.LENGTH_LONG).show();
}else{
String id_user="-1";
Toast.makeText(getApplicationContext(), json.getString("msg"), Toast.LENGTH_LONG).show();
JSONArray arr = json.getJSONArray("data");
for(int i =0;i<arr.length();i++){
JSONObject o = arr.getJSONObject(i);
id_user = o.getString("id_user");
}
User.getInstance().setName(log);
User.getInstance().setId(Integer.valueOf(id_user));
Intent i = new Intent(getApplicationContext(),Discover.class);
startActivity(i);
}
} catch (JSONException e) {
}
super.onPostExecute(w);
}
}
PHP file content:
$data = array(
'err' => 0,
'msg' => "",
'data' => array(),
);
$mysqli = new MySQLi($dbhost,$dbuser,$dbpass,$dbname);
if($mysqli->connect_errno){
$data['err'] = 1;
$data['msg'] = "Brak polaczenia z baza";
exit(json_encode($data));
}
if(isset($_GET['login']) && isset($_GET['pass'])){
$mysqli->query("SET CHARACTER SET 'utf8';");
$query = $mysqli->query("SELECT banned.id_user FROM banned JOIN user ON user.id_user = banned.id_user WHERE user.login ='{$_GET['login']}' LIMIT 1;");
if($query->num_rows){
$data['err']=1;
$data['msg']="User banned";
exit(json_encode($data));
}else{
$query = $mysqli->query("SELECT login FROM user WHERE login='{$_GET['login']}' LIMIT 1;");
if($query->num_rows){
$query = $mysqli->query("SELECT pass FROM user WHERE pass ='{$_GET['pass']}' LIMIT 1;");
if($query->num_rows){
$data['msg']="Logged IN!";
$query = $mysqli->query("SELECT id_user FROM user WHERE login='{$_GET['login']}' LIMIT 1;");
$data['data'][]=$query->fetch_assoc();
exit(json_encode($data));
}else{
$data['err']=1;
$data['msg']="Wrong login credentials.";
exit(json_encode($data));
}
}else{
$data['err']=1;
$data['msg']="This login doesn't exist.";
exit(json_encode($data));
}
}
}else{
$data['err']=1;
$data['msg']="Wrong login credentials";
exit(json_encode($data));
}
I have created there small dictionary $data for my app. I used its err key as a flag to know if any error appeared, msg to inform user about operation results and data to send JSON objects.
Thing you would want to do with if(response == true) if it had exist is similar to construction i used in my onPostExecute(Void w) method in AsyncTask:
if(json.getInt("err")==1){
//something went wrong
}else{
//everything is okay, get JSON, inform user, start new Activity
}
Also here is the way I used $data['data'] to get JSON response:
if($query->num_rows){
while($res=$query->fetch_assoc()){
$data['data'][]=$res;
}
exit(json_encode($data));
}

Android - Keep user logged between activities

In my app I've a first activity that allow you to login to a web service. If the server allow user to connect it should call a TabHost activity. In TabHost activity I've 3 different activity:
HomeActivity: it display just a webview
HistoryActivity: it should display a ListView in which I insert the notification history
SettingsActivity: it display some settings of the app
In HistoryActivity I've to call to a web service to download a list of the notification history. To call this service I've to keep user logged, how I can do that?
I'm using the following code to connect to history service:
public void postData(String url) {
HttpClient httpClient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost(url);
try {
StringEntity jsonSend = new StringEntity("{\"history\": true}");
httpPost.setHeader("Content-type", "application/json; charset=UTF-8");
httpPost.setEntity(jsonSend);
HttpResponse response = httpClient.execute(httpPost);
BufferedReader reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent(), "UTF-8"));
StringBuilder builder = new StringBuilder();
for (String line = null; (line = reader.readLine()) != null;) {
builder.append(line).append("\n");
}
String json = builder.toString();
Log.d("HISTORY", json);
}
} catch (JSONException e) {
e.printStackTrace();
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
I used it for login and it works great. To connect to login service I use the following code:
public void postData(final String username, final String password) {
HttpClient httpClient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost(url);
try {
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
nameValuePairs.add(new BasicNameValuePair("username", username));
nameValuePairs.add(new BasicNameValuePair("password", password));
nameValuePairs.add(new BasicNameValuePair("pollingId", "XXXXXXXXX"));
httpPost.setHeader("Content-type", "application/x-www-form-urlencoded");
httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
HttpResponse response = httpClient.execute(httpPost);
BufferedReader reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent(), "UTF-8"));
StringBuilder builder = new StringBuilder();
for (String line = null; (line = reader.readLine()) != null;) {
builder.append(line).append("\n");
}
String json = builder.toString();
JSONObject jsonObject = new JSONObject(json);
Boolean success = jsonObject.getBoolean("success");
if (success == true) {
MainActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(MainActivity.this, "ACCESSO EFFETTUATO!", Toast.LENGTH_LONG).show();
Intent i = new Intent(MainActivity.this, TabBarActivity.class);
startActivity(i);
}
});
}
} catch (ClientProtocolException e) {
Log.d("CLIENT EXCEPTION", "ERRORE: " + e);
}catch (IOException e) {
Log.d("I/O EXCEPTION", "ERRORE: " + e);
} catch (JSONException e) {
e.printStackTrace();
}
}
If I use it to get notification history the JSON said me that user is not logged. How I can fix it? Thank you
UPDATE
I tried to follow your suggestions, but I've the same result. The modified code is the follow:
MainActivity.java
public void postData(final String username, final String password) {
HttpClient httpClient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost("https://extranet.gruppotesta.it/srv/at-brain/login.jsp");
try {
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
nameValuePairs.add(new BasicNameValuePair("username", username));
nameValuePairs.add(new BasicNameValuePair("password", password));
nameValuePairs.add(new BasicNameValuePair("pollingId", "XXXXXXX"));
httpPost.setHeader("Content-type", "application/x-www-form-urlencoded");
httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
HttpResponse response = httpClient.execute(httpPost);
BufferedReader reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent(), "UTF-8"));
StringBuilder builder = new StringBuilder();
for (String line = null; (line = reader.readLine()) != null;) {
builder.append(line).append("\n");
}
String json = builder.toString();
JSONObject jsonObject = new JSONObject(json);
Boolean success = jsonObject.getBoolean("success");
if (success == true) {
Header[] cookie = response.getHeaders("cookie");
SharedPreferences sharedPreferences = getPreferences(Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putString("cookie", cookie.toString());
editor.commit();
MainActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(MainActivity.this, "ACCESSO EFFETTUATO!", Toast.LENGTH_LONG).show();
Intent i = new Intent(MainActivity.this, TabBarActivity.class);
startActivity(i);
}
});
}
} catch (ClientProtocolException e) {
Log.d("CLIENT EXCEPTION", "ERRORE: " + e);
}catch (IOException e) {
Log.d("I/O EXCEPTION", "ERRORE: " + e);
} catch (JSONException e) {
e.printStackTrace();
}
}
}
HistoryActivity.java
public void postData(String url) {
HttpClient httpClient = new DefaultHttpClient();
SharedPreferences sharedPreferences = getPreferences(Context.MODE_PRIVATE);
String stringCookie = sharedPreferences.getString("cookie", null);
BasicCookieStore cookieStore = new BasicCookieStore();
Cookie cookie = new BasicClientCookie("login", stringCookie);
cookieStore.addCookie(cookie);
HttpContext localContext = new BasicHttpContext();
localContext.setAttribute(ClientContext.COOKIE_STORE, cookieStore);
HttpPost httpPost = new HttpPost(url);
try {
StringEntity jsonRequest = new StringEntity("{\"history\": true}");
httpPost.setEntity(jsonRequest);
httpPost.setHeader("Content-type", "application/json; charset=UTF-8");
httpPost.setHeader("Cookie", cookie.toString());
HttpResponse response = httpClient.execute(httpPost, localContext);
BufferedReader reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent(), "UTF-8"));
StringBuilder builder = new StringBuilder();
for (String line = null; (line = reader.readLine()) != null;) {
builder.append(line).append("\n");
}
String json = builder.toString();
Log.d("HISTORY", json);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
When I try to run the app the server answer me with error "User not logged". What's wrong in my code?
When you first login, the web service must provide you with some sort of access token - a valid user id perhaps. You need to store and retrieve this user id in a SharedPreference. This user id must be passed as a parameter to all subsequent web services to indicate that the user is indeed logged in.
The official tutorial for how to get and set a SharedPreference is here.
You can try to use CookieStore to store a cookie with the login credentials. Take a look at this link: Http cookie store in Android.
Does your service give back a session cookie after successful login? If so you should store the cookie that the service issues after a login (in the Set-Cookie header in the response from the server) and set this cookie for any future HTTP requests.
httpPost.setHeader("Cookie", COOKIE_FROM_SERVER_AFTER_LOGIN);
You could use a CookieStore as well to help you store the cookies from HTTP requests - this will make cookie and session management easier.
UPDATE
Server headers won't include a Cookie header but a Set-Cookie header (because the server is instructing your useragent/browser/client to set a cookie and it's this cookie that will be included in your Cookie headers) so change this line:
response.getHeaders("cookie");
to
response.getHeaders("set-cookie");
UPDATE:
Your revision is now pulling out the correct Set-Cookie header but you are incorrectly storing the value (you are storing the entire header as the cookie when all you need is the value).
if (success == true) {
Header[] cookies = response.getHeaders("set-cookie");
//at this point cookies looks like this:
//Set-Cookie: JSESSIONID=84DB43CE8CABC52EBDF777BC0EA96D0F; Path=/; Secure
//if you just do cookies.toString() like you were doing before it will also include
//the cookie header which will create an incorrect cookie value.
//you just need the value of the Set-Cookie header and store that as your cookie
if (cookies.length > 0){
//it is very possible for a server to return more than one Set-Cookie header so the proper
//way would be to iterate through all of the values and string them together
//in the correct synatax of
//so you might want to store all of the values as a list in sharedPreferences
//and let your cookie store put them all in the request for you
String finalCookie = "";
for (Header header: cookies){
//access the value from the Header object and nothing else
//JSESSIONID=90D84EF5D5BD1C4008F332F9EDA8F9AA; Path=/; Secure;
if (header.getValue().contains(";")){
finalCookie += String.format("%s; ", header.getValue().split(";")[0]);
} else {
finalCookie += String.format("%s; ", header.getValue());
}
}
//finalCookie = JSESSIONID=1B70CAB822430E14991E14ACAE153F5D;
SharedPreferences sharedPreferences = getActivity().getPreferences(Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putString("cookie", finalCookie);
editor.commit();
}
Now in your StoredPreferences you will have correctly formatted cookies (in your case you are only returning one from your server but it's likely that more than one Set-Cookie header can be included in a server response. So this implementation parses out each cookie and builds a cookie string in the correct format.
Since we are now correctly building the cookie string ourselves you can remove the CookieStore and just pull the "cookie" value out of SharedPreferences and use the string that is returned in your setHeader call:
SharedPreferences sharedPreferences = getPreferences(Context.MODE_PRIVATE);
String stringCookie = sharedPreferences.getString("cookie", "");
...
httpPost.setHeader("Cookie", cookie);
Keep in mind that although this implementation will work for you it won't take into consideration if cookies change throughout your session. Since you are the author of the web application you should be aware of whether or not cookies change - maybe when you log in it's the only time you will be given cookies to set in the browser and this solution will work for you. But a more robust solution will be to save out all of the cookies individually (instead of using editor.putString you can use editor.putStringSet to save out all of the cookie headers) then when you want to build a cookie for the respond you can .add() each individual cookie to the cookie store and then use the cookie store the same way you were before. This way each cookie by name is stored individually so that if you ever get another Set-Cookie header again for a cookie that you already have loaded in your client it will correctly overwrite that value with the updated cookie value.

Looping upload only uploads the first item

I have a for loop running in the background, and it's uploading an array to my database online. However, it only uploads the first time it goes through, and I can't figure out why.
I can follow the code as it loops through the params.add and the upload, but when I look at my database, only one extra item is added each time. My success int is also set to 0 each time but the first one.
I've looked at similar problems, and tried to fix this, but I can't find anything. I'd appreciate any help on this.
This is the relevant code ( I call it with "new SavePotholeDetails().execute();" ):
protected void onPreExecute() {
super.onPreExecute();
pDialog = new ProgressDialog(SensorActivity.this);
pDialog.setMessage("Loading pothole details. Please wait...");
pDialog.setIndeterminate(false);
pDialog.setCancelable(true);
pDialog.show();
}
/**
* Saving product
* */
protected String doInBackground(String... args) {
// TODO: Get data from sensorData
for (int i = 0; i < sensorData.size(); i++) {
// Building Parameters
List<NameValuePair> params = new ArrayList<NameValuePair>();
params.add(new BasicNameValuePair(TAG_TIME, Long.toString(sensorData.get(i).getTimestamp())));
params.add(new BasicNameValuePair(TAG_ACCEL_X, Double.toString(sensorData.get(i).getX())));
params.add(new BasicNameValuePair(TAG_ACCEL_Y, Double.toString(sensorData.get(i).getY())));
params.add(new BasicNameValuePair(TAG_ACCEL_Z, Double.toString(sensorData.get(i).getZ())));
params.add(new BasicNameValuePair(TAG_CLIENT_ID, "Epidilius")); //TODO: Make a client ID variable
params.add(new BasicNameValuePair(TAG_GPS_X, Double.toString(sensorData.get(i).getLat())));
params.add(new BasicNameValuePair(TAG_GPS_Y, Double.toString(sensorData.get(i).getLng())));
// sending modified data through http request
// Notice that update product url accepts POST method
JSONObject json = jsonParser.makeHttpRequest(
url_update_pothole, "POST", params);
// check json success tag
try {
int success = json.getInt(TAG_SUCCESS);
if (success == 1) {
// successfully updated
Intent intent = getIntent();
// send result code 100 to notify about product update
setResult(100, intent);
finish();
} else {
// failed to update product
}
} catch (JSONException e) {
e.printStackTrace();
}
}
return null;
}
protected void onPostExecute(String file_url) {
// dismiss the dialog once product updated
pDialog.dismiss();
}
EDIT:
Here is the JSONParser class:
public class JSONParser {
static InputStream is = null;
static JSONObject jObj = null;
static String json = "";
// constructor
public JSONParser() {
}
// function get json from url
// by making HTTP POST or GET mehtod
public JSONObject makeHttpRequest(String url, String method,
List<NameValuePair> params) {
// Making HTTP request
try {
// check for request method
if(method == "POST"){
// request method is POST
// defaultHttpClient
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost(url);
httpPost.setEntity(new UrlEncodedFormEntity(params));
HttpResponse httpResponse = httpClient.execute(httpPost);
HttpEntity httpEntity = httpResponse.getEntity();
is = httpEntity.getContent();
}else if(method == "GET"){
// request method is GET
DefaultHttpClient httpClient = new DefaultHttpClient();
String paramString = URLEncodedUtils.format(params, "utf-8");
url += "?" + paramString;
HttpGet httpGet = new HttpGet(url);
HttpResponse httpResponse = httpClient.execute(httpGet);
HttpEntity httpEntity = httpResponse.getEntity();
is = httpEntity.getContent();
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(
is, "UTF-8"), 8);
StringBuilder sb = new StringBuilder();
String line = null;
while ((line = reader.readLine()) != null) {
sb.append(line + "\n");
}
is.close();
json = sb.toString();
} catch (Exception e) {
Log.e("Buffer Error", "Error converting result " + e.toString());
}
// try parse the string to a JSON object
try {
jObj = new JSONObject(json);
} catch (JSONException e) {
Log.e("JSON Parser", "Error parsing data " + e.toString());
}
// return JSON String
return jObj;
}
}
If you're just running a simple loop and not blocking the loop while your AsyncTasks are executing, then they're just getting fired all at once. I also see that you're sending your web requests through the jsonParser object, but I don't know what that is. If this object is shared between AsyncRequest instances (for example, if all of this stuff is scoped within a single Activity) or if the implementation blocks so that only one request can go out at a time, then everything after the first iteration of the loop is going to fail because your HTTP client is busy.
Without posting more than your AsyncTask code, I can't help much further than that. You might want to think more about how you're executing your loop. You could do something where the loop waits for each AsyncTask instance to call back (from the onPostExecute method) to signal that it's finished. Or, you can do the looping inside of a single AsyncTask instance (probably a more lightweight solution as only a single thread is created).

Optimizing HTTP requests in android

I have noticed that my http requests tend to take alot of time compared apps communicating with same server. It makes my app feel sluggish and I was wondering if there is a better way of making these requests and updating the UI.
At the moment I use this method to make post requests
public String postRequest(List<NameValuePair> nameValuePairs, String method_name) {
String result = "";
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost("http://www.mysite.com/api/"+method_name);
httppost.setHeader("Accept", "application/json");
httppost.setHeader("Authorization", "Basic somestuff");
try {
// Add your data
httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
// Execute HTTP Post Request
HttpResponse response = httpclient.execute(httppost);
BufferedReader rd = new BufferedReader(new InputStreamReader(
response.getEntity().getContent()));
result = rd.readLine();
return result;
} catch (ClientProtocolException e) {
} catch (IOException e) {
}
return null;
}
And in my UI thread (i.e my Fragment classes) I use this in an Async Task like this
class MakeRequest extends AsyncTask<Integer, Integer, String> {
protected String doInBackground(Integer... counter) {
String result = "";
String method_name = "";
try {
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2);
nameValuePairs.add(new BasicNameValuePair("id", value));
nameValuePairs.add(new BasicNameValuePair("name", name));
method_name = "petition/setPetition";
result = fixr.postRequest(nameValuePairs, method_name);
JSONObject jsonFile = new JSONObject(result);
if(!jsonFile.has("error")){
//Parse JSON using GSON
return "success";
}else{
return jsonFile.getString("error");
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
protected void onPostExecute(String jsonResult) {
try {
if(jsonResult != null){
//update UI
}else{
//Error message
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
I'd like to optimize this so users can have a really smooth experience on my application. I'm open to using third party http libraries or is there also an argument against using AysncTasks and maybe the runOnUiThread() instead.
Volley Library is better, http, https etc.
https://developers.google.com/live/shows/474338138
very mini sample here:https://github.com/ogrebgr/android_volley_examples/blob/master/src/com/github/volley_examples/Act_SimpleRequest.java
Try Volley mate! I changed from AsyncTasks to Volley library and i am pretty pleased from the overall experience!
Volley Library

Categories

Resources