最近在处理一个公司的老项目的时候偶然发现一个BUG,项目请求网络数据之后通过SharedPreferences保存在本地,作为数据缓存,清除的时候直接将生成的xml件删除。流程没错,但是这样做是有问题的,抽点时间写了一个小Demo,在此做个记录,权当笔记了。

先说结论:

1、getSharedPreference() 不会生成文件,这个大家都知道;

2、删除掉文件后,再次执行commit(),删除的文件会重生,重生文件的数据和删除之前的数据相同;

3、删除掉文件后,程序在没有完全退出停止运行的情况下,Preferences对象所存储的内容是不变的,虽然文件没有了,但数据依然存在;程序完全退出停止之后,数据才会丢失;

4、清除SharedPreferences数据一定要执行editor.clear(),editor.commit(),不能只是简单的删除文件,这也就是最后的结论,需要注意的地方。


好了,下面开始用一个非常简单的小Demo验证上面的结论。


1、首先是MainActivity ,只有一个Button,点击跳转,没什么东西,模拟首页,xml文件就不贴了。

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        findViewById(R.id.next_btn).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                startActivity(new Intent(MainActivity.this, SharedActivity.class));
            }
        });
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        this.finish();
    }
}



2、来看SharedActivity 和对应的xml文件

public class SharedActivity extends AppCompatActivity implements View.OnClickListener{

    EditText name,age,sex;
    Button save,delete;
    SharedPreferences preferences;
    SharedPreferences.Editor editor;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_shared);
        name = (EditText) findViewById(R.id.name);
        age = (EditText) findViewById(R.id.age);
        sex = (EditText) findViewById(R.id.sex);
        save = (Button) findViewById(R.id.save);
        delete = (Button) findViewById(R.id.delete);
        preferences = getSharedPreferences("TestCache", MODE_PRIVATE);
        editor = preferences.edit();
        save.setOnClickListener(this);
        delete.setOnClickListener(this);
        initData();
    }

    public void initData(){
        name.setText(preferences.getString("name",""));
        age.setText(preferences.getString("age",""));
        sex.setText(preferences.getString("sex",""));
    }

    /**
     * 保存SharedPreferences数据
     */
    public void saveCache(){
        editor.putString("name",name.getText().toString());
        editor.putString("age",age.getText().toString());
        editor.putString("sex",sex.getText().toString());
        if(editor.commit()){
            Toast.makeText(this,"保存成功!", Toast.LENGTH_SHORT).show();
        }
    }

    /**
     * 删除SharedPreferences数据文件
     * @param files
     */
    public void deleteCache(File[] files){

        boolean flag;
        for(File itemFile : files){
            flag = itemFile.delete();
            if (flag == false) {
                deleteCache(itemFile.listFiles());
            }
        }
        Toast.makeText(this, "清除缓存成功", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onClick(View view) {
        switch (view.getId()){
            case R.id.save:
                saveCache();
                break;
            case R.id.delete:
                File[] files = new File("/data/data/"+this.getPackageName()+"/shared_prefs").listFiles();
                deleteCache(files);
                break;
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        this.finish();
    }



<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <EditText
        android:id="@+id/name"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="姓名"/>
    <EditText
        android:id="@+id/age"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="年龄"/>
    <EditText
        android:id="@+id/sex"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="性别"/>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:layout_marginTop="20dp">

        <Button
            android:id="@+id/save"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:layout_margin="10dp"
            android:text="保存"/>

        <Button
            android:id="@+id/delete"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:layout_margin="10dp"
            android:text="删除"/>

    </LinearLayout>

</LinearLayout>

布局很简单,三个输入框,两个按钮,保存代表存储数据到SharedPreferences中,删除代表删除所生成的xml文件。


Activity中的代码也很简单,都有注释,不说了,下面开始跑程序。先来验证结论 1 和 3。

1结论好验证,直接运行起来点击跳转按钮之后,到 /data/data/packageName/shared_prefs 文件夹下看一下有没有文件就行了,结果当然是没有。

3结论也好验证,程序启动之后我们将姓名、年龄、性别等要保存的信息填上之后保存,此时在 /data/data/packageName/shared_prefs  文件夹下会生成TestCache.xml文件,打开查看就是我们所保存的信息,以键值对的形式保存。然后我们再点击删除按钮,删除生成的xml文件,此时TestCache.xml文件被删除,我们点击返回键,返回到MainActivity,之后再重新跳转到SharedActivity中,我们看到我们之前保存的信息还依然存在(此时TestCache.xml文件是不存在的),反复几次都是一样;之后我们退出程序,回到手机桌面,然后在重新打开程序,发现所保存的信息还是存在,重复几次结果还是一样,最后我们在应用程序中将程序强行停止,然后重新打开程序,之前保存的信息没有了,到此,我们的3结论就验证完成。

根据上面说的,我贴几张过程图(真机演示连不上了,用的模拟器,有点卡,也没法看到文件,有兴趣的可以自己试试,需要ROOT):

SharedPreferences清空内容 删除sharedpreferences_SharedPreferences

  

SharedPreferences清空内容 删除sharedpreferences_SharedPreferences_02

   

SharedPreferences清空内容 删除sharedpreferences_缓存_03

上面第一张图就是验证流程,第二张为点击保存按钮后生成的文件,第三张为文件的内容,点删除时,文件被删除,也就是第二张图中的文件被删除,图就不贴了。


接下来验证 2 结论

我们在SharedActivity中的onDestroy()方法中加上两行代码:

@Override
    protected void onDestroy() {
        super.onDestroy();
        //删除缓存数据的xml文件之后再次执行commit(),删除的文件会重生。
        editor.putString("address","济南");
        editor.commit();
        this.finish();
    }

然后重新运行程序,当我们点击删除之后(这是文件目录下是没有TestCache.xml文件的),按返回键返回到MainActivity后,我们在看一下结果:

SharedPreferences清空内容 删除sharedpreferences_缓存_04

   

SharedPreferences清空内容 删除sharedpreferences_存储_05

没法用真机录制完整的动图,有兴趣的可以下载下来代码自己在手机上验证一下。

最后要说的就是结论4了,当我们要清除SharedPreferences中的数据的时候一定要先clear()、再commit(),不能直接删除xml文件,一定要注意!!!

//清空数据
        editor.clear();
        editor.commit();

好了,啰啰嗦嗦一大堆,最终只要记住结论4就可以了。

不说了,渴。

代码传送门