开源数据库开源库:

Ormlite



SQLite支持的字段类型及建表

http://boonya.iteye.com/blog/2118252


SQLite查询

http://www.cnblogs.com/Excellent/archive/2011/11/19/2254888.html



一、Android中的数据库的创建和操作

    在Android中如果进行大量的具有相同数据结构存储时,需要用到SQLite数据库。

  1.SQLite的特点:

    1)它是一个轻量级的数据库,其实就是一个文件。当然它的容量有有限的,毕竟是运行在

       手机Android系统中的。

    2)它虽然小,但是它功能却十分的强大,操作起来非常简便。

  2.SQLite的创建

    第1步:创建一个类继承SQLiteOpenHelper类,实现它的2个方法onCreate()和onUpgrade()。

public class MyOpenHelper extends SQLiteOpenHelper {//本来构造方法应该有4个参数,super调用的时候把参数写死了,这里就只传context参数了。public MyOpenHelper(Context context) {/* * Parameterscontext 上下文name SQLite数据库名称factory 用于创建Cursor,一般写null。version 数据库的版本号 */super(context, "user.db", null, 3);//调用父类的构造方法初始化数据库,在调用MYOpenHelper才去判断数据库是否存在。} /*  * onCreate数据库第一次创建的时候会被调用 ,如果数据库已经存在,不会被调用。  * SQLiteDatabase数据库对象,可以执行SQL语句。  */@Overridepublic void onCreate(SQLiteDatabase db) {//此方法一般用来写创建表的代码db.execSQL("create table info (_id integer primary key autoincrement,name varchar(20))");//注意这里的sql语句是mysql中使用的sql语句的区别,int变成integer,autoincr                 ement中间没有下划线}/* * onUpgrade当数据库升级的时候调用。 * oldVersion新版本 * newVersion老版本 * 注意修改表结构时不能添加重复字段 */@Overridepublic void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {//此方法一般用来写修改表结构的代码db.execSQL("alter table info add phone varchar(11)");}}

   第2步:创建上面定义这个数据库打开助手类的实例

MyOpenHelper myOpenHelper = new MyOpenHelper(this);

   第3步:利用数据库打开助手类来创建数据库(两种方式)

//getReadableDatabase()方法首先会调用getWritableDatabase()方法,如果数据库在磁盘中的存储空间已满,就会以只读方式打开数据库。SQLiteDatabase readableDatabase = myOpenHelper.getReadableDatabase();    //建议使用//getWritableDatabase()会以读写方式打开数据库,如果磁盘中的存储空间已满,就会直接报错。SQLiteDatabase writableDatabase = myOpenHelper.getWritableDatabase();

  数据库创建成功后,会生成在/data/data/应用程序包名/databases目录下,即私有目录。之前还学过files、shared_prefs目录。

 3.SQLite增删改查操作

    SQLite的增删改查的流程是一致的,只是中间执行的sql语句有所不同。

       》通过数据库助手打开助手返回一个数据库对象SQLiteDatabase

       》通过SQLiteDatabase对象执行sql语句,2种方式。

       》关闭数据库。

   下面就说上面的第2步操作,执行sql。

   *传统方式:

      SQLiteDatabase.execSQL("sql语句"[,点位符参数数组Object类型]);

      这种方式的弊端就是容易将sql语句写错,如有中文字符、圆角字符等;而且execSQL的方法

      没有返回值,无法判断sql操作是否成功。

   *调用方法

      SQLiteDatabase类定义了和sql语句相对应的方法,虽然此方式减小了书写sql语句出

      错的机率,但是方法的参数比较多,用起来比较麻烦。

       

public class UserDaoImpl implements UserDao{private MyOpenHelper sqlHelper;//在构造函数中创建SQLiteOpenHelper数据库打开助手对象public UserDaoImpl(Context context){sqlHelper = new MyOpenHelper(context);}//增加操作/**    insert方法的第3个参数为    ContentValues类型,底层用的是map。存取的是要添加         *    的字段的名称和值。*/@Overridepublic long add(UserBean user) {//得到数据库对象SQLiteDatabase database = sqlHelper.getWritableDatabase();//database.execSQL("insert into info values(null,?,?)",new Object[]{user.name,user.phone});//利用SQLiteDatabase自带的有返回值的方法来替代sql语句。ContentValues values = new ContentValues();values.put("name", user.name);values.put("phone", user.phone);long row_id = database.insert("info", null, values);database.close();return row_id;}//删除操作@Overridepublic long del(String name) {SQLiteDatabase database = sqlHelper.getWritableDatabase();//database.execSQL("delete from info where name like ?",new Object[]{name});long delete_rows = database.delete("info", "name like ?", new String[]{name});    //注意条件是没有where关键字的database.close();return delete_rows;}//更新操作/**    update方法的第2个参数为    ContentValues类型,底层用的是map。键就是要更         *    改的字段,值就是修改后的字段对应的值。*/@Overridepublic int update(UserBean user) {SQLiteDatabase database = sqlHelper.getWritableDatabase();//database.execSQL("update info set name = ?,phone = ?",new Object[]{user.name + "_修改",user.phone + "_修改"});ContentValues values = new ContentValues();values.put("phone", user.phone + "_修改");int update_rows = database.update("info", values, "name=?", new String[]{user.name});database.close();return update_rows;}//查询操作/**query方法的第2参数为要查询的项*/@Overridepublic List query() {SQLiteDatabase database = sqlHelper.getWritableDatabase();//创建一个List集合,返回数据List list_user = new ArrayList();//得到查询集合//Cursor cursor = database.rawQuery("select name,phone from info", null);Cursor cursor = database.query("info", new String[]{"name","phone"}, null, null, null, null, null);if(cursor != null & cursor.getCount() > 0){while(cursor.moveToNext()){//注意索引是相对于Cursor的,不是相对于数据库的,第1列为nameString name = cursor.getString(0);//得到电话 String phone =  cursor.getString(1);list_user.add(new UserBean(name,phone));}return list_user;}return null;}}

对于Cursor,特别要注意:Cursor得到之后,要调用一次moveToFirst或者moveToNext。否则就会将表头误认为表的记录。 

  • cursor getCount不为0,但是遍历却一个也没有遍历出来。

    https://www.jianshu.com/p/ba722c2271d6




4.SQLite数据库的事物 

事务 : 要么多条sql语句同时成功执行,要么同时失败银行转账    //开启事物    db.beginTransaction();    try {        //      转账        db.execSQL("update account set money= money-200 where name=?",new String[]{"李四"});        db.execSQL("update account set money= money+200 where name=?",new String[]{"张三"});        //设置事物已经成功执行        db.setTransactionSuccessful();    } finally {        //结束事物        db.endTransaction();    }

 5.在linux命令行下执行SQLite数据库的命令

 

 在多线程访问数据库的时候会出现这样的异常:java.lang.IllegalStateException: Cannot perform this operation because the connection pool has been closed.或 java.lang.IllegalStateException: attempt to re-open an already-closed object: SQLiteDatabase: 或java.lang.IllegalStateException: attempt to re-open an already-closed object: SQLiteDatabase:

   

 6.数据库查询

   1)如何从后往前查询

     方式1:写sql语句,用desc关键字。

     方式2:用sqlite自带的query方法,得到cursor,操作cursor的指针

     

 List list; boolean result = cursor.moveToLast();    if(result){        list.add(result);    } while(cursor.moveToPrevious()){     ...     list.add(); }    return list;

 

   2)查询指定时间范围内的数据

     存储记录的时候,存储一个时间戳,写sql的时候就好写了。否则sql语句是不支持自定义的函数的。

  

  6.Sqlite数据库的几大坑要注意:

     1)database 在app退出的时候记得关掉

     2)cursor做完查询后也要关掉

     3)记得往数据库存储的时候用的什么类型,取的时候类型也要对应。特别是在存储long型时间戳时,定义表用的虽然是Integer类型,但是取的时候还是要
      cursor.getLong来取。

    4)数据库的结构发生变化 :表的字段发生变化时,一定要写相关的升级代码,不要直接跑程序。否则就会发生错误。


     

二、Android中ListView的使用

 1.ListView的使用流程:

     第1步:创建有ListView的布局,并创建ListView的item项的UI。

    第2步:得到要传递给适配器构造函数的数据,可以模拟或从网络上解析获取。

    第3步:创建一个适配器对象,一般先会定义一个类继承BaseAdapter这个抽象适配器类,实现

         它的4个基本方法,并创建一个带有数据参数的构造函数。通过那4个方法将构造函数

        传递初始化的数据参数绑定给lListView的各个item项。

     第4步:在java代码中找到ListView,调用它的setAdapter方法关联创建的适配器对象。

  2.ListView的代码实现: 

    以网易新闻客户端为例,来说明ListView的实现。

    开发步骤:

    第1步:设计UI

    第2步:模拟适配器的数据(实际是从网络解析的)

    第3步:定义适配器类继承BaseAdapter类,并创建适配器对象。

    第4步:在java代码中得到ListView,关联适配器对象。

    -----------------------------------------------------------------------------

    第1步:设计UI

        主UI设计:

    

        子UI设计:

    

    

    第2步:模拟数据

 创建一个bean包,在里面创建一个NewsBean类,定义3 个属性     class NewsBean{           public Drawablepic;    //代表图片            publicString title,des,url;  //代表主题、内容、链接地址                            } 在工具类中创建一个静态方法,返回List的集合。

    第3步:定义适配器(最重要、最复杂的一步)*********************************

class MyAdapter extends BaseAdapter{List news = null; //定义构造方法来初始化要绑定给适配器的数据集public MyAdapter(List news){this.news = news;} //getCount返回ListView要显示的Item条数,一般返回数据集的长度。@Overridepublic int getCount() {return news.size();}     //getItem返回的是指定位置的数据集,并不是item本身。@Overridepublic Object getItem(int position) {return news.get(position);}     //getItemId返回的指定位置item项对应的的id,一般保持与position一致。 @Overridepublic long getItemId(int position) {return position;}     //绑定指定位置的item的视图      @Overridepublic View getView(int position, View convertView, ViewGroup pare           nt) {View view = null;/*ListView的优化,在ListView滚动的时候,不会创建新的view,会引用前面第一屏创建好的view对象。*/if(convertView != null){    view = convertView;}else{               view = View.inflate(mContext, R.layout.newsitem, null);        /*        下面为另外两种获取item的view的方式。               view = LayoutInflater.from(mContext).inflate(R.layout.n                        ewsitem, null);   LayoutInflater inflater = (LayoutInflater) mContext.g                etSystemService(LAYOUT_INFLATER_SERVICE);   view = inflater.inflate(R.layout.newsitem, null);         */}//得到item视图中的组件ImageView imgItem = (ImageView) view.findViewById(R.id.img);TextView titleItem = (TextView) view.findViewById(R.id.title);TextView desItem = (TextView) view.findViewById(R.id.des);//获取指定position的对应于数据集的数据。NewsBean newItem = news.get(position);//为item组件绑定数据imgItem.setImageDrawable(newItem.pic);titleItem.setText(newItem.title);desItem.setText(newItem.des);return view;    //最开始就写好,不要忘了返回item的显示视图。}}

    第4步:获取ListView,创建并绑定适配器。

//创建javaBean和适配器        List news = NewsUtils.getAllNews(mContext);        MyAdapter adapter = new MyAdapter(news);         //关联listView的适配器        ListView lv_news = (ListView) findViewById(R.id.lv_news);        lv_news.setAdapter(adapter);

    最终效果:

    



    其它的一些适配器

     它们都是非抽象类,可以直接用构造函数来传递数据并创建对象。

     ■ArrayAdapter

      它的常用的一个构造方法

        public ArrayAdapter (Context context, int resource, inttextViewResourceId, T[] objects)

         

          Parameters

          context          上下文

          resource            Item项的布局文件R.layout.name

          textViewResourceId     Item项TextViewid,指的是resource布局中的id.          objects            要显示在item上的数据,有多个数据,就显示多少

                      个item

        这种适配器比较粗糙,单纯的用构造函数来构造的话,也不不能设置Itemview的样

        式,而且一个item只能给子布局中的一个TextView适配数据。

      

    示例代码及其效果:       mContext = this;        ListView lv_arr = (ListView)findViewById(R.id.lv_arr);                Integer[] items = new Integer[100];        for(int i = 0; i(mContext,R.layout.item_arradapte                                r, R.id.tv_arrItem, items);        lv_arr.setAdapter(arrAdapter);

      
    效果图:

    

     ■SimpleAdapter

        与ArrayAdapter不同,它可以绑定多个TextView的数据,它绑定的数据稍微复杂

        点。

      它的常用构造方法  

        public SimpleAdapter (Context context, List<? extendsMap> data,

        int resource, String[] from, int[] to)

 

        Parameters

        context       上下文

        data           List<?extends Map>类型的集合    

        resource        Item项的布局文件,至少要包含"to"参数中指定的

                  textview,但允许它有其它的组件。                                                                        

        from           map的键的名称数组,它对应的值会被”to”中对应的textview

                   显示 

        to          显示"from"数组中map键对应的值组件id数组

     示例代码:

List> data = newArrayList>();        for(int i= 0;i <40;i++)        {            Map map = newHashMap();            map.put("name", "张飞");            map.put("age", "30");            data.add(map);                        Map map1 = newHashMap();            map1.put("name", "李小龙");            map1.put("age", "34");            data.add(map1);                        Map map2 = newHashMap();            map2.put("name", "李连杰");            map2.put("age", "50");            data.add(map2);        }                SimpleAdapter simpleAdapter= new SimpleAdapter(mContext, data, R.layout.item_simpleadapter, new String[]{"name","age"}, newint[]{R.id.tv_name,R.id.tv_age});               lv_arr.setAdapter(simpleAdapter);

     效果图:

    

    

    ■SimpleCursorAdapter

         这个适配器可以绑定数据库查询结果集的Cursor对象的数据。

Cursor cr= useru.qurryUser1();      //直接获得数据库的数据SimpleCursorAdapter adapter = newSimpleCursorAdapter(mContext, R.layout.userinfo_layout, cr, new String[]{"_id","name","phone"}, new int[]{R.id.tv_id,R.id.tv_name,R.id.tv_phone});lv_user.setAdapter(adapter);

    说了这么多适配器,其实所有的适配器目的只能一个:为ListView的item指定视图,为

  ListView中的item视图中的组件绑定数据。


  ListView就是一个典型的MVC模型

    m:    javabean数据    

    v:    ListView

    c:    Adapter

杂项:

  1. 图片用Drawable类来表示,获取通过context.getResources().getDrawale(R.drawable.XXX);

  2. 注意资源文件不要用中文、数字、大写字母来命名,否则可能R文件不能正确的自动生成,或不能自动生成。

  3. weight:权重

    width不确定要设置为0,水平等分

    height不确定要设置为0  ,垂直等分。

4.sqlite3    在/system/xbin


      

        

        

更多相关文章

  1. mybatisplus的坑 insert标签insert into select无参数问题的解决
  2. python起点网月票榜字体反爬案例
  3. 《Android开发从零开始》——25.数据存储(4)
  4. Android系统配置数据库注释(settings.db)
  5. Android中不同应用间实现SharedPreferences数据共享
  6. android图表ichartjs
  7. Android内容提供者源码
  8. android SharedPreferences
  9. Android(安卓)Paging组件Demo

随机推荐

  1. 导入color文件中的颜色值 android
  2. Android之打开和关闭软键盘
  3. 4.8.4 在Android(安卓)中fragment中获取
  4. android http中请求访问添加 cookie
  5. android 常用调用系统功能
  6. android 图片圆角 遮罩_安卓圆角、背景遮
  7. Android运行时动态全屏以及旋转屏幕时不
  8. android 弹悬浮窗
  9. 2012年第1周国内Android应用下载排行榜
  10. [Learn Android(安卓)Studio 汉化教程]第