学习andriod开发之 文件存储(一)

        大家好 我是akira 又和大家见面了 今天依旧来学习andriod系列的开发教程 

我们知道 很多应用都是要靠联网拿到数据的 如果没有联网 那么你的应用就是一个空壳大笑

然而我们在现实中却发现不然 有些应用即使在离线状态下也依然有数据 而不是空壳 这是为什么呢 

答案就是它们都很好的做了缓存 也就是说在加载数据的时候 已经将缓存的那部分数据保存在了我们的手机上 从而下一次即使没有网

依然能看到数据 而不是空壳 那么这个是怎么做的呢 要想做这样的东西 我们就先了解下andriod中的存储技术 


   andriod存储 这个顾名思义 那么有几种方式呢 这个很多人想必都知道 在我们andriod系统中有五种常见的存储方式 我们就来看个究竟

文件存储数据 

SQLite数据库存储数据 

使用ContentProvider存储数据

使用网络存储数据

以及使用SharedPreferences存储

没错 就是这五种 为什么我要把sharedPreference放到最后呢 因为接下来我们要着重说明下这个


我们来看下关于文件存储是怎么玩的 

我们保持过很多的数据 最常见的莫非是用户名和密码了 我们也来一个

首先看下ui效果 


没错 就是这样简单的登陆效果 我就仿一下索尼的psn登陆

页面xml代码

<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"
    tools:context=".MainActivity" 
    android:background="@drawable/bg"
    >

    <TextView
       android:id="@+id/psntitle"
       style="@style/psnstyle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:text="@string/loginpsn" />
    
    <LinearLayout 
        android:layout_marginTop="30dp"
        android:id="@+id/llname"
        android:layout_below="@id/psntitle"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        >
      <TextView
          style="@style/psnstyle1"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:text="@string/psnname" />
        
        <EditText 
            android:hint="@string/typepsnname"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="2"
            />
     </LinearLayout>
     
    <LinearLayout 
        android:id="@+id/llpass"
        android:layout_marginTop="30dp"
        android:layout_below="@id/llname"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        >
      <TextView
          style="@style/psnstyle1"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:text="@string/psnpassword" />
        
        <EditText 
            android:hint="@string/typepsnpassword"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="2"
            />
     </LinearLayout>
	
    <LinearLayout 
        android:layout_below="@id/llpass"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        >
        <CheckBox 
            style="@style/psnstyle1"
            android:textSize="16sp"
            android:id="@+id/cb"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/remebername"
           	android:layout_marginRight="30dp"
            />
        <Button 
            android:id="@+id/bt"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/login"
            />
        
    </LinearLayout>
</RelativeLayout>

这里 我们没有其他新的知识点 有一个style 因为我们发现有很多相似的东西 可以提取出来 而这些相似的东西称之为样式 我们来完成一个自定义的样式

这个代码在values/styel中 

代码如下

<style name="psnstyle" parent="android:Widget.TextView">
        <item name="android:textSize">30sp</item>
        <item name="android:textColor">#ffffff</item>
    </style>
    <style name="psnstyle1" parent="android:Widget.TextView">
        <item name="android:textSize">20sp</item>
        <item name="android:textColor">#ffffff</item>
    </style>

你可以清楚的看到 要想实现自定义的样式 其实很简单 style的开头和结尾让我们想起了html (吐槽:明明就是xml)

它里面有个item 而item所要填写的只有name 和你想要达到的 一切如你所看 

主UI完成之后 我们要完成逻辑代码

文件存储 顾名思义就是要将数据存储到文件中 

看下具体代码

public class MainActivity extends Activity implements OnClickListener {

	private EditText et_name;
	private EditText et_pass;
	private CheckBox cb;
	private Button bt;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		findview();
		setlistener();
	}

	private void setlistener() {
		bt.setOnClickListener(this);
		
	}

	private void findview() {
		et_name = (EditText) findViewById(R.id.et_name);
		et_pass = (EditText) findViewById(R.id.et_pass);
		cb = (CheckBox) findViewById(R.id.cb);
		bt = (Button) findViewById(R.id.bt);
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.activity_main, menu);
		return true;
	}

	@Override
	public void onClick(View v) {
			String name = et_name.getText().toString();
			String pass = et_pass.getText().toString();
		if(v.getId()==R.id.bt)
			//这里登陆
			if(cb.isChecked())
				//进行存储
				saveToFile(name,pass);
				
			login(name,pass);
	}
	/**
	 * 进行文件存储
	 * @param name
	 * @param pass
	 */
	private void saveToFile(String name, String pass) {
			File f = new File("data/data/akira"+"/psnuser.txt");
			if(!f.exists())
				try {
					f.createNewFile();
					FileWriter fw = new FileWriter(f);
					fw.write(name+"||"+pass);
					fw.close();
					showToast(this, "保存成功");
				} catch (IOException e) {
					e.printStackTrace();
				}
	}

	private void login(String name, String pass) {
		// 执行登陆
		
	}
	private static void showToast(Context ct,String content){
		Toast.makeText(ct, content, Toast.LENGTH_LONG).show();
		
	}

}

以上的核心代码只有saveToFile 这么一个方法 

步骤只是new了一个file 利用 FileWriter来写 

然而 更多的时候 我们要利用手机上的sd卡来进行操作 于是乎 代码进行修改

@Override
	public void onClick(View v) {
			String name = et_name.getText().toString();
			String pass = et_pass.getText().toString();
		if(v.getId()==R.id.bt)
			//这里登陆
			if(cb.isChecked())
				//进行存储
				if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
					File dir = Environment.getExternalStorageDirectory();
					saveToSD(dir,name,pass);
				}else{
					//挂载sd卡
					
				saveToFile(name,pass);
				}
			login(name,pass);
	}
	/**
	 * 存储到sd卡
	 * @param dir
	 * @param name
	 * @param pass
	 */
	private void saveToSD(File dir, String name, String pass) {

		File f = new File(dir+"/psnuser.txt");
		if(!f.exists())
			try {
				f.createNewFile();
				FileWriter fw = new FileWriter(f);
				fw.write(name+"||"+pass);
				fw.close();
				showToast(this, "保存成功");
			} catch (IOException e) {
				e.printStackTrace();
			}

		
	}

这里 我们的方法和前面无异 无非是多加了一个判断 

这里会引用一个类 Envirment 这个类是判断sd卡常用的类 

而我们的文件名不是什么data/data 变成了dir

这样 文件到sd卡就完成了 

        下面我们来说下 首选项

首选项 其实你理解它是一个map就可以了 我们可以看下首选项的源码

public interface Editor {
        /**
         * Set a String value in the preferences editor, to be written back once
         * {@link #commit} or {@link #apply} are called.
         * 
         * @param key The name of the preference to modify.
         * @param value The new value for the preference.
         * 
         * @return Returns a reference to the same Editor object, so you can
         * chain put calls together.
         */
        Editor putString(String key, String value);
        
        /**
         * Set a set of String values in the preferences editor, to be written
         * back once {@link #commit} is called.
         * 
         * @param key The name of the preference to modify.
         * @param values The new values for the preference.
         * @return Returns a reference to the same Editor object, so you can
         * chain put calls together.
         */
        Editor putStringSet(String key, Set<String> values);
        
        /**
         * Set an int value in the preferences editor, to be written back once
         * {@link #commit} or {@link #apply} are called.
         * 
         * @param key The name of the preference to modify.
         * @param value The new value for the preference.
         * 
         * @return Returns a reference to the same Editor object, so you can
         * chain put calls together.
         */
        Editor putInt(String key, int value);
        
        /**
         * Set a long value in the preferences editor, to be written back once
         * {@link #commit} or {@link #apply} are called.
         * 
         * @param key The name of the preference to modify.
         * @param value The new value for the preference.
         * 
         * @return Returns a reference to the same Editor object, so you can
         * chain put calls together.
         */
        Editor putLong(String key, long value);
        
        /**
         * Set a float value in the preferences editor, to be written back once
         * {@link #commit} or {@link #apply} are called.
         * 
         * @param key The name of the preference to modify.
         * @param value The new value for the preference.
         * 
         * @return Returns a reference to the same Editor object, so you can
         * chain put calls together.
         */
        Editor putFloat(String key, float value);
        
        /**
         * Set a boolean value in the preferences editor, to be written back
         * once {@link #commit} or {@link #apply} are called.
         * 
         * @param key The name of the preference to modify.
         * @param value The new value for the preference.
         * 
         * @return Returns a reference to the same Editor object, so you can
         * chain put calls together.
         */
        Editor putBoolean(String key, boolean value);

        /**
         * Mark in the editor that a preference value should be removed, which
         * will be done in the actual preferences once {@link #commit} is
         * called.
         * 
         * <p>Note that when committing back to the preferences, all removals
         * are done first, regardless of whether you called remove before
         * or after put methods on this editor.
         * 
         * @param key The name of the preference to remove.
         * 
         * @return Returns a reference to the same Editor object, so you can
         * chain put calls together.
         */
        Editor remove(String key);

        /**
         * Mark in the editor to remove <em>all</em> values from the
         * preferences.  Once commit is called, the only remaining preferences
         * will be any that you have defined in this editor.
         * 
         * <p>Note that when committing back to the preferences, the clear
         * is done first, regardless of whether you called clear before
         * or after put methods on this editor.
         * 
         * @return Returns a reference to the same Editor object, so you can
         * chain put calls together.
         */
        Editor clear();

        /**
         * Commit your preferences changes back from this Editor to the
         * {@link SharedPreferences} object it is editing.  This atomically
         * performs the requested modifications, replacing whatever is currently
         * in the SharedPreferences.
         *
         * <p>Note that when two editors are modifying preferences at the same
         * time, the last one to call commit wins.
         *
         * <p>If you don't care about the return value and you're
         * using this from your application's main thread, consider
         * using {@link #apply} instead.
         *
         * @return Returns true if the new values were successfully written
         * to persistent storage.
         */
        boolean commit();

        /**
         * Commit your preferences changes back from this Editor to the
         * {@link SharedPreferences} object it is editing.  This atomically
         * performs the requested modifications, replacing whatever is currently
         * in the SharedPreferences.
         *
         * <p>Note that when two editors are modifying preferences at the same
         * time, the last one to call apply wins.
         *
         * <p>Unlike {@link #commit}, which writes its preferences out
         * to persistent storage synchronously, {@link #apply}
         * commits its changes to the in-memory
         * {@link SharedPreferences} immediately but starts an
         * asynchronous commit to disk and you won't be notified of
         * any failures.  If another editor on this
         * {@link SharedPreferences} does a regular {@link #commit}
         * while a {@link #apply} is still outstanding, the
         * {@link #commit} will block until all async commits are
         * completed as well as the commit itself.
         *
         * <p>As {@link SharedPreferences} instances are singletons within
         * a process, it's safe to replace any instance of {@link #commit} with
         * {@link #apply} if you were already ignoring the return value.
         *
         * <p>You don't need to worry about Android component
         * lifecycles and their interaction with <code>apply()</code>
         * writing to disk.  The framework makes sure in-flight disk
         * writes from <code>apply()</code> complete before switching
         * states.
         *
         * <p class='note'>The SharedPreferences.Editor interface
         * isn't expected to be implemented directly.  However, if you
         * previously did implement it and are now getting errors
         * about missing <code>apply()</code>, you can simply call
         * {@link #commit} from <code>apply()</code>.
         */
        void apply();
    }

这里面东西比较多 我们只看

Editor putString(String key, String value); 因为 用首选项的时候 都要用到编辑器 Editor 

而Editor最终要进行提交 他在存的时候是key value 键值对 所以这就可以看做是一个map

知道了这点之后 我们来存下这个东西 

依旧是很简单 为了使代码能够重用 这里我写一个工具类 叫做SpUtil

这里提到的一点是开发中很常用的一个代码结构 良好的工具类的效果无异是使事物事半功倍 

好的 我们看下工具类的写法

public class SpUtil {
	
	public static String spname="user";
	public static void saveSp(Context ct,String name,String pass){
		
		SharedPreferences sp = ct.getSharedPreferences(spname, ct.MODE_PRIVATE);
		Editor edit = sp.edit();
		edit.putString("name", name);
		edit.putString("pass", pass);
		edit.commit();
	}
	
	

}

这里面只是将name和pass的保持做了封装 

很多人可能会对 getXXX的最后一个模式 有的疑问 其实很简单 private 私有 也就是覆盖

append 为追加 也就是说你下一次再存的时候 不会进行覆盖 

而readeable和writerable为读和写的权限 这个就更好理解了 由于源码里封装了一个接口editor 所以我们只需要拿着这个编辑器进行提交就可以了

这样的话 我们的主代码反而变得很简单

if(cb.isChecked())
				/*//进行存储
				if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
					File dir = Environment.getExternalStorageDirectory();
					saveToSD(dir,name,pass);
				}else{
					//挂载sd卡
					
				saveToFile(name,pass);
				}*/
				SpUtil.saveSp(this, name, pass);

轻松搞定 当然 如果我们要进行回显的话 可以在工具类里面增加get方法 返回值为map 

然后拿着get方法 去填map.get(0)和get(1)就可以了 

下次 我们讲解剩下几个模块 大家一起进步!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值