I have two non-activity class and I need to send one string from one class to another, my approach is to use shared preference but I cannot get the shared string in the second class. First class will run every time the app is opened and will generate a token
First class:
public class MyFirebaseInstanceIDService extends FirebaseInstanceIdService {
private static final String TAG = "MyFirebaseIDService";
/**
* Called if InstanceID token is updated. This may occur if the security of
* the previous token had been compromised. Note that this is called when the InstanceID token
* is initially generated so this is where you would retrieve the token.
*/
// [START refresh_token]
#Override
public void onTokenRefresh() {
// Get updated InstanceID token.
String refreshedToken = FirebaseInstanceId.getInstance().getToken();
Log.d(TAG, "Refreshed token: " + refreshedToken);
sendRegistrationToServer(refreshedToken);
}
// [END refresh_token]
/**
* Persist token to third-party servers.
*
* Modify this method to associate the user's FCM InstanceID token with any server-side account
* maintained by your application.
*
* #param token The new token.
*/
public void sendRegistrationToServer(String token) {
// TODO: Implement this method to send token to your app server.
SharedPreferences sp = getSharedPreferences("PUSHToken", Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sp.edit();
editor.putString("PUSHToken", token);
editor.commit();
}
}
I am trying to pass the string token and store in my second non-activity class for my volley request:
public class VolleyPut {
private static final String TAG = "VolleyPut";
private static VolleyPut instance = null;
public static final String KEY_TOKEN = "token";
//for Volley API
public RequestQueue requestQueue;
SharedPreferences sp2=getSharedPreferences("PUSHToken", Context.MODE_PRIVATE);
String token = sp2.getString("PUSHToken", "");
private VolleyPut(Context context)
{
this.token = token;
requestQueue = Volley.newRequestQueue(context.getApplicationContext());
return;
}
public static synchronized VolleyPut getInstance(Context context)
{
if (null == instance)
instance = new VolleyPut(context);
return instance;
}
public static synchronized VolleyPut getInstance()
{
if (null == instance)
{
throw new IllegalStateException(VolleyPut.class.getSimpleName() +
" is not initialized, call getInstance(...) first");
}
return instance;
}
public void VolleyPUT(String domain, String api, final String finalToken, final CustomListener<String> listener){
JSONArray jsonArray = new JSONArray();
JSONObject jsonObject = new JSONObject();
try{
jsonObject.put("token", token);
jsonArray.put(jsonObject);
Log.i("JsonString :", jsonObject.toString());
}catch (Exception e){
System.out.println("Error:" + e);
}
StringRequest sr = new StringRequest(Request.Method.PUT, domain + api,
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
Log.e("HttpClient", "success! response: " + response);
if(null != response)
listener.getResult(response);
return;
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
if (null != error.networkResponse)
{
Log.d(TAG + ": ", "Error Response code: " + error.networkResponse.statusCode);
//listener.getResult(false);
}
}
})
{
#Override
public Map<String,String> getHeaders() throws AuthFailureError {
HashMap<String, String> headers= new HashMap<>();
headers.put("Authorization",finalToken);
headers.put("Content-Type","application/json");
headers.put(KEY_TOKEN,token);
return headers;
}
};
requestQueue.add(sr);
}
}
However I am getting error unable to resolve method getsharedpreference in my second class. How is the way to solve this and are there anyway to pass strings between non-activity class?
The problem is that FirebaseInstanceIdService innherits from class android.content.Context so, in MyFirebaseInstanceIDService you have a Context and can use getSharedPreferences.
The solution is (to modify the minimum code) pass a context to the second class, and use it to get the shared preferences.
Better solution (my own think) is create a custom Application and use it always as a common context for all your app. Lower params and lower dependencies, because you always have the "CustomApplication" and can use it.
Here how to implement it:
https://stackoverflow.com/a/27416998/585540
Remember, if you use this approach, must put it in Manifest:
<application ....
android:name="com.you.yourapp.CustomApplication"
......>
You can create a global variable as:-
public Context context;
public VolleyPut(Context context)
{
this.token = token;
this.context=context
requestQueue = Volley.newRequestQueue(context.getApplicationContext());
return;
}
SharedPreferences sp2=**context**.getSharedPreferences("PUSHToken", Context.MODE_PRIVATE);
This will resolve error unable to resolve method getsharedpreference
Related
I am trying to implement server side using php Joomla API for my application. User sends login info and server processes and creates session successfully. However, i am unable to catch this session data in android. I am using volley to perform the post, however multiple post seems to create new logins which should not be the case as user is already logged in. I am guessing their is a problem with headers being sent by volley. Anyone with a solution for this i will appreciate.
Note server side is working 100%. Problem is only with android.
protected void doLogin(){
final String username = editTextUsername.getText().toString().trim();
final String password = editTextPassword.getText().toString().trim();
final CookieManager cookieManager = new CookieManager(new PersistentCookieStore(getApplicationContext()), CookiePolicy.ACCEPT_ORIGINAL_SERVER);
CookieHandler.setDefault(cookieManager);
RequestQueue queue = Volley.newRequestQueue(this);
String loginUrl ="http://loginurl/sesslogin/";
final StringRequest stringRequest = new StringRequest(Request.Method.POST, loginUrl,
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
//COOKIE_JAR = cookieManager.getCookieStore().getCookies().toString();
//PersistentCookieStore.getCookies();
// Toast.makeText(getApplicationContext(), response, Toast.LENGTH_LONG).show();
//stringRequest.getHeaders().values()
Toast.makeText(getApplicationContext(), response , Toast.LENGTH_LONG).show();
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(getApplicationContext(), "That didn't work!", Toast.LENGTH_LONG).show();
}
}
){
#Override
protected Map<String,String> getParams(){
Map<String,String> params = new HashMap<String, String>();
params.put(KEY_USERNAME,username);
params.put(KEY_PASSWORD,password);
return params;
}
};
queue.add(stringRequest);
}
I also got an implementation of shared preference and cookie manager that i found on Github and is part of my code. But i dont see any impact of this code.
public class PersistentCookieStore implements CookieStore {
/**
* The default preferences string.
*/
private final static String PREF_DEFAULT_STRING = "";
/**
* The preferences name.
*/
private final static String PREFS_NAME = PersistentCookieStore.class.getName();
/**
* The preferences session cookie key.
*/
private final static String PREF_SESSION_COOKIE = "Set-Cookie";
private CookieStore mStore;
private Context mContext;
/**
* #param context The application context
*/
public PersistentCookieStore(Context context) {
// prevent context leaking by getting the application context
mContext = context.getApplicationContext();
// get the default in memory store and if there is a cookie stored in shared preferences,
// we added it to the cookie store
mStore = new CookieManager().getCookieStore();
String jsonSessionCookie = getJsonSessionCookieString();
if (!jsonSessionCookie.equals(PREF_DEFAULT_STRING)) {
Gson gson = new Gson();
HttpCookie cookie = gson.fromJson(jsonSessionCookie, HttpCookie.class);
mStore.add(URI.create(cookie.getDomain()), cookie);
}
}
#Override
public void add(URI uri, HttpCookie cookie) {
if (cookie.getName().equals("sessionid")) {
// if the cookie that the cookie store attempt to add is a session cookie,
// we remove the older cookie and save the new one in shared preferences
remove(URI.create(cookie.getDomain()), cookie);
saveSessionCookie(cookie);
}
mStore.add(URI.create(cookie.getDomain()), cookie);
}
#Override
public List<HttpCookie> get(URI uri) {
return mStore.get(uri);
}
#Override
public List<HttpCookie> getCookies() {
return mStore.getCookies();
}
#Override
public List<URI> getURIs() {
return mStore.getURIs();
}
#Override
public boolean remove(URI uri, HttpCookie cookie) {
return mStore.remove(uri, cookie);
}
#Override
public boolean removeAll() {
return mStore.removeAll();
}
private String getJsonSessionCookieString() {
return getPrefs().getString(PREF_SESSION_COOKIE, PREF_DEFAULT_STRING);
}
/**
* Saves the HttpCookie to SharedPreferences as a json string.
*
* #param cookie The cookie to save in SharedPreferences.
*/
private void saveSessionCookie(HttpCookie cookie) {
Gson gson = new Gson();
String jsonSessionCookieString = gson.toJson(cookie);
SharedPreferences.Editor editor = getPrefs().edit();
editor.putString(PREF_SESSION_COOKIE, jsonSessionCookieString);
editor.apply();
}
private SharedPreferences getPrefs() {
return mContext.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
}
}
I have identified the issue. So i will answer this for anyone encountering the same problem. The problem was here;
final CookieManager cookieManager = new CookieManager(new PersistentCookieStore(getApplicationContext()), CookiePolicy.ACCEPT_ORIGINAL_SERVER);
CookieHandler.setDefault(cookieManager);
This CookieManager for some reason should be instatiated during the onCreate method. Also the type final is unnecesary here. My final code is as follows;
#Override
protected void onCreate(Bundle savedInstanceState) {
//INSTANTIATE COOKIE MANAGER
CookieManager cookieManager = new CookieManager(new PersistentCookieStore(this.getApplicationContext()), CookiePolicy.ACCEPT_ORIGINAL_SERVER);
CookieHandler.setDefault(cookieManager);
doLogin();
}
I have followed a tutorial on how to setup SNS Push notification but the CreatePlatformEndpointResult object returns null. I need that so that I can retrieve the endpointArn and send that to the backend. Below is my entire setup. And here is the link to the tutorial: http://www.allcode.com/amazon-sns-push-notification-tutorial-android-using-gcm/
First I retrieve a token from GCM by calling
AWSManager.registerAppToGCM(getApplicationContext())
This is from my AWSManager class
public class AWSManager {
private static final String TAG = AWSManager.class.getSimpleName();
private static final String SNS_ACCESS_KEY_ID = "1234567890"; // I have swapped out the real key
private static final String SNS_SECRET_KEY = "1234567890"; // I have swapped out the real key
private static AmazonSNSClient snsClient;
/**
* Method is used to retrieve SNSClient object
*
* #return snsClient object
*/
public static AmazonSNSClient getSNSClient() {
if (FrameworkUtils.checkIfNull(snsClient)) {
snsClient = new AmazonSNSClient(new BasicAWSCredentials(SNS_ACCESS_KEY_ID, SNS_SECRET_KEY));
snsClient.setRegion(Region.getRegion(Regions.US_WEST_1));
}
return snsClient;
}
/**
* Method is used to register app to GCM
*
* #param context
*/
public static void registerAppToGCM(Context context) {
SharedPref sharedPref = new SharedPref(context, Constants.PREF_FILE_NAME);
String gcmToken = sharedPref.getStringPref(Constants.NOTIFICATION_GCM_TOKEN, "");
if (FrameworkUtils.isStringEmpty(gcmToken)) {
new GCMRegisterTask(context).execute();
}
}
}
Here is the class performing the background task
public class GCMRegisterTask extends AsyncTask<String, Void, Boolean> {
private static final String TAG = GCMRegisterTask.class.getSimpleName();
private Context mContext;
/**
* Constructor
*
* #param context
*/
public GCMRegisterTask(Context context) {
super();
mContext = context;
}
#Override
protected Boolean doInBackground(String... params) {
String token;
try {
token = InstanceID.getInstance(mContext).getToken(mContext.getString(R.string.gcm_project_id), GoogleCloudMessaging.INSTANCE_ID_SCOPE);
SharedPref sharedPref = new SharedPref(mContext, Constants.PREF_FILE_NAME);
sharedPref.setPref(Constants.NOTIFICATION_GCM_TOKEN, token);
Logger.i(TAG, "GCM token successfully stored to prefs: " + token);
return true;
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
}
Once I have successfully retrieved the GCM token. I use new
AWSCreateEndpointTask(mContext).execute(test, token,
"email#gmail.com")
to begin the process of creating the endpoint ARN. test = "arn:aws:sns:region:us-east-1:app/GCM/AppName"
public class AWSCreateEndpointTask extends AsyncTask<String, Void, CreatePlatformEndpointResult> {
Context mContext;
/**
* Constructor
*
* #param context
*/
public AWSCreateEndpointTask(Context context) {
super();
mContext = context;
}
#Override
protected CreatePlatformEndpointResult doInBackground(String[] params) {
if (params.length < 3) {
return null;
}
String arn = params[0];
String gcmToken = params[1];
String userData = params[2];
try {
CreatePlatformEndpointRequest request = new CreatePlatformEndpointRequest();
request.setCustomUserData(userData);
request.setToken(gcmToken);
request.setPlatformApplicationArn(arn);
return AWSManager.getSNSClient().createPlatformEndpoint(request);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
#Override
protected void onPostExecute(CreatePlatformEndpointResult result) {
if (!FrameworkUtils.checkIfNull(result)) {
String endpointArn = result.getEndpointArn();
SharedPref sharedPref = new SharedPref(mContext, Constants.PREF_FILE_NAME);
sharedPref.setPref(Constants.NOTIFICATION_ENDPOINT_ARN, endpointArn);
}
}
Inside of onPostExecute, the returned CreatePlatformEndpointResult object is null. What am I missing or doing incorrectly to cause this?
It turns out that the implementation is correct, the arn value was wrong. For others running into this conflict, make sure the information is correct when trying to get the endpointARN. I updated mine to
arn:aws:sns:us-east-1::app/GCM/
This comes from the developer console.
There are two ways to make a Retrofit call synchronous (with methods, returning values) and asynchronous (with callbacks).
Second one, async, works great out-of-the-box. But there is an issue, when it comes to OAuth2 authenticated access.
Can you recommend me a good RestAdapter, compatible with asynchronous retrofit calls.
I tried to use interceptors as follows, but it makes network calls on the main thread, which is not sufficient to me (Android). I am trying to use the following code (not mine).
public class SecuredRestBuilder extends RestAdapter.Builder {
private class OAuthHandler implements RequestInterceptor {
private boolean loggedIn;
private Client client;
private String tokenIssuingEndpoint;
private String username;
private String password;
private String clientId;
private String clientSecret;
private String accessToken;
public OAuthHandler(Client client, String tokenIssuingEndpoint, String username,
String password, String clientId, String clientSecret) {
super();
this.client = client;
this.tokenIssuingEndpoint = tokenIssuingEndpoint;
this.username = username;
this.password = password;
this.clientId = clientId;
this.clientSecret = clientSecret;
}
/**
* Every time a method on the client interface is invoked, this method is
* going to get called. The method checks if the client has previously obtained
* an OAuth 2.0 bearer token. If not, the method obtains the bearer token by
* sending a password grant request to the server.
*
* Once this method has obtained a bearer token, all future invocations will
* automatically insert the bearer token as the "Authorization" header in
* outgoing HTTP requests.
*
*/
#Override
public void intercept(RequestFacade request) {
// If we're not logged in, login and store the authentication token.
if (!loggedIn) {
try {
// This code below programmatically builds an OAuth 2.0 password
// grant request and sends it to the server.
// Encode the username and password into the body of the request.
FormUrlEncodedTypedOutput to = new FormUrlEncodedTypedOutput();
to.addField("username", username);
to.addField("password", password);
// Add the client ID and client secret to the body of the request.
to.addField("client_id", clientId);
to.addField("client_secret", clientSecret);
// Indicate that we're using the OAuth Password Grant Flow
// by adding grant_type=password to the body
to.addField("grant_type", "password");
// The password grant requires BASIC authentication of the client.
// In order to do BASIC authentication, we need to concatenate the
// client_id and client_secret values together with a colon and then
// Base64 encode them. The final value is added to the request as
// the "Authorization" header and the value is set to "Basic "
// concatenated with the Base64 client_id:client_secret value described
// above.
String base64Auth = BaseEncoding.base64().encode(new String(clientId + ":" + clientSecret).getBytes());
// Add the basic authorization header
List<Header> headers = new ArrayList<Header>();
headers.add(new Header("Authorization", "Basic " + base64Auth));
// Create the actual password grant request using the data above
Request req = new Request("POST", tokenIssuingEndpoint, headers, to);
// Request the password grant.
Response resp = client.execute(req);
// Make sure the server responded with 200 OK
if (resp.getStatus() < 200 || resp.getStatus() > 299) {
// If not, we probably have bad credentials
throw new SecuredRestException("Login failure: "
+ resp.getStatus() + " - " + resp.getReason());
} else {
// Extract the string body from the response
String body = IOUtils.toString(resp.getBody().in());
// Extract the access_token (bearer token) from the response so that we
// can add it to future requests.
accessToken = new Gson().fromJson(body, JsonObject.class).get("access_token").getAsString();
// Add the access_token to this request as the "Authorization"
// header.
request.addHeader("Authorization", "Bearer " + accessToken);
// Let future calls know we've already fetched the access token
loggedIn = true;
}
} catch (Exception e) {
throw new SecuredRestException(e);
}
}
else {
// Add the access_token that we previously obtained to this request as
// the "Authorization" header.
request.addHeader("Authorization", "Bearer " + accessToken );
}
}
private String username;
private String password;
private String loginUrl;
private String clientId;
private String clientSecret = "";
private Client client;
#Override
public RestAdapter build() {
if (username == null || password == null) {
throw new SecuredRestException(
"You must specify both a username and password for a "
+ "SecuredRestBuilder before calling the build() method.");
}
if (client == null) {
client = new OkClient();
}
OAuthHandler hdlr = new OAuthHandler(client, loginUrl, username, password, clientId, clientSecret);
setRequestInterceptor(hdlr);
return super.build();
}
// setters and getters here
}
So, I ended up splitting RestAdapter class into two separate classes. The first one gets token. Another one is a RestAdapter class that takes the token as input.
Class for getting token:
public class GetTokenRequest {
public static final String TAG = GetTokenRequest.class.getCanonicalName();
public static final String CLIENT_ID = AccessPoint.CLIENT_ID;
public static final String CLIENT_SECRET = AccessPoint.CLIENT_SECRET;
public static final String ENDPOINT = AccessPoint.ENDPOINT;
public static final String TOKEN_PATH = AccessPoint.TOKEN_PATH;
public interface Listener {
void onGetTokenSucess(String token);
void onGetTokenUnauthorized();
void onGetTokenFailure();
}
public static void getAccessToken(Client client, String username, String password,
final Listener callback) {
try {
// This code below programmatically builds an OAuth 2.0 password
// grant request and sends it to the server.
// Encode the username and password into the body of the request.
FormUrlEncodedTypedOutput to = new FormUrlEncodedTypedOutput();
to.addField("username", username);
to.addField("password", password);
// Add the client ID and client secret to the body of the request.
to.addField("client_id", CLIENT_ID);
to.addField("client_secret", CLIENT_SECRET);
// Indicate that we're using the OAuth Password Grant Flow
// by adding grant_type=password to the body
to.addField("grant_type", "password");
// The password grant requires BASIC authentication of the client.
// In order to do BASIC authentication, we need to concatenate the
// client_id and client_secret values together with a colon and then
// Base64 encode them. The final value is added to the request as
// the "Authorization" header and the value is set to "Basic "
// concatenated with the Base64 client_id:client_secret value described
// above.
String base64Auth = BaseEncoding.base64()
.encode(new String(CLIENT_ID + ":" + CLIENT_SECRET).getBytes());
// Add the basic authorization header
List<Header> headers = new ArrayList<Header>();
headers.add(new Header("Authorization", "Basic " + base64Auth));
// Create the actual password grant request using the data above
Request req = new Request("POST", ENDPOINT + TOKEN_PATH, headers, to);
// Request the password grant.
Response resp = client.execute(req);
if (resp == null) {
Log.e(TAG, "resp is null");
callback.onGetTokenFailure();
return;
}
int status = resp.getStatus();
// Make sure the server responded with 200 OK
if (status >= 200 && status < 300) {
Log.e(TAG, "getToken response code is okay");
// Extract the string body from the response
final String body = IOUtils.toString(resp.getBody().in());
// Extract the access_token (bearer token) from the response so that we
// can add it to future requests.
if (callback instanceof LoginActivity)
((LoginActivity) callback).runOnUiThread(new Runnable() {
#Override
public void run() {
callback.onGetTokenSucess(new Gson().fromJson(body, JsonObject.class)
.get("access_token").getAsString());
}
});
} else if (status == HttpStatus.SC_UNAUTHORIZED
|| status == HttpStatus.SC_BAD_REQUEST) {
Log.e(TAG, "getToken response code is 401");
// Incorrect credentials
if (callback instanceof LoginActivity)
((LoginActivity) callback).runOnUiThread(new Runnable() {
#Override
public void run() {
callback.onGetTokenUnauthorized();
}
});
} else {
// Other error
Log.e(TAG, "getToken response code - other");
if (callback instanceof LoginActivity)
((LoginActivity) callback).runOnUiThread(new Runnable() {
#Override
public void run() {
((LoginActivity) callback).onGetTokenFailure();
}
});
}
} catch (Exception e) {
Log.e(TAG, "Exception caught");
Log.e(TAG, e.toString());
if (callback instanceof LoginActivity)
((LoginActivity) callback).runOnUiThread(new Runnable() {
#Override
public void run() {
callback.onGetTokenFailure();
}
});
}
}
}
RestAdapter class:
public class SecuredRestAdapter extends RestAdapter.Builder {
private class OAuthHandler implements RequestInterceptor {
private boolean loggedIn;
private Client client;
private String tokenIssuingEndpoint;
private String username;
private String password;
private String clientId;
private String clientSecret;
private String accessToken;
public OAuthHandler(Client client, String accessToken) {
super();
this.client = client;
this.accessToken = accessToken;
}
#Override
public void intercept(RequestFacade request) {
// Add the access_token that we previously obtained to this request as
// the "Authorization" header.
request.addHeader("Authorization", "Bearer " + accessToken);
}
}
private String loginUrl;
private Client client;
private String token;
public SecuredRestAdapter setLoginEndpoint(String endpoint){
loginUrl = endpoint;
return this;
}
#Override
public SecuredRestAdapter setEndpoint(String endpoint) {
return (SecuredRestAdapter) super.setEndpoint(endpoint);
}
#Override
public SecuredRestAdapter setEndpoint(Endpoint endpoint) {
return (SecuredRestAdapter) super.setEndpoint(endpoint);
}
#Override
public SecuredRestAdapter setClient(Client client) {
this.client = client;
return (SecuredRestAdapter) super.setClient(client);
}
#Override
public SecuredRestAdapter setClient(Provider clientProvider) {
client = clientProvider.get();
return (SecuredRestAdapter) super.setClient(clientProvider);
}
#Override
public SecuredRestAdapter setErrorHandler(ErrorHandler errorHandler) {
return (SecuredRestAdapter) super.setErrorHandler(errorHandler);
}
#Override
public SecuredRestAdapter setExecutors(Executor httpExecutor,
Executor callbackExecutor) {
return (SecuredRestAdapter) super.setExecutors(httpExecutor,
callbackExecutor);
}
#Override
public SecuredRestAdapter setRequestInterceptor(
RequestInterceptor requestInterceptor) {
return (SecuredRestAdapter) super
.setRequestInterceptor(requestInterceptor);
}
#Override
public SecuredRestAdapter setConverter(Converter converter) {
return (SecuredRestAdapter) super.setConverter(converter);
}
#Override
public SecuredRestAdapter setProfiler(#SuppressWarnings("rawtypes") Profiler profiler) {
return (SecuredRestAdapter) super.setProfiler(profiler);
}
#Override
public SecuredRestAdapter setLog(Log log) {
return (SecuredRestAdapter) super.setLog(log);
}
#Override
public SecuredRestAdapter setLogLevel(LogLevel logLevel) {
return (SecuredRestAdapter) super.setLogLevel(logLevel);
}
public SecuredRestAdapter setToken(String token) {
this.token = token;
return this;
}
#Override
public RestAdapter build() {
if (this.token == null || this.token.equals(""))
throw new SecuredRestAdapterException(
"Token must be provided, when calling SecuredRestAdapter");
if (client == null) {
client = new OkClient();
}
OAuthHandler hdlr = new OAuthHandler(client, token);
setRequestInterceptor(hdlr);
return super.build();
}
}
Exception class:
public class SecuredRestAdapterException extends RuntimeException {
public SecuredRestAdapterException(String message) {
super(message);
}
}
I can't seem to figure out how to get android annotations rest client to work I'm having 2 main issues.
A)How to parse the generic json response and get the meaningful key
B)How to add parameters
For the first problem all responses come back as a json string fomatted like this
{"success":,"message":"","data":{}}
Where success is boolean message is a string and data is going to be the main data I want to parse that may be a boolean, an array, a string or an int
I'm pretty sure I need to intercept the response and handle the code but I'm not sure how to do that
Lets use a real response that look something like this
{"success":true,"message":"random message","data":{"profile":{"id":"44","user_id":"44","name":"Matt","username":"mitch","icon":"b1da7ae15027b7d6421c158d644f3220.png","med":"2a3df53fb39d1d8b5edbd0b93688fe4a.png","map":"b7bfed1f456ca4bc8ca748ba34ceeb47.png","background":null,"mobile_background":null}}
First in my interceptor I want to see if the boolean key "success" is true and then return the data value
#EBean
public class RestInterceptor implements ClientHttpRequestInterceptor {
final String TAG = "rest";
#Bean
AuthStore authStore;
#Override
public ClientHttpResponse intercept(HttpRequest request, byte[] data, ClientHttpRequestExecution execution)
throws IOException{
//Need to set the api key here but nothing happens code quits
// Log.d("Rest",authStore.getApiKey());
HttpHeaders headers = request.getHeaders();
headers.set("api_key","");
ClientHttpResponse resp = execution.execute(request, data);
HttpStatus code = resp.getStatusCode();
if(code.value() == 200){
Log.d(TAG,"success code 200");
//valid http request but is it a valid API request?
//perform some logic of if success == true in root json object
//if true cast return data key
}
else{
Log.d(TAG,"fail code" + code.toString());
}
return resp;
}
}
The second problem is sending params with the http request that have an api key and a session key, I define the application class like this
#EApplication
public class MyApp extends Application {
final String TAG = "app";
#Bean
AuthStore authStore;
#RestService
RestClient restClient;
public void onCreate() {
super.onCreate();
init();
}
#AfterInject
public void init() {
authStore.setApiKey("dummy_key");
Log.d(TAG, "api key set to " + authStore.getApiKey());
}
}
With the AuthStore class like this
#EBean(scope = Scope.Singleton)
public class AuthStore {
public String apiKey,sessionKey;
public String getApiKey() {
return apiKey;
}
public void setApiKey(String apiKey) {
this.apiKey = apiKey;
}
public String getSessionKey() {
return sessionKey;
}
public void setSessionKey(String sessionKey) {
this.sessionKey = sessionKey;
}
}
Basically I'm setting a dummy api key at the application level in a singleton, which I should be able to access in the rest interceptor interface but the code just quits without errors I'm basically following this guide https://github.com/excilys/androidannotations/wiki/Authenticated-Rest-Client
Finally I have an activity class which injects the app dependency which has refrence to the rest http class and the authstore class
#EActivity(R.layout.activity_login)
public class LoginActivity extends Activity {
#App
MyApp app;
#ViewById
TextView email;
#ViewById
TextView password;
#ViewById
Button loginButton;
#AfterInject
public void init() {
Log.d(app.TAG, "api in login key set to " + app.authStore.getApiKey());
}
#Click
#Trace
void loginButton() {
login(email.toString(), password.toString());
}
#Background
void login(String email, String password) {
app.restClient.forceLogin();
}
}
Sorry if it's a lot of info, I've been searching for a while and can't figure this out!
thanks in advance
I'm not known with the library you're using (annotations, spring) but it seems to me that you are struggling with parsing the success = true because that is not supposed to be in the JSON.
The JSON should preferably represent a class in your app 1on1 so you can easily map that into an object.
Communication between your app and the webservice, regarding the status of requests should go into the headers.
Like this you can check a request's headers, before parsing the JSON.
This is mathod I am using to parse any JSON object recursively.
private void parseJson(JSONObject data) {
if (data != null) {
Iterator<String> it = data.keys();
while (it.hasNext()) {
String key = it.next();
try {
if (data.get(key) instanceof JSONArray) {
JSONArray arry = data.getJSONArray(key);
int size = arry.length();
for (int i = 0; i < size; i++) {
parseJson(arry.getJSONObject(i));
}
} else if (data.get(key) instanceof JSONObject) {
parseJson(data.getJSONObject(key));
} else {
System.out.println("" + key + " : " + data.optString(key));
}
} catch (Throwable e) {
System.out.println("" + key + " : " + data.optString(key));
e.printStackTrace();
}
}
}
}
I am trying to make social network application for Android. My question is how to maintain user session when user logs in?
Please help me to find the solution for the above question.
try
public class Session {
private static String sessionId;
private static String userRole;
public static void setSessionId(String sessionId) {
Session.sessionId = sessionId;
}
public static String getSessionId() {
return sessionId;
}
}
Use this class and import it in every other activity. You can define your own functions to maintain your specific session data
http://www.devahead.com/blog/2011/06/extending-the-android-application-class-and-dealing-with-singleton/
Please look at the above link. It is detailed pretty well.
Use a singleton to maintain the user session.
I use DefaultHttpClient with HttpRequestInterceptor and HttpResponseInterceptor.
Something similar to this:
public class HTTPClients {
private static DefaultHttpClient _defaultClient;
private static String session_id;
private static HTTPClients _me;
private HTTPClients() {
}
public static DefaultHttpClient getDefaultHttpClient(){
if ( _defaultClient == null ) {
_defaultClient = new DefaultHttpClient();
_me = new HTTPClients();
_defaultClient.addResponseInterceptor(_me.new SessionKeeper());
_defaultClient.addRequestInterceptor(_me.new SessionAdder());
}
return _defaultClient;
}
private class SessionAdder implements HttpRequestInterceptor {
#Override
public void process(HttpRequest request, HttpContext context)
throws HttpException, IOException {
Log.d("SessionKeeper", "Adding session with the following string: " + session_id);
if ( session_id != null ) {
request.setHeader("Cookie", session_id);
}
}
}
private class SessionKeeper implements HttpResponseInterceptor {
#Override
public void process(HttpResponse response, HttpContext context)
throws HttpException, IOException {
Header[] headers = response.getHeaders("Set-Cookie");
if ( headers != null && headers.length == 1 ){
Log.d("SessionKeeper", "Keeping session with the following string: " + headers[0].getValue());
session_id = headers[0].getValue();
}
}
}
}
I have the similar problem on my android client side when I am trying to send that session id ,the server side is creating a new session...but what you check at android client side that you are not creating the DefaulthttpClient twice... create the httpclient just once say main activity and pass the objects in other activity ...... dont create second HttpClient
Create session using SharedPreferences.
public class Session {
private SharedPreferences prefs;
public Session(Context cntx) {
// TODO Auto-generated constructor stub
prefs = PreferenceManager.getDefaultSharedPreferences(cntx);
}
public void setusename(String usename) {
prefs.edit().putString("usename", usename).commit();
}
public String getusename() {
String usename = prefs.getString("usename","");
return usename;
}
}
now after making this class when u want to use this use like this make object og this class like
private Session session;//global variable
session = new Session(cntx); //in oncreate
//and now we set sharedpreference then use this like
session.setusename("USERNAME");
now when ever u want to get username then same work for session object and call this
session.getusename();
best of luck :) same for password