Android数据持久化篇
一.文件操作篇
主要通过流来完成
得到输出流对象FileOutputStream:通过Context的openFileOuput("文件名",模式)方法获取
文件路径:/data/data/<包名>/files/ 存放在这个目录下
模式有二:Activity.MODE_PRIVATE覆盖;Activity.MODE_APPEND——追加
得到输入流对象FileInputStream:通过Context的openFileInput("文件名")返回一个输入流对象
会自动在路径:/data/data/<包名>/files/ 下找到要读取的文件名
接下来的操作即为java的IO操作技术!
贴入一段小代码
1 package com.example.filepersistencetest; 2 3 import java.io.BufferedReader; 4 import java.io.BufferedWriter; 5 import java.io.FileInputStream; 6 import java.io.FileOutputStream; 7 import java.io.InputStreamReader; 8 import java.io.OutputStreamWriter; 9 10 import android.app.Activity; 11 import android.os.Bundle; 12 import android.util.Log; 13 import android.view.View; 14 import android.view.View.OnClickListener; 15 import android.widget.Button; 16 import android.widget.EditText; 17 18 public class MainActivity extends Activity implements OnClickListener { 19 private EditText editText; 20 private Button sava_button; 21 private Button read_button; 22 23 @Override 24 protected void onCreate(Bundle savedInstanceState) { 25 super.onCreate(savedInstanceState); 26 setContentView(R.layout.activity_main); 27 editText = (EditText) findViewById(R.id.edit); 28 sava_button = (Button) findViewById(R.id.save); 29 read_button = (Button) findViewById(R.id.read); 30 31 // 绑定单击事件 32 sava_button.setOnClickListener(this); 33 read_button.setOnClickListener(this); 34 35 } 36 37 @Override 38 public void onClick(View v) { 39 // 监听 40 switch (v.getId()) { 41 case R.id.save: 42 save(); 43 break; 44 case R.id.read: 45 read(); 46 break; 47 48 default: 49 break; 50 } 51 52 } 53 54 public void save() { 55 String inputText = editText.getText().toString(); 56 BufferedWriter bufw = null; 57 FileOutputStream out = null; 58 // 得到输出流 Context->openFileOutput("文件名",写出模式——覆盖Private或者追加append) 59 // 返回FileOutputStream对象 60 try { 61 62 out = openFileOutput("my_data.txt", Activity.MODE_PRIVATE); 63 bufw = new BufferedWriter(new OutputStreamWriter(out)); 64 bufw.write(inputText); 65 Log.d("test", inputText); 66 bufw.flush(); 67 editText.setText(""); 68 } catch (Exception e) { 69 throw new RuntimeException("打开文件异常!!"); 70 } finally { 71 try { 72 if (null != bufw) 73 bufw.close(); 74 } catch (Exception e2) { 75 throw new RuntimeException("关闭流失败"); 76 } 77 } 78 } 79 80 public void read() { 81 editText.setText(""); 82 FileInputStream in = null; 83 BufferedReader bur = null; 84 try { 85 in = openFileInput("my_data.txt"); 86 bur = new BufferedReader(new InputStreamReader(in)); 87 String line = null; 88 boolean flag = false; 89 while ((line = bur.readLine()) != null) { 90 if (flag) 91 editText.append("\n" + line);// 92 else { 93 editText.append(line); 94 flag=true; 95 } 96 } 97 } catch (Exception e) { 98 // TODO: handle exception 99 } finally { 100 try { 101 bur.close(); 102 } catch (Exception e2) { 103 // TODO: handle exception 104 } 105 } 106 107 } 108 109 }
另外补充两点
a.TextUtils.isEmpty(inputText)——文本工具类,双重判空
b.edit.setSelection(inputText.length())——设置光标到末尾
二.xml存储篇——SharedPreferences
文件操作方式有点类似于无脑读,无脑写
而SharedPreferences则将数据分类的比较好,可以做到存什么类型就读什么类型,以键值对的方式存储
通常映射关系简单的时候,用SharedPreferences是比较合适的
存储路径:/data/data/<packagename>/shared_prefs/目录下
A.获取SharedPreferences,三种方法
a.Context 的 getSharedPreferences("文件名",模式)——如果指定的文件不存在,则会自动创建
MODE_PRIVATE(=0,默认,只有当前应用程序可以访问)
MODE_MULTI_PROCESS,用于多个进程多同一个SharedPreferences进行访问
b.Activity 的 getPreferences(模式) 会自动将当前活动的类名作为SharedPreferences文件名
c.PreferenceManager 的 静态getDefaultSharedPreferences(Context)——自动使用当前应用程序名称作为文件名的前缀
B.写
a.获得编辑器 通过SharedPreferences对象的edit()方法获取一个SharedPreferences.Editor对象
b.通过编辑器写数据 putBoolean putString ==
c.提交 commit()
代码示例:
1 saveButton.setOnClickListener(new OnClickListener() { 2 3 @Override 4 public void onClick(View v) { 5 // Context获取SharedPreferences对象,创建编辑器 6 SharedPreferences.Editor editor = getSharedPreferences("data", MODE_PRIVATE).edit(); 7 // put内容 8 editor.putString("name", "二哥"); 9 editor.putInt("age", 22); 10 editor.putBoolean("married", false); 11 // 提交 12 editor.commit(); 13 } 14 });
1 getButton.setOnClickListener(new OnClickListener() { 2 3 @Override 4 public void onClick(View v) { 5 SharedPreferences pref = getSharedPreferences("data", MODE_PRIVATE); 6 String name = pref.getString("name", "null"); 7 int age = pref.getInt("age", 0); 8 boolean married = pref.getBoolean("married", false); 9 10 Toast.makeText(MainActivity.this, name+"::"+age+"::"+married, Toast.LENGTH_LONG).show(); 11 } 12 });
记住密码功能实现——参看BroadcastBestPractice
a.定义一个控制器ActivityController管理所有的活动:包括增加,移除活动和销毁所有活动,通过一个List承载
1 package com.example.broadcastbestpractic; 2 3 import java.util.ArrayList; 4 import java.util.List; 5 6 import android.app.Activity; 7 8 /** 9 * 活动控制器 10 * 1.添加活动 11 * 2.删除活动 12 * 3.销毁所有活动 13 */ 14 public class ActivityController { 15 public static List<Activity> activities = new ArrayList<Activity>(); 16 public static void addActivity(Activity activity ){ 17 activities.add(activity); 18 } 19 public static void removeActivity(Activity activity ){ 20 21 activities.remove(activity); 22 } 23 public static void finishAll(){ 24 for(Activity activity:activities){ 25 activity.finish(); 26 } 27 } 28 }
b.定义一个基类继承Activity,改类的onCreate和onDestory方法分别实现增加和移除活动
1 package com.example.broadcastbestpractic; 2 3 import android.app.Activity; 4 import android.os.Bundle; 5 6 public class BaseActivity extends Activity { 7 8 @Override 9 protected void onCreate(Bundle savedInstanceState) { 10 // TODO Auto-generated method stub 11 super.onCreate(savedInstanceState); 12 ActivityController.addActivity(this); 13 } 14 15 @Override 16 protected void onDestroy() { 17 // TODO Auto-generated method stub 18 super.onDestroy(); 19 ActivityController.removeActivity(this); 20 } 21 22 }
c.主界面MainActivity,具有Button,用于发送强制下线广播
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="com.example.broadcastbestpractic.MainActivity" > 10 11 <Button 12 android:id="@+id/force_offline" 13 android:layout_width="match_parent" 14 android:layout_height="wrap_content" 15 android:text="Send a force offline broadcast" 16 android:gravity="center" 17 /> 18 19 </RelativeLayout>
1 package com.example.broadcastbestpractic; 2 3 import android.app.Activity; 4 import android.content.Intent; 5 import android.os.Bundle; 6 import android.view.View; 7 import android.view.View.OnClickListener; 8 import android.widget.Button; 9 10 11 public class MainActivity extends Activity { 12 13 @Override 14 protected void onCreate(Bundle savedInstanceState) { 15 super.onCreate(savedInstanceState); 16 setContentView(R.layout.activity_main); 17 18 Button offLine_btn = (Button) findViewById(R.id.force_offline); 19 offLine_btn.setOnClickListener(new OnClickListener() { 20 21 @Override 22 public void onClick(View v) { 23 // 发送轻质下线广播 24 Intent intent = new Intent("com.example.broadcastbestpractic.FORCE_OFFLINE"); 25 26 sendBroadcast(intent); 27 28 } 29 }); 30 } 31 32 }
d.登录界面LoginActivity,登录成功则跳转至主界面
1 <?xml version="1.0" encoding="utf-8"?> 2 <TableLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:layout_width="match_parent" 4 android:layout_height="match_parent" 5 android:stretchColumns="1" 6 > 7 8 <TableRow > 9 <TextView 10 android:layout_height="wrap_content" 11 android:text="Account:" 12 /> 13 <EditText 14 android:id="@+id/account" 15 android:layout_height="wrap_content" 16 android:hint="admin 123456" 17 /> 18 </TableRow> 19 20 <TableRow > 21 <TextView 22 android:layout_height="wrap_content" 23 android:text="Password:" 24 /> 25 <EditText 26 android:id="@+id/password" 27 android:layout_height="wrap_content" 28 android:inputType="textPassword" 29 /> 30 </TableRow> 31 <TableRow > 32 <CheckBox 33 android:id="@+id/remember_pass" 34 android:layout_height="wrap_content" 35 android:layout_gravity="right" 36 android:layout_marginRight="10dp" 37 /> 38 <TextView 39 android:layout_height="wrap_content" 40 android:layout_gravity="center_vertical" 41 android:text="Remenbered password" 42 /> 43 </TableRow> 44 <TableRow > 45 <Button 46 android:id="@+id/login" 47 android:text="login" 48 android:layout_span="2" 49 /> 50 51 </TableRow> 52 53 </TableLayout>
1 package com.example.broadcastbestpractic; 2 3 import android.content.Intent; 4 import android.content.SharedPreferences; 5 import android.os.Bundle; 6 import android.view.View; 7 import android.view.View.OnClickListener; 8 import android.widget.Button; 9 import android.widget.CheckBox; 10 import android.widget.EditText; 11 import android.widget.Toast; 12 13 public class LoginActivity extends BaseActivity { 14 private EditText accoutnEdit; 15 private EditText passwordEdit; 16 private Button loginButton; 17 private CheckBox rememberBox; 18 19 20 private SharedPreferences pref; 21 private SharedPreferences.Editor editor; 22 @Override 23 protected void onCreate(Bundle savedInstanceState) { 24 super.onCreate(savedInstanceState); 25 26 setContentView(R.layout.login); 27 28 loginButton = (Button) findViewById(R.id.login); 29 accoutnEdit = (EditText) findViewById(R.id.account); 30 passwordEdit = (EditText) findViewById(R.id.password); 31 rememberBox = (CheckBox) findViewById(R.id.remember_pass); 32 33 /* 在登录界面创建的时候,先读取xml文件,看复选框的值是否为true 34 * 如果为true,复选框状态改为true,账号密码的内容设置为xml文件的账号密码 35 * 不为true,则不管 36 */ 37 // 获取checkbox的值 38 pref = getSharedPreferences("data", MODE_PRIVATE); 39 Boolean isRemember = pref.getBoolean("isRemember", false); 40 41 if(isRemember){ 42 accoutnEdit.setText(pref.getString("account", "")); 43 passwordEdit.setText(pref.getString("password", "")); 44 45 // 注意设置选中的语句为 setChecked(true) 46 rememberBox.setChecked(true); 47 } 48 49 loginButton.setOnClickListener(new OnClickListener() { 50 51 @Override 52 public void onClick(View v) { 53 // 验证成功则跳转至主界面,失败者提示账号密码不正确 54 if("admin".equals(accoutnEdit.getText().toString())&&"123456".equals(passwordEdit.getText().toString())){ 55 // 记录账号 56 editor = getSharedPreferences("data", MODE_PRIVATE).edit(); 57 // 如果选中,则上传 58 if(rememberBox.isChecked()){ 59 editor.putBoolean("isRemember", true); 60 editor.putString("account", "admin"); 61 editor.putString("password", "123456"); 62 63 }else { 64 // 如果未选中,则清除,如果不清除,依然会记住密码 65 // 可用的方案二是,如果不清除,可以吧isRemember这个值设置为false,就不用大范围清空数据 66 editor.clear(); 67 } 68 editor.commit(); 69 70 Intent intent = new Intent(LoginActivity.this,MainActivity.class); 71 72 startActivity(intent); 73 }else { 74 Toast.makeText(LoginActivity.this, "account or password is not corret", Toast.LENGTH_SHORT).show(); 75 } 76 77 } 78 }); 79 } 80 }
e.静态广播接收器,用于接收强制下线广播,收到后销毁所有活动,弹出AlertDialog,提示重新登录
1 package com.example.broadcastbestpractic; 2 3 import android.app.AlertDialog; 4 import android.content.BroadcastReceiver; 5 import android.content.Context; 6 import android.content.DialogInterface; 7 import android.content.DialogInterface.OnClickListener; 8 import android.content.Intent; 9 import android.view.WindowManager; 10 /** 11 * 12 * 静态注册一个广播接收器,用于销毁活动和开启活动 13 */ 14 public class OfflineReceiver extends BroadcastReceiver { 15 16 @Override 17 public void onReceive(final Context context, Intent intent) { 18 // 销毁活动 19 ActivityController.finishAll(); 20 // 弹出对话框 21 AlertDialog.Builder alerBuilder = new AlertDialog.Builder(context); 22 alerBuilder.setTitle("Warnning!"); 23 alerBuilder.setMessage("You are forced line , plese try to login agin."); 24 alerBuilder.setCancelable(false); 25 alerBuilder.setPositiveButton("OK", new OnClickListener() { 26 27 @Override 28 public void onClick(DialogInterface dialog, int which) { 29 // 销毁所有活动 30 ActivityController.finishAll(); 31 // 重启登录 32 Intent intent = new Intent(context, LoginActivity.class); 33 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 34 context.startActivity(intent); 35 } 36 }); 37 38 AlertDialog dialog = alerBuilder.create(); 39 40 // dialog 创建好了,必须要让其显示,并且屏蔽home键 41 dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); 42 dialog.show(); 43 44 45 } 46 47 }
f.Manifest注册,LoginActivity(入口),MainActivity(主界面),静态广播
1 <?xml version="1.0" encoding="utf-8"?> 2 <manifest xmlns:android="http://schemas.android.com/apk/res/android" 3 package="com.example.broadcastbestpractic" 4 android:versionCode="1" 5 android:versionName="1.0" > 6 7 <uses-sdk 8 android:minSdkVersion="14" 9 android:targetSdkVersion="19" /> 10 11 <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /> 12 13 <application 14 android:allowBackup="true" 15 android:icon="@drawable/ic_launcher" 16 android:label="@string/app_name" 17 android:theme="@style/AppTheme" > 18 <activity 19 android:name=".LoginActivity" 20 android:label="@string/app_name" > 21 <intent-filter> 22 <action android:name="android.intent.action.MAIN" /> 23 24 <category android:name="android.intent.category.LAUNCHER" /> 25 </intent-filter> 26 </activity> 27 <activity android:name=".MainActivity" > 28 </activity> 29 <receiver android:name="com.example.broadcastbestpractic.OfflineReceiver"> 30 <intent-filter > 31 <action android:name="com.example.broadcastbestpractic.FORCE_OFFLINE"/> 32 </intent-filter> 33 </receiver> 34 </application> 35 36 </manifest>
注意:
a.Receiver中弹出对话框的步骤以及需要的权限
b.Manifest中要声明权限 android.permission.SYSTEM_ALERT_WINDOW,因为需要对话框一直存活直到点击重新ok重新登录
三.sqlite数据库篇
首先得知道的事情:
1.当数据映射复杂的时候,必然会用到数据库
2.Android内置轻量级数据库sqlite,路径在/system/xbin/sqlite3
3.程序中创建的数据库地址:/data/data/<包名>/databases/目录下
4.用实现抽象类SQLiteOpenHelper的子类对象XXX来创建和升级数据库
5.用XXX.getReadableDatabase()或XXX.getWritableDatabase()获取SQLiteDatabase对象YYY
6.通过YYY进行数据的增删改查
补充下cmd下sqlite测试操作
C:\Users\joho>adb shell
$ su
# cd /data/data/com.example.databasetest/databases
# sqlite3 BookStore.db
sqlite>.table
sqlite>.schema
sqlite>select * from Book;
sqlite>.quit
...
1.创建数据库
23.sqLiteOpenHelper = new MyDatabaseHelper(this, "BookStore.db", null, 1); 38.sqLiteOpenHelper.getWritableDatabase();
2.增
1 addDataButton.setOnClickListener(new OnClickListener() { 2 3 @Override 4 public void onClick(View v) { 5 // SQLiteOpenHelper的getWritableDatabase和getReadableDatab会返回一个SQLiteDatabase对象 6 SQLiteDatabase db = sqLiteOpenHelper.getWritableDatabase(); 7 // public long insert(String table, String nullColumnHack, ContentValues values) 8 ContentValues values = new ContentValues(); 9 values.put("author", "erge"); 10 values.put("price", "88.8"); 11 values.put("pages", "1"); 12 values.put("name", "程序员的自我修养"); 13 db.insert("Book", null, values);// 插入一条数据 14 15 values.clear(); // 准备插入第二条 16 values.put("author", "erge"); 17 values.put("price", "888.8"); 18 values.put("pages", "2"); 19 values.put("name", "程序员的未来"); 20 db.insert("Book", null, values); //插入第二条 21 22 } 23 });
3.改
1 updateButton.setOnClickListener(new OnClickListener() { 2 3 @Override 4 public void onClick(View v) { 5 // TODO Auto-generated method stub 6 SQLiteDatabase db = sqLiteOpenHelper.getWritableDatabase(); 7 // public int update(String table, ContentValues values, String whereClause, String[] whereArgs) 8 // (表名,值,where,where的值) 9 ContentValues values = new ContentValues(); 10 values.put("name", "the self_improvement of developer"); 11 db.update("Book", values, "name = ?", new String[]{"程序员的自我修养"}); 12 13 values.clear(); 14 values.put("name", "the future of developer"); 15 db.update("Book", values, "name = ?", new String[]{"程序员的未来"}); 16 Toast.makeText(MainActivity.this, "update sucess", Toast.LENGTH_SHORT).show(); 17 } 18 });
4.删
1 deleteButton.setOnClickListener(new OnClickListener() { 2 3 @Override 4 public void onClick(View v) { 5 // 6 SQLiteDatabase db = sqLiteOpenHelper.getWritableDatabase(); 7 // public int delete(String table, String whereClause, String[] whereArgs) 8 db.delete("Book", "pages > ?", new String[]{"1"}); 9 } 10 });
5.查
1 // 查询最为复杂,参数较多,得到的结果保存在游标——Cursor对象中 2 queryButton.setOnClickListener(new OnClickListener() { 3 4 @Override 5 public void onClick(View v) { 6 // TODO Auto-generated method stub 7 SQLiteDatabase db = sqLiteOpenHelper.getWritableDatabase(); 8 // public Cursor query(String table, String[] columns, String selection,String[] selectionArgs, String groupBy, String having,String orderBy) 9 //columns用于约束查询哪几列,不指定则查全部 10 //selection,selectionArgs用来约束查询哪些行,不指定则全部; 11 //groupBy指定需要group by的列,不指定则对结果进行group by处理; 12 //having用于对之前group by的数据进一步过滤,不指定则不过滤;orderBy对结果进行排序,不指定则默认排序 13 14 // 遍历得结果会存储到一个Course对象中,通过遍历这个对象,来输出数据 15 Cursor cursor = db.query("Book",null,null,null,null,null,null); 16 if(cursor.moveToFirst()){ 17 do { 18 String author = cursor.getString(cursor.getColumnIndex("author")); 19 Double price = cursor.getDouble(cursor.getColumnIndex("price")); 20 int pages = cursor.getInt(cursor.getColumnIndex("pages")); 21 String name = cursor.getString(cursor.getColumnIndex("name")); 22 Log.d("test", "name::"+name); 23 Log.d("test", "pages::"+pages); 24 Log.d("test", "price::"+price); 25 Log.d("test", "author::"+author); 26 } while (cursor.moveToNext()); 27 } 28 cursor.close(); 29 } 30 });
DatabaseTest代码
主布局
1 <LinearLayout 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:orientation="vertical" > 6 7 <Button 8 android:id="@+id/create" 9 android:layout_height="wrap_content" 10 android:layout_width="match_parent" 11 android:text="create database BookStore.db" 12 /> 13 14 <Button 15 android:id="@+id/add_data" 16 android:layout_height="wrap_content" 17 android:layout_width="match_parent" 18 android:text="Add data" 19 /> 20 <Button 21 android:id="@+id/update_data" 22 android:layout_height="wrap_content" 23 android:layout_width="match_parent" 24 android:text="Update data" 25 /> 26 <Button 27 android:id="@+id/delete_data" 28 android:layout_height="wrap_content" 29 android:layout_width="match_parent" 30 android:text="Delete data" 31 /> 32 <Button 33 android:id="@+id/query_data" 34 android:layout_height="wrap_content" 35 android:layout_width="match_parent" 36 android:text="Query data" 37 /> 38 <Button 39 android:id="@+id/replace_data" 40 android:layout_height="wrap_content" 41 android:layout_width="match_parent" 42 android:text="use transaction to replace Book" 43 /> 44 45 <Button 46 android:id="@+id/upgrade_one" 47 android:layout_height="wrap_content" 48 android:layout_width="match_parent" 49 android:text="upgrade database one" 50 /> 51 <Button 52 android:id="@+id/upgrade_two" 53 android:layout_height="wrap_content" 54 android:layout_width="match_parent" 55 android:text="upgrade database two" 56 /> 57 </LinearLayout>
定义MyDatabaseHelper继承SQLiteOpenHelper
特别注意升级数据库的写法!!
1 package com.example.databasetest; 2 3 import android.content.Context; 4 import android.database.sqlite.SQLiteDatabase; 5 import android.database.sqlite.SQLiteDatabase.CursorFactory; 6 import android.database.sqlite.SQLiteOpenHelper; 7 import android.widget.Toast; 8 /** 9 * 10 * 注意 id 设为主键时 primary key 两个词,分开的 11 */ 12 public class MyDatabaseHelper extends SQLiteOpenHelper { 13 public static final String CREATE_BOOK = 14 "create table Book(" + 15 "id integer primary key autoincrement," + 16 "author text, " + 17 "price real," + 18 "pages integer," + 19 "name text)"; 20 public static final String CREATE_CATEGORY="create table Category(" + 21 "id integer primary key autoincrement," + 22 "category_name text," + 23 "category_code integer)"; 24 private Context mContext;//为什么需要?获取SQLiteOpenHelper实例的时候,会传入context,为了在这个context中进行操作 25 // 构造方法(contex , 数据库名 , 光标? , 版本号) 26 public MyDatabaseHelper(Context context, String name, 27 CursorFactory factory, int version) { 28 super(context, name, factory, version); 29 mContext = context; 30 } 31 32 @Override 33 public void onCreate(SQLiteDatabase db) { 34 // 创建数据库的时候创建一张表 35 db.execSQL(CREATE_BOOK); 36 //db.execSQL(CREATE_CATEGORY); 37 Toast.makeText(mContext, "create table sussessed", Toast.LENGTH_SHORT).show(); 38 } 39 40 @Override 41 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 42 // 更新数据库——感觉这种方法很糟糕,如果存在则删除,数据不要了?? 43 /* 44 db.execSQL("drop table if exists Category"); 45 db.execSQL("drop table if exists Book"); 46 onCreate(db); 47 */ 48 49 // 最佳写法——当然第二版创建时就会创建category表,第三版创建时就会增加id 50 // 只有低版本升级是才会执行到下面的语句,另外特别注意: 51 // 这里并没有写break语句,是为了保证夸版本升级可以执行到所有语句——感觉还能改造,事务之类的 52 switch (oldVersion) { 53 //升级至第二版时,会多创建一个category表 54 case 1: 55 db.execSQL(CREATE_CATEGORY); 56 //升级至第三版时,Book表会新建一列 category_id 57 case 2: 58 db.execSQL("alter table Book add column category_id integer"); 59 default: 60 } 61 62 } 63 64 }
主入口
1 package com.example.databasetest; 2 3 import android.app.Activity; 4 import android.content.ContentValues; 5 import android.database.Cursor; 6 import android.database.sqlite.SQLiteDatabase; 7 import android.database.sqlite.SQLiteOpenHelper; 8 import android.os.Bundle; 9 import android.util.Log; 10 import android.view.View; 11 import android.view.View.OnClickListener; 12 import android.widget.Button; 13 import android.widget.Toast; 14 15 16 public class MainActivity extends Activity { 17 private SQLiteOpenHelper sqLiteOpenHelper; 18 @Override 19 protected void onCreate(Bundle savedInstanceState) { 20 super.onCreate(savedInstanceState); 21 setContentView(R.layout.activity_main); 22 // 得到SQLiteOpentHelper的实例 23 sqLiteOpenHelper = new MyDatabaseHelper(this, "BookStore.db", null, 1); 24 Button createDatabaseButton = (Button) findViewById(R.id.create); 25 Button addDataButton = (Button) findViewById(R.id.add_data); 26 Button updateButton = (Button) findViewById(R.id.update_data); 27 Button deleteButton = (Button) findViewById(R.id.delete_data); 28 Button queryButton = (Button) findViewById(R.id.query_data); 29 Button replaceButton = (Button) findViewById(R.id.replace_data); 30 Button upgrade_One_Button = (Button) findViewById(R.id.upgrade_one); 31 Button upgrade_Two_Button = (Button) findViewById(R.id.upgrade_two); 32 33 createDatabaseButton.setOnClickListener(new OnClickListener() { 34 35 @Override 36 public void onClick(View v) { 37 // 没有则会创建数据库,有则不创建 38 sqLiteOpenHelper.getWritableDatabase(); 39 } 40 }); 41 42 43 addDataButton.setOnClickListener(new OnClickListener() { 44 45 @Override 46 public void onClick(View v) { 47 // SQLiteOpenHelper的getWritableDatabase和getReadableDatab会返回一个SQLiteDatabase对象 48 SQLiteDatabase db = sqLiteOpenHelper.getWritableDatabase(); 49 // public long insert(String table, String nullColumnHack, ContentValues values) 50 ContentValues values = new ContentValues(); 51 values.put("author", "erge"); 52 values.put("price", "88.8"); 53 values.put("pages", "1"); 54 values.put("name", "程序员的自我修养"); 55 db.insert("Book", null, values);// 插入一条数据 56 57 values.clear(); // 准备插入第二条 58 values.put("author", "erge"); 59 values.put("price", "888.8"); 60 values.put("pages", "2"); 61 values.put("name", "程序员的未来"); 62 db.insert("Book", null, values); //插入第二条 63 64 } 65 }); 66 67 updateButton.setOnClickListener(new OnClickListener() { 68 69 @Override 70 public void onClick(View v) { 71 // TODO Auto-generated method stub 72 SQLiteDatabase db = sqLiteOpenHelper.getWritableDatabase(); 73 // public int update(String table, ContentValues values, String whereClause, String[] whereArgs) 74 // (表名,值,where,where的值) 75 ContentValues values = new ContentValues(); 76 values.put("name", "the self_improvement of developer"); 77 db.update("Book", values, "name = ?", new String[]{"程序员的自我修养"}); 78 79 values.clear(); 80 values.put("name", "the future of developer"); 81 db.update("Book", values, "name = ?", new String[]{"程序员的未来"}); 82 Toast.makeText(MainActivity.this, "update sucess", Toast.LENGTH_SHORT).show(); 83 } 84 }); 85 86 deleteButton.setOnClickListener(new OnClickListener() { 87 88 @Override 89 public void onClick(View v) { 90 // 91 SQLiteDatabase db = sqLiteOpenHelper.getWritableDatabase(); 92 // public int delete(String table, String whereClause, String[] whereArgs) 93 db.delete("Book", "pages > ?", new String[]{"1"}); 94 } 95 }); 96 97 // 查询最为复杂,参数较多 98 queryButton.setOnClickListener(new OnClickListener() { 99 100 @Override 101 public void onClick(View v) { 102 // TODO Auto-generated method stub 103 SQLiteDatabase db = sqLiteOpenHelper.getWritableDatabase(); 104 // public Cursor query(String table, String[] columns, String selection,String[] selectionArgs, String groupBy, String having,String orderBy) 105 //columns用于约束查询哪几列,不指定则查全部 106 //selection,selectionArgs用来约束查询哪些行,不指定则全部; 107 //groupBy指定需要group by的列,不指定则对结果进行group by处理; 108 //having用于对之前group by的数据进一步过滤,不指定则不过滤;orderBy对结果进行排序,不指定则默认排序 109 110 // 遍历得结果会存储到一个Course对象中,通过遍历这个对象,来输出数据 111 Cursor cursor = db.query("Book",null,null,null,null,null,null); 112 if(cursor.moveToFirst()){ 113 do { 114 String author = cursor.getString(cursor.getColumnIndex("author")); 115 Double price = cursor.getDouble(cursor.getColumnIndex("price")); 116 int pages = cursor.getInt(cursor.getColumnIndex("pages")); 117 String name = cursor.getString(cursor.getColumnIndex("name")); 118 Log.d("test", "name::"+name); 119 Log.d("test", "pages::"+pages); 120 Log.d("test", "price::"+price); 121 Log.d("test", "author::"+author); 122 } while (cursor.moveToNext()); 123 } 124 cursor.close(); 125 } 126 }); 127 128 replaceButton.setOnClickListener(new OnClickListener() { 129 130 @Override 131 public void onClick(View v) { 132 // TODO Auto-generated method stub 133 SQLiteDatabase db = sqLiteOpenHelper.getWritableDatabase(); 134 db.beginTransaction(); 135 try { 136 // 删除原来的表 137 db.delete("Book", null, null); 138 139 // 中断测试 140 if(true){ 141 throw new RuntimeException("..."); 142 } 143 // 重新添加数据 144 ContentValues values = new ContentValues(); 145 values.put("author", "nima"); 146 values.put("price", 25.5); 147 values.put("pages", 88); 148 values.put("name", "zhiqinchun"); 149 150 db.insert("Book", null, values); 151 db.setTransactionSuccessful(); 152 } catch (Exception e) { 153 // TODO: handle exception 154 }finally{ 155 db.endTransaction(); 156 } 157 } 158 }); 159 160 upgrade_One_Button.setOnClickListener(new OnClickListener() { 161 162 @Override 163 public void onClick(View v) { 164 // 这里数据库版本应该搞个变量控制一下,不然升级就只能升级一次 ,后面指定的版本号比之前的大的话,就会调用onUpgrade方法 165 sqLiteOpenHelper = new MyDatabaseHelper(MainActivity.this, "BookStore.db", null, 2); 166 sqLiteOpenHelper.getWritableDatabase(); 167 168 } 169 }); 170 upgrade_Two_Button.setOnClickListener(new OnClickListener() { 171 172 @Override 173 public void onClick(View v) { 174 // 这里数据库版本应该搞个变量控制一下,不然升级就只能升级一次 ,后面指定的版本号比之前的大的话,就会调用onUpgrade方法 175 sqLiteOpenHelper = new MyDatabaseHelper(MainActivity.this, "BookStore.db", null, 3); 176 sqLiteOpenHelper.getWritableDatabase(); 177 178 } 179 }); 180 181 } 182 183 }