在重新启动应用之前,Android SharedPreferences不会被删除

时间:2016-09-26 11:25:24

标签: android login sharedpreferences logout

我对这个问题很感兴趣。 在我的应用程序中,我使用 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'
}

谢谢!

6 个答案:

答案 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(); 方法>

我把它放在代码的另一部分中并且有效。