I’m trying to save Facebook AccessToken in SheredPreference, and log in later using that token, but the application crashes when I do that.
package com.fit.android;
import java.sql.Date;
import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import com.facebook.AccessToken;
import com.facebook.AccessTokenSource;
import com.facebook.Request;
import com.facebook.Response;
import com.facebook.Session;
import com.facebook.SessionState;
import com.facebook.model.GraphUser;
public class LoginActivity extends Activity implements OnClickListener {
Button login;
Button logout;
Button loginToken;
SharedPreferences sp;
AccessToken token;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login_activity);
login = (Button) findViewById(R.id.login);
logout = (Button) findViewById(R.id.logout);
login.setOnClickListener(this);
logout.setOnClickListener(this);
loginToken = (Button) findViewById(R.id.token);
loginToken.setOnClickListener(this);
sp = getPreferences(MODE_PRIVATE);
String access_token = sp.getString("access_token", null);
String expires = sp.getString("access_expires", null);
if (access_token != null && expires != null) {
token.createFromExistingAccessToken(access_token, Date.valueOf(expires), null,
AccessTokenSource.TEST_USER, null);
}
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
Session.getActiveSession().onActivityResult(this, requestCode, resultCode, data);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.login:
if (token != null) {
Session.openActiveSessionWithAccessToken(this, token, new Session.StatusCallback() {
@Override
public void call(final Session session, SessionState state, Exception exception) {
if (session.isOpened()) {
Request.executeMeRequestAsync(session, new Request.GraphUserCallback() {
@Override
public void onCompleted(GraphUser user, Response response) {
if (user != null) {
TextView welcome = (TextView) findViewById(R.id.textView1);
welcome.setText("Hello " + user.getName());
}
}
});
}
}
});
} else {
Session.openActiveSession(this, true, new Session.StatusCallback() {
@Override
public void call(final Session session, SessionState state, Exception exception) {
if (session.isOpened()) {
Request.executeMeRequestAsync(session, new Request.GraphUserCallback() {
@Override
public void onCompleted(GraphUser user, Response response) {
if (user != null) {
TextView welcome = (TextView) findViewById(R.id.textView1);
welcome.setText("Hello " + user.getName());
Editor editor = sp.edit();
editor.putString("access_token", session.getAccessToken());
editor.putString("access_expires", session.getExpirationDate().toString());
editor.commit();
}
}
});
}
}
});
}
break;
case R.id.logout:
Session.getActiveSession().closeAndClearTokenInformation();
break;
}
}
}
Logcat:
12-29 19:16:32.316: E/AndroidRuntime(1118): FATAL EXCEPTION: main
12-29 19:16:32.316: E/AndroidRuntime(1118): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.fit.android/com.fit.android.Login_activity}: java.lang.IllegalArgumentException
12-29 19:16:32.316: E/AndroidRuntime(1118): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2180)
12-29 19:16:32.316: E/AndroidRuntime(1118): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2230)
12-29 19:16:32.316: E/AndroidRuntime(1118): at android.app.ActivityThread.access$600(ActivityThread.java:141)
12-29 19:16:32.316: E/AndroidRuntime(1118): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1234)
12-29 19:16:32.316: E/AndroidRuntime(1118): at android.os.Handler.dispatchMessage(Handler.java:99)
12-29 19:16:32.316: E/AndroidRuntime(1118): at android.os.Looper.loop(Looper.java:137)
12-29 19:16:32.316: E/AndroidRuntime(1118): at android.app.ActivityThread.main(ActivityThread.java:5039)
12-29 19:16:32.316: E/AndroidRuntime(1118): at java.lang.reflect.Method.invokeNative(Native Method)
12-29 19:16:32.316: E/AndroidRuntime(1118): at java.lang.reflect.Method.invoke(Method.java:511)
12-29 19:16:32.316: E/AndroidRuntime(1118): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
12-29 19:16:32.316: E/AndroidRuntime(1118): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)
12-29 19:16:32.316: E/AndroidRuntime(1118): at dalvik.system.NativeStart.main(Native Method)
12-29 19:16:32.316: E/AndroidRuntime(1118): Caused by: java.lang.IllegalArgumentException
12-29 19:16:32.316: E/AndroidRuntime(1118): at java.sql.Date.valueOf(Date.java:226)
12-29 19:16:32.316: E/AndroidRuntime(1118): at com.fit.android.Login_activity.onCreate(Login_activity.java:53)
12-29 19:16:32.316: E/AndroidRuntime(1118): at android.app.Activity.performCreate(Activity.java:5104)
12-29 19:16:32.316: E/AndroidRuntime(1118): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1080)
12-29 19:16:32.316: E/AndroidRuntime(1118): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2144)
12-29 19:16:32.316: E/AndroidRuntime(1118): ... 11 more
Here is the solution:
1- Parse Date in this way:
2- Init AccessToken:
Update 2023: There is a way to delete some questions and answers without value, even if there are some votes, but I am not going to do that. Let’s keep it as a reference for what you should not do.
In general, it’s a very bad idea to store sensitive information in Android Shared Preferences. I don’t know what my use case was at that time, but I am sure it was not necessary because the SDK should provide all necessary functions without the need to store tokens manually. Still, if we need to store sensitive information on Android, we should use KeyChain.