0

I want to store session key and other info in sharedpreference and retrieve it when calling another api. I am referencing this answer - https://stackoverflow.com/a/16743595/10243953 . I made a separate class MyApp and calling its method for storing and retrieving info. It is my first project with session so i dont know much but i tried this code.

Login Function

public void LoginAPI(){
    progressDialog.show();
    StringRequest stringRequest = new StringRequest(Request.Method.POST, LOGIN_URL, new Response.Listener<String>() {
        @Override
        public void onResponse(String response) {

      // My Operations with response

    }, new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError error) {
            progressDialog.dismiss();
            Snackbar.make(v,"LOGIN FAILED",Snackbar.LENGTH_SHORT).show();
        }
    }){
        @Override
        protected Map<String, String> getParams() {
            Map<String, String> params = new HashMap<>();
            // the POST parameters:
            params.put("identity", username);
            params.put("pass",password);
            return params;
        }


      //Storing Session Data
        @Override
        protected Response<String> parseNetworkResponse(NetworkResponse response) {
            MyApp.get().checkSessionCookie(response.headers);
            return super.parseNetworkResponse(response);
        }

    };
    RequestQueue queue = Volley.newRequestQueue(this);
    queue.add(stringRequest);
}

Retrieving data to add session data

public void GetStudentData(){
    progressBar.setVisibility(View.VISIBLE);
    String parent_id = SharedPreferenceManager.getmInstance(getContext()).getID();
    StringRequest stringRequest = new StringRequest(Request.Method.GET, GET_STUDENT_URL+parent_id, new Response.Listener<String>() {
        @Override
        public void onResponse(String response) {
            progressBar.setVisibility(View.GONE);
        }
    }, new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError error) {

        }
    }){
        @Override
        protected Response<String> parseNetworkResponse(NetworkResponse response) {

            return super.parseNetworkResponse(response);
        }

        @Override
        public Map<String, String> getHeaders() throws AuthFailureError {
            Map<String,String> headers = super.getHeaders();
            if (headers == null || headers.equals(Collections.<String, String>emptyMap())){
                headers = new HashMap<String, String>();
            }
            MyApp.get().addSessionCookie(headers);
            return headers;
        }
    };
    RequestQueue queue = Volley.newRequestQueue(getContext());
    queue.add(stringRequest);
}

MyApp

public class MyApp extends Application {
private static final String SET_COOKIE_KEY = "Set-Cookie";
private static final String COOKIE_KEY = "Cookie";
private static final String SESSION_COOKIE = "sessionid";

private static MyApp _instance;
private RequestQueue _requestQueue;
private SharedPreferences _preferences;

public static MyApp get() {
    return _instance;
}

@Override
public void onCreate() {
    super.onCreate();
    _instance = this;
    _preferences = PreferenceManager.getDefaultSharedPreferences(this);
    _requestQueue = Volley.newRequestQueue(this);
}

public RequestQueue getRequestQueue() {
    return _requestQueue;
}


/**
 * Checks the response headers for session cookie and saves it
 * if it finds it.
 * @param headers Response Headers.
 */
public final void checkSessionCookie(Map<String, String> headers) {
    if (headers.containsKey(SET_COOKIE_KEY)
            && headers.get(SET_COOKIE_KEY).startsWith(SESSION_COOKIE)) {
        String cookie = headers.get(SET_COOKIE_KEY);
        if (cookie.length() > 0) {
            String[] splitCookie = cookie.split(";");
            String[] splitSessionId = splitCookie[0].split("=");
            cookie = splitSessionId[1];
            SharedPreferences.Editor prefEditor = _preferences.edit();
            prefEditor.putString(SESSION_COOKIE, cookie);
            prefEditor.commit();
        }
    }
}

/**
 * Adds session cookie to headers if exists.
 * @param headers
 */
public final void addSessionCookie(Map<String, String> headers) {
    String sessionId = _preferences.getString(SESSION_COOKIE, "");
    if (sessionId.length() > 0) {
        StringBuilder builder = new StringBuilder();
        builder.append(SESSION_COOKIE);
        builder.append("=");
        builder.append(sessionId);
        if (headers.containsKey(COOKIE_KEY)) {
            builder.append("; ");
            builder.append(headers.get(COOKIE_KEY));
        }
        headers.put(COOKIE_KEY, builder.toString());
    }
}
}

Menifest

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.acg.digimkeyparent">
<!-- To auto-complete the email text field in the login form with the user's emails -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.READ_PROFILE" />
<uses-permission android:name="android.permission.READ_CONTACTS" />

<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:supportsRtl="true"
    android:theme="@style/AppTheme"
    android:usesCleartextTraffic="true">
    <activity
        android:name=".Slide"
        android:theme="@style/Theme.AppCompat.NoActionBar" />
    <activity
        android:name=".Login"
        android:theme="@style/Theme.AppCompat.Light.NoActionBar" />
    <activity
        android:name=".ForgotPassword"
        android:theme="@style/Theme.AppCompat.Light.NoActionBar" />
    <activity android:name=".ResetPassword" />
    <activity android:name=".EditNumber" />
    <activity android:name=".OTP" />
    <activity android:name=".ProfileChild" />
    <activity
        android:name=".SplashScreen"
        android:theme="@style/Theme.AppCompat.NoActionBar">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>

    <service
        android:name=".GSMRegistrationIntentService"
        android:exported="false">
        <intent-filter>
            <action android:name="com.google.android.gms.iid.InstanceID" />
        </intent-filter>
    </service>

    <activity
        android:name=".MainActivity"
        android:label="@string/title_activity_main" />
    <activity android:name=".ChangePassword" />
    <activity android:name=".ChangeMobile" />
    <activity android:name=".StudentDashboard" />
</application>
</manifest>

Error - in Login function

E/Volley: [462] NetworkDispatcher.processRequest: Unhandled exception java.lang.NullPointerException: Attempt to invoke virtual method 'void com.example.acg.digimkeyparent.MyApp.checkSessionCookie(java.util.Map)' on a null object reference
      java.lang.NullPointerException: Attempt to invoke virtual method 'void com.example.acg.digimkeyparent.MyApp.checkSessionCookie(java.util.Map)' on a null object reference
          at com.example.acg.digimkeyparent.Login$5.parseNetworkResponse(Login.java:186)
          at com.android.volley.NetworkDispatcher.processRequest(NetworkDispatcher.java:132)
          at com.android.volley.NetworkDispatcher.run(NetworkDispatcher.java:87)
Ajay Gohel
  • 243
  • 7
  • 17

2 Answers2

0

Add this line android:name=".MyApp" to your application tag in AndroidManifest.xml file

<application
    android:name=".MyApp"
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:supportsRtl="true"
    android:theme="@style/AppTheme"
    android:usesCleartextTraffic="true">

And give it a try!

Son Truong
  • 13,661
  • 5
  • 32
  • 58
0

I'd remove that MyApp.get(), which returns NULL and call it statically, for example:

public static boolean checkSessionCookie(Map<String, String> headers) {
    if (headers.containsKey(SET_COOKIE_KEY) && headers.get(SET_COOKIE_KEY).startsWith(SESSION_COOKIE)) {
        String cookie = headers.get(SET_COOKIE_KEY);
        if (cookie.length() > 0) {

            String[] splitCookie = cookie.split(";");
            String[] splitSessionId = splitCookie[0].split("=");
            cookie = splitSessionId[1];

            SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
            SharedPreferences.Editor prefEditor = preferences.edit();
            prefEditor.putString(SESSION_COOKIE, cookie);
            prefEditor.commit();

            return true;
        }
    }
    return false;
}

usable alike boolean hasCookie = MyApp.checkSessionCookie(response.headers);

... when referencing MyApp in the Mainfest.xml it should also return the instance, but having static Context fields is prone to Context leaks; better to be avoided whenever just possible. you'd just have to get a handle to the Preferences from within that static method; most likely getApplicationContext() would suffice to get the handle.

Martin Zeitler
  • 1
  • 19
  • 155
  • 216