第39,40,41,42章
第39章 偏好
- 在Android应用中,我们常需要记录用户设置的一些偏好参数,,此时我们就需要用SharedPreferences和Editor将这些信息保存下来,在下次登录时读取。
SharedPreferences保存的数据主要类似于配置信息格式的数据,因此它保存数据的形式为key-value对,下面我们来看下实例代码。
首先是界面布局,比较简单,就是一个普通的登陆界面.
1 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
2 xmlns:tools="http://schemas.android.com/tools"
3 android:layout_width="match_parent"
4 android:layout_height="match_parent"
5 android:paddingBottom="@dimen/activity_vertical_margin"
6 android:paddingLeft="@dimen/activity_horizontal_margin"
7 android:paddingRight="@dimen/activity_horizontal_margin"
8 android:paddingTop="@dimen/activity_vertical_margin"
9 tools:context=".MainActivity" >
10 <EditText
11 android:layout_width="fill_parent"
12 android:layout_height="wrap_content"
13 android:id="@+id/account"
14 />
15 <EditText
16 android:layout_width="fill_parent"
17 android:layout_height="wrap_content"
18 android:id="@+id/password"
19 android:layout_below="@id/account"
20 />
21 <Button
22 android:layout_width="fill_parent"
23 android:layout_height="wrap_content"
24 android:layout_below="@id/password"
25 android:text="保存参数"
26 android:id="@+id/save"
27 android:onClick="save"
28 />
29 </RelativeLayout>
这是自定义的Preferences 类,用来实现数据的保存 ,可在Android的内置存储空间产生一文件。
1 import android.R.integer;
2 import android.content.Context;
3 import android.content.SharedPreferences;
4 import android.content.SharedPreferences.Editor;
5 import android.widget.EditText;
6
7 public class Preferences {
8
9 private Context context;
10 public Preferences(Context context)
11 {
12 this.context=context;
13 }
14
15
16 public void save(String name, Integer valueOf)
17 {
18 //保存文件名字为"shared",保存形式为Context.MODE_PRIVATE即该数据只能被本应用读取
19 SharedPreferences preferences=context.getSharedPreferences("shared",Context.MODE_PRIVATE);
20
21 Editor editor=preferences.edit();
22 editor.putString("name", name);
23 editor.putInt("age", valueOf);
24
25 editor.commit();//提交数据
26 }
27
28
29 }
下面是Mainactivity的代码。在activity的oncreate阶段我们加载本地的数据。
import java.util.HashMap;
import java.util.Map;
import android.R.integer;
import android.os.Bundle;
import android.app.Activity;
import android.content.SharedPreferences;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
public class MainActivity extends Activity {
private EditText account,passworad;
Preferences prefer;//自定义的类
SharedPreferences preference;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
account=(EditText)findViewById(R.id.account);
passworad=(EditText)findViewById(R.id.password);
//获取本地的数据
preference=getSharedPreferences("shared", MODE_PRIVATE);
Map<String, String> map=new HashMap<String, String>();
map.put("name",preference.getString("name",""));
map.put("age", String.valueOf(preference.getInt("age", 0)));
account.setText(map.get("name"));
passworad.setText(map.get("age"));
}
//保存文件的方法
public void save(View v) {
String name=account.getText().toString();
String age=passworad.getText().toString();
prefer=new Preferences(this);
prefer.save(name,Integer.valueOf(age));
Toast.makeText(getApplicationContext(), "保存完成", Toast.LENGTH_SHORT).show();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}
点击保存参数,出现保存完成则说明我们已经保存成功了,在下次登录的时候可以看到这些参数还在。因为记录文件是在内置空间中的,所以我们在SD卡中找不到该文件,
如果有root权限的手机可以下载个RE文件管理,我们可以再/data/data/的路径找到很多应用程序的内置文件夹,我们可以在这些文件夹中看到一个shared_prefs文件夹,
里面就有我们刚刚设置而产生的xml文件。
第40章 操作文件
- 相对路径和绝对路径
在java中,关于相对路径和绝对路径是这样解释的,如果你很熟悉这部分以下灰色文字可以跳过:
绝对路径是指书写文件的完整路径,例如d:javaHello.java,该路径中包含文件的完整路径d:java以及文件的全名Hello.java。使用该路径可以唯一的找到一个文件,不会产生歧义。但是使用绝对路径在表示文件时,受到的限制很大,且不能在不同的操作系统下运行,因为不同操作系统下绝对路径的表达形式存在不同。
相对路径是指书写文件的部分路径,例如 estHello.java,该路径中只包含文件的部分路径 est和文件的全名Hello.java,部分路径是指当前路径下的子路径,例如当前程序在d:abc下运行,则该文件的完整路径就是d:abc est。使用这种形式,可以更加通用的代表文件的位置,使得文件路径产生一定的灵活性。
在Eclipse项目中运行程序时,当前路径是项目的根目录,例如工作空间存储在d:javaproject,当前项目名称是Test,则当前路径是:d:javaprojectTest。在控制台下面运行程序时,当前路径是class文件所在的目录,如果class文件包含包名,则以该class文件最顶层的包名作为当前路径。
这是java在多数操作系统中这样操作,很显然是要我们尽可能的使用相对路径,但是在安卓中,其实多数情况下我们都是使用的绝对路径。为什么呢?注意上面说到相对路径是以当前项目所在路径为当前路径,但在安卓中我们是不可能在项目所在路径目录下做任何操作的,因为普通java中我们的项目创建于服务器(pc也算是服务器),运行于服务器,我们当然能在服务器操作自己的文件目录。但是安卓开发中,我们的项目一般是创建于自己工作的电脑,而运行于手机,既然apk已经运行于手机了,那项目就已经部署到手机上了,应该以apk在手机上的位置来确定相对路径,但我们好像们没有办法操作这个路径的,因为apk是在system目录下,就算可以操作,在这个目录下存取文件也是没有意义的,比如我写一个相册程序,图片肯定是放在外部存储中,而如果我要保存一个应用的一些设置数据,我是放在内部存储的data目录下,因此其实在安卓文件管理中,我们都是在操作绝对路径。 - File类
操作一个文件(读写,创建文件或者目录)是通过File类来完成的,这个操作和java中完全一致。
外部存储external storage和内部存储internal storage
1.内部存储:
注意内部存储不是内存。内部存储位于系统中很特殊的一个位置,如果你想将文件存储于内部存储中,那么文件默认只能被你的应用访问到,且一个应用所创建的所有文件都在和应用包名相同的目录下。也就是说应用创建于内部存储的文件,与这个应用是关联起来的。当一个应用卸载之后,内部存储中的这些文件也被删除。从技术上来讲如果你在创建内部存储文件的时候将文件属性设置成可读,其他app能够访问自己应用的数据,前提是他知道你这个应用的包名,如果一个文件的属性是私有(private),那么即使知道包名其他应用也无法访问。 内部存储空间十分有限,因而显得可贵,另外,它也是系统本身和系统应用程序主要的数据存储所在地,一旦内部存储空间耗尽,手机也就无法使用了。所以对于内部存储空间,我们要尽量避免使用。Shared Preferences和SQLite数据库都是存储在内部存储空间上的。内部存储一般用Context来获取和操作。
getFilesDir()获取你app的内部存储空间,相当于你的应用在内部存储上的根目录。
如果是要创建一个文件,如下
File file = newFile(context.getFilesDir(), filename);
安卓还为我们提供了一个简便方法 openFileOutput()来读写应用在内部存储空间上的文件,下面是一个向文件中写入文本的例子:
String filename = "myfile";
String string = "Hello world!";
FileOutputStream outputStream;
try{
outputStream = openFileOutput(filename, Context.MODE_PRIVATE);
outputStream.write(string.getBytes());
outputStream.close();
} catch(Exception e) {
e.printStackTrace();
}
总结一下文件相关操作,可以得出以下三个特点:
- 文件操作只需要向函数提供文件名,所以程序自己只需要维护文件名即可;
- 不用自己去创建文件对象和输入、输出流,提供文件名就可以返回File对象或输入输出流
- 对于路径操作返回的都是文件对象。
2.外部存储:
最容易混淆的是外部存储,如果说pc上也要区分出外部存储和内部存储的话,那么自带的硬盘算是内部存储,U盘或者移动硬盘算是外部存储,因此我们很容易带着这样的理解去看待安卓手机,认为机身固有存储是内部存储,而扩展的T卡是外部存储。比如我们任务16GB版本的Nexus 4有16G的内部存储,普通消费者可以这样理解,但是安卓的编程中不能,这16GB仍然是外部存储。
所有的安卓设备都有外部存储和内部存储,这两个名称来源于安卓的早期设备,那个时候的设备内部存储确实是固定的,而外部存储确实是可以像U盘一样移动的。但是在后来的设备中,很多中高端机器都将自己的机身存储扩展到了8G以上,他们将存储在概念上分成了"内部internal" 和"外部external" 两部分,但其实都在手机内部。所以不管安卓手机是否有可移动的sdcard,他们总是有外部存储和内部存储。最关键的是,我们都是通过相同的api来访问可移动的sdcard或者手机自带的存储(外部存储)。
外部存储虽然概念上有点复杂,但也很好区分,你把手机连接电脑,能被电脑识别的部分就一定是外部存储。
外部存储中的文件是可以被用户或者其他应用程序修改的,有两种类型的文件(或者目录):
1.公共文件Public files:文件是可以被自由访问,且文件的数据对其他应用或者用户来说都是由意义的,当应用被卸载之后,其卸载前创建的文件仍然保留。比如camera应用,生成的照片大家都能访问,而且camera不在了,照片仍然在。
如果你想在外存储上放公共文件你可以使用getExternalStoragePublicDirectory()
public File getAlbumStorageDir(String albumName) {
// Get the directory for the user's public pictures directory.
File file = newFile(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES), albumName);
if(!file.mkdirs()) {
Log.e(LOG_TAG, "Directory not created");
}
returnfile;
}
在上面的代码中我们创建获得了存放picture的目录,并且新创建一个albumName文件。
如果你的api 版本低于8,那么不能使用getExternalStoragePublicDirectory(),而是使用Environment.getExternalStorageDirectory(),他不带参数,也就不能自己创建一个目录,只是返回外部存储的根路径。
2.私有文件Private files:其实由于是外部存储的原因即是是这种类型的文件也能被其他程序访问,只不过一个应用私有的文件对其他应用其实是没有访问价值的(恶意程序除外)。外部存储上,应用私有文件的价值在于卸载之后,这些文件也会被删除。类似于内部存储。
创建应用私有文件的方法是Context.getExternalFilesDir(),如下:
public File getAlbumStorageDir(Context context, String albumName) {
// Get the directory for the app's private pictures directory.
File file = newFile(context.getExternalFilesDir(
Environment.DIRECTORY_PICTURES), albumName);
if(!file.mkdirs()) {
Log.e(LOG_TAG, "Directory not created");
}
returnfile;
}
所有应用程序的外部存储的私有文件都放在根目录的Android/data/下,目录形式为/Android/data/<package_name>/
第41章 操作数据库
1、数据库的创建:
private static final String TABLENAME = "student";
private static final String CREATETABLE = "CREATE TABLE " + TABLENAME +
"(_id INTEGER PRIMARY KEY AUTOINCREMENT,name TEXT,age INTEGER)";
public void creatTable(View view){
/**
* 创建数据库
* 参数一:数据库名
* 参数二:模式,一般为MOE_PRIVATE
* 参数三:游标工厂对象,一般写null,表示系统自动提供
*/
SQLiteDatabase db = this.openOrCreateDatabase("text.db",MODE_PRIVATE,null);
db.execSQL(CREATETABLE);
db.close();
}
2、数据库表的创建和数据的添加:
public void insertData(View view){
SQLiteDatabase db = this.openOrCreateDatabase("text.db",MODE_PRIVATE,null);
ContentValues values = new ContentValues();
values.put("name","张三");
values.put("age",18);
/**
*插入数据
* 参数一:要插入的表名
* 参数二:要插入的空数据所在的行数,第三个参数部位空,则此参数为null
* 参数三:要插入的数据
*/
db.insert(TABLENAME,null,values);
ContentValues values1 = new ContentValues();
values1.put("name","李四");
values1.put("age",21);
db.insert(TABLENAME,null,values1);
db.close();
}
3、数据库的更新:
public void updateData(View view){
SQLiteDatabase db = this.openOrCreateDatabase("text.db",MODE_PRIVATE,null);
ContentValues values = new ContentValues();
values.put("name","赵四");
values.put("age",43);
/**
* 数据的更新
* 参数一:要更新的数据所在的表名
* 参数二:新的数据
* 参数三:要更新数据的查找条件
* 参数四:条件的参数
*/
db.update(TABLENAME,values,"_id=?",new String []{"2"});
db.close();
}
4、数据的查找:
public void queryData(View view){
SQLiteDatabase db = this.openOrCreateDatabase("text.db",MODE_PRIVATE,null);
//查询部分数据
Cursor cursor = db.rawQuery("select * from " + TABLENAME + "where name=?",new String []{"张三"});
//查询全部数据
Cursor cursor1 = db.rawQuery("select * from " + TABLENAME ,null);
//将游标移到第一行
cursor1.moveToFirst();
//循环读取数据
while(!cursor1.isAfterLast()){
//获得当前行的标签
int nameIndex = cursor1.getColumnIndex("name");
//获得对应的数据
String name = cursor1.getString(nameIndex);
int ageIndex = cursor1.getColumnIndex("age");
int age = cursor1.getInt(ageIndex);
Log.d(TAG, "name:"+ name +"age: "+age);
//游标移到下一行
cursor1.moveToNext();
}
db.close();
}
5、数据的删除:
public void delectData(View view){
SQLiteDatabase db = this.openOrCreateDatabase("text.db",MODE_PRIVATE,null);
//要删除的数据
db.delete(TABLENAME,"name = ?",new String[]{"赵四"});
db.close();
}
第42章 获取图片
在Andorid系统中所有的文件路径都保存在一个数据库中,位于data/data/com.android.providers.media文件夹下的external.db
里面的files表就有我们需要的内容,这个表包含了机器所有的文件。接下来只要选择合适的sql语句来获取我们需要的内容就行了。