我对这个问题很感兴趣。 在我的应用程序中,我使用 SharedPrefManager 作为单例类,以便保留一些" session"信息。在这个简单的示例应用程序中,我只保存用户的名称和一个布尔值,该布尔值指示用户是否已登录以在已登录时跳过登录屏幕,或者如果没有则显示。 启动应用程序时,在启动画面之后, LoginActivity 将启动。 此时,如果用户之前已经登录(稍后没有注销,这意味着的布尔值 SharedPreferences变量是 true ),则用户被重定向到 MainActivity ,否则他会看到登录表单,他可以在其中插入用户名和密码,并向远程服务器发出REST API请求。 如果登录正确,则 MainActivity 将启动,并仅显示用户的名称,该名称取自远程登录REST API调用获取的响应JSON。 现在,这是我的问题:我想实现一个简单的注销功能,删除(或更改,如在此测试应用程序中)SharedPreferences存储的所有信息,并将用户带回LoginActivity。 但是当我单击logout时,SharedPreferences的值仅在MainActivity中更新,而在LoginActivity中它们保持与以前相同,因此当用户重定向到LoginActivity时, isusedadded 共享首选项仍然是 true ,用户被重定向回MainActivity。 但SharedPrefManager类是一个单例,因此它的值应该在应用程序的每个部分都相同,因为它只存在一个实例,为什么我有这种行为呢?
您可以通过下载完整的应用代码here并使用这些凭据进行登录来测试应用:
用户名: 52346
密码: 32fjueM1(区分大小写)
以下是我的代码。
App.java:
package mypackage.sharedprefapp;
import android.app.Application;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.toolbox.Volley;
public class App extends Application
{
private RequestQueue mRequestQueue;
private static App mInstance;
@Override
public void onCreate()
{
super.onCreate();
mInstance = this;
}
public static synchronized App getInstance()
{
return mInstance;
}
// This method returns the queue containing GET/POST requests
public RequestQueue getRequestQueue()
{
if(mRequestQueue == null)
{
mRequestQueue = Volley.newRequestQueue(getApplicationContext());
}
return mRequestQueue;
}
// This method adds a GET/POST request to the queue of requests
public <T> void addToRequestQueue(Request<T> req)
{
getRequestQueue().add(req);
}
}
SplashActivity.java
package mypackage.sharedprefapp;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
public class SplashActivity extends AppCompatActivity
{
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Intent intent = new Intent(this, LoginActivity.class);
startActivity(intent);
finish();
}
}
LoginActivity.java
package mypackage.sharedprefapp;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TextView;
public class LoginActivity extends AppCompatActivity
{
private static final String TAG = "LoginActivity";
Button loginButton;
EditText userIDInput, passwordInput;
TextView loginErrorMsg, title;
LinearLayout bgLayout;
SharedPrefManager sharedPrefManager;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
sharedPrefManager = SharedPrefManager.getInstance(this);
Log.i("HERE", "LoginActivity onCreate: "+sharedPrefManager.isUserAdded());
}
@Override
protected void onResume()
{
super.onResume();
sharedPrefManager = SharedPrefManager.getInstance(this);
Log.i("HERE", "LoginActivity onResume: "+sharedPrefManager.getUserName());
// if the user is already logged in
if(sharedPrefManager.isUserAdded())
{
Log.i(TAG, "User is logged in");
// if the device is connected to the internet
if(Utils.isDeviceOnline(this))
{
Intent intent = new Intent(this, MainActivity.class);
startActivity(intent);
finish();
}
// if the device is offline
else
{
Log.i(TAG, "Internet connection is not available");
}
}
// if the user is not logged in
else
{
Log.i(TAG, "User is NOT logged in");
setContentView(R.layout.activity_login);
title = (TextView) findViewById(R.id.title);
loginErrorMsg = (TextView) findViewById(R.id.login_errorText);
userIDInput = (EditText) findViewById(R.id.login_id_paziente);
passwordInput = (EditText) findViewById(R.id.login_password);
loginButton = (Button) findViewById(R.id.login_submitButton);
bgLayout = (LinearLayout) findViewById(R.id.login_parentLayout);
// Bind a custom click listener to the login button
loginButton.setOnClickListener(new LoginButtonClickListener(this));
// Bind a custom click listener to the background layout
// so that the soft keyboard is dismissed when clicking on the background
bgLayout.setOnClickListener(new LoginBackgroundClickListener());
}
}
}
LoginButtonClickListener.java
package mypackage.sharedprefapp;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;
import com.android.volley.AuthFailureError;
import com.android.volley.Request;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.StringRequest;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.HashMap;
import java.util.Map;
public class LoginButtonClickListener implements View.OnClickListener
{
private Context context;
private SharedPrefManager sharedPrefManager;
public LoginButtonClickListener(Context c)
{
this.context = c;
}
@Override
public void onClick(View v)
{
sharedPrefManager = SharedPrefManager.getInstance(context);
// if internet connection is available
if(Utils.isDeviceOnline(context))
{
// Verify login credentials from DB
doLogin();
}
else {}
}
// check login data with REST API
private void doLogin()
{
final String paziente_id = ((EditText)((Activity)context).findViewById(R.id.login_id_paziente)).getText().toString();
final String paziente_password = ((EditText)((Activity)context).findViewById(R.id.login_password)).getText().toString();
StringRequest stringRequest = new StringRequest
(
Request.Method.POST,
"http://www.stefanopace.net/iCAREServer/api/v1/index.php/login",
new Response.Listener<String>()
{
@Override
public void onResponse(String s)
{
try
{
JSONObject obj = new JSONObject(s);
if(!obj.getBoolean("error"))
{
String name = obj.getString("nome");
sharedPrefManager.addUser(name);
Intent intent = new Intent(context, MainActivity.class);
context.startActivity(intent);
}
else
{
Toast.makeText(context, "Error on JSON response", Toast.LENGTH_LONG).show();
}
}
catch(JSONException e)
{
e.printStackTrace();
}
}
},
new Response.ErrorListener()
{
@Override
public void onErrorResponse(VolleyError volleyError)
{
Toast.makeText(context, volleyError.getMessage(), Toast.LENGTH_LONG).show();
}
})
{
@Override
protected Map<String, String> getParams() throws AuthFailureError
{
Map<String, String> params = new HashMap<>();
params.put("id_paziente", paziente_id);
params.put("password", paziente_password);
return params;
}
};
App.getInstance().addToRequestQueue(stringRequest);
}
}
LoginBackgroundClickListener.java
package mypackage.sharedprefapp;
import android.view.View;
public class LoginBackgroundClickListener implements View.OnClickListener
{
@Override
public void onClick(View v)
{
Utils.hideSoftKeyboard(v);
}
}
MainActivity.java
package mypackage.sharedprefapp;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity
{
private static final String TAG = "MainActivity";
TextView personName;
SharedPrefManager sharedPrefManager;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
sharedPrefManager = SharedPrefManager.getInstance(this);
setContentView(R.layout.activity_main);
personName = (TextView) findViewById(R.id.person_name);
Log.i(TAG, "Value: "+sharedPrefManager.isUserAdded());
personName.setText(sharedPrefManager.getUserName());
}
@Override
protected void onResume()
{
super.onResume();
sharedPrefManager = SharedPrefManager.getInstance(this);
Log.w("MainActivity", "onResume");
}
@Override
public boolean onCreateOptionsMenu(Menu menu)
{
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.mainmenu, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item)
{
switch(item.getItemId())
{
// Logout button has been pressed
case R.id.logout_action:
{
Log.i("Logout pressed", "Logout button has been pressed!");
final AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);
alertDialogBuilder.setMessage("Are you sure you want to logout?");
alertDialogBuilder.setPositiveButton
(
"Yes",
new DialogInterface.OnClickListener()
{
@Override
public void onClick(DialogInterface arg0, int arg1)
{
boolean success = sharedPrefManager.removeDataFromSharedPreference();
// if the operation is OK
if(success)
{
// go to the login activity
Intent intent = new Intent(MainActivity.this, LoginActivity.class);
startActivity(intent);
finish();
}
else
{
Toast.makeText(getApplicationContext(), "Error during logout", Toast.LENGTH_LONG).show();
}
}
}
);
alertDialogBuilder.setNegativeButton
(
"No",
new DialogInterface.OnClickListener()
{
@Override
public void onClick(DialogInterface arg0, int arg1)
{}
}
);
AlertDialog alertDialog = alertDialogBuilder.create();
alertDialog.show();
return true;
}
}
return super.onOptionsItemSelected(item);
}
}
SharedPrefManager.java
package mypackage.sharedprefapp;
import android.content.Context;
import android.content.SharedPreferences;
public final class SharedPrefManager
{
private static final String TAG = "SharedPrefManager";
private SharedPreferences sharedPreferences;
private SharedPreferences.Editor editor;
private static SharedPrefManager mInstance;
private static final String SHARED_PREF = "sharedprefs";
private static final String KEY_IS_USER_ADDED = "isuseradded";
public static final String KEY_USER_NAME = "username";
private SharedPrefManager(Context context)
{
sharedPreferences = context.getSharedPreferences(SHARED_PREF, Context.MODE_PRIVATE);
editor = sharedPreferences.edit();
sharedPreferences.registerOnSharedPreferenceChangeListener(new LocalSharedPreferencesChangeListener());
}
public static SharedPrefManager getInstance(Context context)
{
if(mInstance == null)
{
mInstance = new SharedPrefManager(context);
}
return mInstance;
}
// add an user to the shared preferences
public boolean addUser(String name)
{
editor.putString(KEY_USER_NAME, name);
editor.putBoolean(KEY_IS_USER_ADDED, true);
return editor.commit();
}
public boolean removeDataFromSharedPreference()
{
editor.putString(KEY_USER_NAME, "HELLO");
editor.putBoolean(KEY_IS_USER_ADDED, false);
return editor.commit();
}
public String getUserName()
{
return sharedPreferences.getString(KEY_USER_NAME, "");
}
public boolean isUserAdded()
{
return sharedPreferences.getBoolean(KEY_IS_USER_ADDED, false);
}
}
Utils.java
package mypackage.sharedprefapp;
import android.app.Activity;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.support.v7.app.AlertDialog;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
public class Utils
{
public static void hideSoftKeyboard(View view)
{
InputMethodManager inputMethodManager = (InputMethodManager) view.getContext().getSystemService(Activity.INPUT_METHOD_SERVICE);
inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), 0);
}
// This method checks if the device is connected to the Internet
public static boolean isDeviceOnline(final Context context)
{
final ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
if(connectivityManager != null)
{
final NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
boolean isOnline = (networkInfo != null && networkInfo.isConnectedOrConnecting());
if(!isOnline)
{
AlertDialog.Builder alertDialog = new AlertDialog.Builder(context);
alertDialog.setCancelable(false);
alertDialog.setTitle("Error");
alertDialog.setMessage("Internet is not available");
alertDialog.setPositiveButton("Try again", new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dialog, int which)
{
// Reload the Activity
Intent intent = ((Activity) context).getIntent();
((Activity) context).finish();
context.startActivity(intent);
}
});
alertDialog.show();
}
return isOnline;
}
return false;
}
}
LocalSharedPreferencesChangeListener
package mypackage.sharedprefapp;
import android.content.SharedPreferences;
import android.util.Log;
public class LocalSharedPreferencesChangeListener implements SharedPreferences.OnSharedPreferenceChangeListener
{
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key)
{
Log.i("HERE", key);
}
}
activity_login.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin"
tools:context=".LoginActivity"
android:padding="0dp">
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/scrollView"
android:layout_gravity="center_horizontal">
<LinearLayout
android:id="@+id/login_parentLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:clickable="true">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/ic_launcher"
android:layout_gravity="center_horizontal"
android:layout_marginTop="50dp"
android:layout_marginBottom="30dp" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/app_name"
android:layout_gravity="center_horizontal"
android:gravity="center_horizontal"
android:layout_marginBottom="30dp"
android:singleLine="false"
android:padding="5dp"
android:textSize="30sp" />
<EditText
android:id="@+id/login_id_paziente"
android:layout_width="match_parent"
android:layout_height="40dp"
android:inputType="number"
android:ems="10"
android:hint="Username"
android:textColor="@android:color/black"
android:textColorHint="@android:color/darker_gray"
android:singleLine="true"
android:minLines="1"
android:gravity="center_horizontal"
android:layout_marginLeft="50dp"
android:layout_marginRight="50dp"
android:focusableInTouchMode="true"
android:focusable="true" />
<EditText
android:id="@+id/login_password"
android:layout_width="match_parent"
android:layout_height="40dp"
android:hint="Password"
android:textColorHint="@android:color/darker_gray"
android:inputType="textPassword"
android:ems="10"
android:textColor="@android:color/black"
android:maxLines="1"
android:singleLine="true"
android:layout_marginTop="20dp"
android:gravity="center_horizontal"
android:layout_marginLeft="50dp"
android:layout_marginRight="50dp"
android:focusableInTouchMode="true"
android:focusable="true" />
<TextView
android:id="@+id/login_errorText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Login error"
android:textColor="@android:color/holo_red_dark"
android:layout_gravity="center_horizontal"
android:gravity="center_horizontal"
android:singleLine="false"
android:padding="5dp"
android:textSize="20sp"
android:layout_margin="10dp"
android:visibility="invisible" />
<Button
android:id="@+id/login_submitButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Login"
android:textSize="20sp"
android:layout_marginLeft="50dp"
android:layout_marginRight="50dp" />
</LinearLayout>
</ScrollView>
</LinearLayout>
activity_main.xml中
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="mypackage.sharedprefapp.MainActivity">
<TextView
android:id="@+id/person_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
android:textSize="25sp"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true" />
</RelativeLayout>
splashscreen.xml (在可绘制资源文件夹中)
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@android:color/holo_green_dark"/>
<item>
<bitmap
android:gravity="center"
android:src="@mipmap/ic_launcher"/>
</item>
</layer-list>
mainmenu.xml (在res /菜单资源文件夹中)
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item android:id="@+id/logout_action"
android:title="Logout"
app:showAsAction="always" />
</menu>
styles.xml
<resources>
...
<style name="SplashTheme" parent="Theme.AppCompat.NoActionBar">
<item name="android:windowBackground">@drawable/splashscreen</item>
</style>
</resources>
的AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="mypackage.sharedprefapp">
<!-- Needs internet to connect to Google Services -->
<uses-permission android:name="android.permission.INTERNET" />
<!-- Permission to check internet connection state -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application
android:name=".App"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity
android:name=".SplashActivity"
android:label="@string/app_name"
android:screenOrientation="portrait"
android:theme="@style/AppTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:screenOrientation="portrait"
android:theme="@style/AppTheme" />
<activity
android:name=".LoginActivity"
android:label="@string/app_name"
android:process=":other_process"
android:screenOrientation="portrait"
android:theme="@style/AppTheme">
<intent-filter>
<action android:name="android.intent.action.LOGIN_ACTION" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
</application>
</manifest>
build.gradle (模块:应用)
dependencies {
...
compile 'com.android.volley:volley:1.0.0'
}
谢谢!
答案 0 :(得分:1)
只需致电 editor.clear(); 和 editor.commit(); 足以从共享首选项中删除所有数据。
答案 1 :(得分:0)
由于onResume
,您继续实例化新的SharedPrefManager
sharedPrefManager = new SharedPrefManager(this);
修改SharedPrefManager
,使其始终只提供一个实例,或者在返回LoginActivity时确保引用同一个对象。
答案 2 :(得分:0)
SharedPreferences是永久存储,您可以清除
SharedPreferences.Editor.clear().commit();
替代解决方案 您希望一旦应用关闭清除整个值,请尝试Application singleton class
答案 3 :(得分:0)
@Ciammarica你可以点击Logout按钮调用这段代码,希望这可以帮到你..你可以在logout按钮中设置布尔值false ..
SessionManager.setUserLoggedIn(YourActivity.this,false); SessionManager.clearAppCredential(YourActivity.this);
答案 4 :(得分:0)
我更改了我的代码,以便只有一个SharedPrefManager类实例。 这是我的 App 单例类:
public class App extends Application
{
private static App mInstance;
private SharedPrefManager sharedPrefManager;
@Override
public void onCreate() {
super.onCreate();
mInstance = this;
sharedPrefManager = new SharedPrefManager(this);
}
public SharedPrefManager getSharedPrefManager(){
return sharedPrefManager;
}
public static synchronized App getInstance(){
return mInstance;
}
}
然后从其他类中我通过调用
获取实例SharedPrefManager sharedPrefManager = App.getInstance().getSharedPrefManager();
现在,通过此更改, onSharedPreferenceChanged()事件仅触发一次,因此这比以前更好,但“延迟”行为仍然存在...我的意思是,即使我用editor.clear();和editor.commit();方法,值已更新,但只有在我再次关闭并打开应用程序时才会看到它们。
答案 5 :(得分:0)
我自己发现了这个问题......它不喜欢从 new DialogInterface.OnClickListener() sharedPrefManager.removeDataFromSharedPreference(); 方法>
我把它放在代码的另一部分中并且有效。