Android SharedPreferences 全面解析

RudolphRees 8年前
   <p>SharedPreference是以key-value键值对的形式存储数据,它只能存储简单的基本数据类型:boolean, float, int, long, String. 它的文件是在data/data/package-name/shared-prefs/目录下。</p>    <h2><strong>获取SharedPreferences对象</strong></h2>    <p>可以使用以下两种方法之一:</p>    <ul>     <li> <p>getSharedPreferences(String name, int mode)</p> </li>     <li> <p>getPreferences(int mode)</p> </li>    </ul>    <p>其实 getPreferences() 内部也是调用了 getSharedPreferences() ,看下源码:</p>    <pre>  <code class="language-java">public SharedPreferences getPreferences(int mode) {      return getSharedPreferences(getLocalClassName(), mode);  }</code></pre>    <pre>  <code class="language-java">/**   * Returns class name for this activity with the package prefix removed.   * This is the default name used to read and write settings.   *   * @return The local class name.   */  @NonNull  public String getLocalClassName() {      final String pkg = getPackageName();      final String cls = mComponent.getClassName();      int packageLen = pkg.length();      if (!cls.startsWith(pkg) || cls.length() <= packageLen              || cls.charAt(packageLen) != '.') {          return cls;      }      return cls.substring(packageLen+1);  }</code></pre>    <p>getPreferences() 是Activity的方法,不需要传入 name 参数,它返回的是以 getLocalClassName() 返回值命名的SharedPreferences对象,而 getLocalClassName() 方法返回的是去掉package-name的当前Activity类名。所以在不同的Activity中调用 getPreferences() 返回的是不同的SharedPreferences对象。</p>    <p>例如:</p>    <pre>  <code class="language-java">package com.lc.learndemo.sharedpreference;    ...  import com.lc.learndemo.R;    public class SharedPrefsActivity extends Activity implements View.OnClickListener{        private SharedPreferences sPrefs;        @Override      protected void onCreate(Bundle savedInstanceState) {          super.onCreate(savedInstanceState);          setContentView(R.layout.activity_shared_prefs);            sPrefs = getPreferences(MODE_PRIVATE);//此时并没有创建文件          sPrefs.edit().putString("name","小明").commit();//第一次写数据的时候才会创建文件      }  }</code></pre>    <p>启动这个Activity后,会在data/data/package-name/shared-prefs/目录下创建一个名为 sharedpreference.SharedPrefsActivity 的xml文件。</p>    <h2><strong>SharedPreferences的读写</strong></h2>    <p>SharedPreferences本身只支持读数据:</p>    <pre>  <code class="language-java">SharedPreferences sPrefs = getSharedPreferences("config_sprefs", MODE_PRIVATE);  String name = sPrefs.getString("name","该值不存在")</code></pre>    <p>而存储或修改数据则需要通过 SharedPreferences.Editor 对象。例如:</p>    <pre>  <code class="language-java">@Override  protected void onCreate(Bundle savedInstanceState) {      super.onCreate(savedInstanceState);      setContentView(R.layout.activity_shared_prefs);        SharedPreferences sPrefs = getSharedPreferences("config_sprefs", MODE_PRIVATE);      SharedPreferences.Editor editor = sPrefs.edit(); //获取Editor对象      editor.putString("name","小明"); //存储数据      editor.commit(); //提交修改  }</code></pre>    <h2><strong>SharedPreferences的标志位</strong></h2>    <h3><strong>文件创建标志位:</strong></h3>    <ul>     <li>Context.MODE_PRIVATE 这是默认标志位,表示创建的文件只能被当前应用访问。</li>     <li>Context.MODE_WORLD_READABLE 允许其它应用程序读该文件。</li>     <li>Context.MODE_WORLD_WRITEABLE 允许其它应用程序写该文件。</li>    </ul>    <h3><strong>文件加载标志位:</strong></h3>    <ul>     <li>Context.MODE_MULTI_PROCESS 这是文件加载标志位,表示即使你的SharedPreferences文件已经加载到进程,系统还是会去检查文件是否更改。这个是在API level 11加入的,解决的问题是:当加载SharedPreference文件的时候,系统会在内存中留有一份缓存,所以当SharedPreference文件的内容发生改变时,其他应用程序读取的还是缓存的数据,不能读到最新的数据,当设置这个标志位问题就解决了。这个标志主要用在跨进程访问中。</li>    </ul>    <h2><strong>跨进程访问SharedPreferences</strong></h2>    <h3><strong>同一个应用中的跨进程访问</strong></h3>    <p>首先创建应用App1,创建 A Activity,在A中创建SharedPreferences</p>    <pre>  <code class="language-java">public class A extends Activity implements View.OnClickListener {        private SharedPreferences sPrefs;      private SharedPreferences.Editor editor;        @Override      protected void onCreate(Bundle savedInstanceState) {          super.onCreate(savedInstanceState);          setContentView(R.layout.activity_shared_prefs);            sPrefs = getSharedPreferences("config_sprefs",MODE_WORLD_READABLE);          editor = sPrefs.edit();          editor.putString("name","小明");          editor.commit();          init();      }        private void init () {          Button editButton = (Button) findViewById(R.id.btn_edit);          editButton.setOnClickListener(this);      }        @Override      public void onClick(View v) {          switch (v.getId()) {              case R.id.btn_edit:                   editor.putString("name","张三").commit();          }      }  }</code></pre>    <p>在应用App1中再创建 B Activity,在AndroidManifest.xml中给B Activity 指定在另一个独立的进程中运行:</p>    <pre>  <code class="language-java"><activity android:name=".B"            android:process=":Remote" /></code></pre>    <p>在B中跨进程访问App1所在的进程的SharedPreference文件:</p>    <pre>  <code class="language-java">public class B extends Activity implements View.OnClickListener{        private TextView tvAcrossProcess;      private Button btnAcrossProcess;        @Override      protected void onCreate(Bundle savedInstanceState) {          super.onCreate(savedInstanceState);          setContentView(R.layout.activity_androidprocess);          initViews();      }        private void initViews () {          tvAcrossProcess = (TextView) findViewById(R.id.tv_across_process);          btnAcrossProcess = (Button) findViewById(R.id.btn_across_process);          btnAcrossProcess.setOnClickListener(this);      }          @Override      public void onClick(View v) {          switch (v.getId()) {              case R.id.btn_across_process:                  /*在同一个应用中得进程可以直接获取SharedPreferences对象,加载模式设置为MODE_MULTI_PROCESS才可以对到修改后的数据*/                  SharedPreferences sp = getSharedPreferences("config_sprefs", MODE_MULTI_PROCESS);                  tvAcrossProcess.setText(sp.getString("name","该值不存在"));          }      }  }</code></pre>    <p>B中有一个Button和一个TextView,点击Button跨进程访问SharedPreferences,获取的内容显示到TextView中。</p>    <h3><strong>不同应用程序之间的跨进程访问</strong></h3>    <p>我们再创建一个App2,在App2中创建 C Activity,点击Button访问App1中得SharedPreferences,结果显示在TextView中:</p>    <pre>  <code class="language-java">public class C extends Activity implements View.OnClickListener{        private TextView tvAcrossProcess;      private Button btnAcrossProcess;      private Context context;        @Override      protected void onCreate(Bundle savedInstanceState) {          super.onCreate(savedInstanceState);          setContentView(R.layout.activity_main);          initViews();      }        private void initViews () {          tvAcrossProcess = (TextView) findViewById(R.id.tv_across_process);          btnAcrossProcess = (Button) findViewById(R.id.btn_across_process);          btnAcrossProcess.setOnClickListener(this);      }          @Override      public void onClick(View v) {          switch (v.getId()) {              case R.id.btn_across_process:                  try {                      context = createPackageContext("com.lc.learndemo",CONTEXT_IGNORE_SECURITY);                  } catch (PackageManager.NameNotFoundException e) {                      e.printStackTrace();                  }                    SharedPreferences sp = context.getSharedPreferences("config_sprefs", MODE_MULTI_PROCESS);                  String content = sp.getString("name","该值不存在");                  tvAcrossProcess.setText(content);          }      }  }</code></pre>    <p>createPackageContext(String packageName, int flags) 创建其它程序的Context,第一个参数是应用的包名,第二个参数是标志位,它有两个值,CONTEXT_INCLUDE_CODE的意思是包括代码,也就是说可以执行这个包里面的代码。CONTEXT_IGNORE_SECURITY的意思 是忽略安全警告,如果不加这个标志的话,有些功能是用不了的,会出现安全警告。</p>    <p>但是谷歌官方文档不建议使用SharedPreferences来进行跨进程通信,会有安全性问题,可以用ContentProvider, BroadcastReceiver, 或Service来代替.</p>    <h2><strong>SharedPreferences.OnSharedPreferenceChangeListener</strong></h2>    <p>这个接口用来监听SharedPreferences内容变化的,其内部有两个方法:</p>    <pre>  <code class="language-java">//注册监听  registerOnSharedPreferenceChangeListener(SharedPreferences.OnSharedPreferenceChangeListener listener)</code></pre>    <pre>  <code class="language-java">//解除注册  unregisterOnSharedPreferenceChangeListener(SharedPreferences.OnSharedPreferenceChangeListener listener)</code></pre>    <p>注意:当调用 getXxx() 方法获取SharedPreference对象是,这个文件并没有创建,只有当第一次调用 putXxx() 方法想文件中写值得时候才会在data/data/package-name/shared-prefs/目录下创建该文件。</p>    <p> </p>    <p>来自:http://www.jianshu.com/p/ad26833a73de</p>    <p> </p>