• 用Spinner + SQLite实现省市县三级联动


    1. 建立省市县行政区划代码(截止2010年12月31日)数据表

    CREATE TABLE xzqhdm (
      _id INTEGER PRIMARY KEY,
      code NUMERIC,
      region TEXT,
      parent_code NUMERIC
    );

    parent_code指上一级的行政区划代码,省属于最上级的行政单位,设置它的区划代码为999999。

    insert into xzqhdm values(NULL, 110000, "北京市", 999999);
    insert into xzqhdm values(NULL, 110100, "市辖区", 110000);
    insert into xzqhdm values(NULL, 110101, "东城区", 110100);
    insert into xzqhdm values(NULL, 110102, "西城区", 110100);
    insert into xzqhdm values(NULL, 110103, "崇文区", 110100);
    insert into xzqhdm values(NULL, 110104, "宣武区", 110100);
    insert into xzqhdm values(NULL, 110105, "朝阳区", 110100);
    insert into xzqhdm values(NULL, 110106, "丰台区", 110100);
    ...
    insert into xzqhdm values(NULL, 659001, "石河子市", 659000);
    insert into xzqhdm values(NULL, 659002, "阿拉尔市", 659000);
    insert into xzqhdm values(NULL, 659003, "图木舒克市", 659000);
    insert into xzqhdm values(NULL, 659004, "五家渠市", 659000);
    

     

    2. SQLite数据库的操作
      如果应用使用到了SQLite数据库,在用户初次使用应用时,需要创建应用使用到的数据库表结构及添加一些初始化记录,另外在软件升级的时候,也需要对数据表结构进行更新。Android系统为我们提供了一个名为SQLiteOpenHelper的类,这是一个抽象类,该类用于对数据库版本进行管理,有两个重要的方法,分别是onCreate()和onUpgrade()。

      当调用SQLiteOpenHelper的getWritableDatabase()或getReadableDatabase()方法获取数据库实例时,如果数据库不存在,Android系统会自动生成一个数据库文件,接着调用onCreate()方法,onCreate()方法在初次生成数据库时才会被调用,在onCreate()方法里可以生成数据库表结构及添加一些应用使用到的初始化数据。onUpgrade()方法在数据库的版本发生变化时会被调用,数据库的版本是由程序员控制的,假设数据库现在的版本是1,由于业务的需要,修改了数据库表的结构,这时候就需要升级软件,升级软件时希望更新用户手机里的数据库表结构,为了实现这一目的,可以把原来的数据库版本设置为2(或其他数值),并且在onUpgrade()方法里面实现表结构的更新。当软件的版本升级次数比较多,这时在onUpgrade()方法里面可以根据原版号和目标版本号进行判断,然后作出相应的表结构及数据更新。

      SQLiteDatabase类则封装了一些操作数据库的常用API,使用该类可以完成对数据进行CRUD操作。主要是execSQL()和rawQuery()方法。execSQL()方法可以执行insert、delete、update和CREATE TABLE之类有更改行为的SQL语句; rawQuery()方法可以执行select语句。SQLiteDatabase还专门提供了对应于CRUD的操作方法: insert()、delete()、update()和query()。

    问题:
      如何将SQLite数据库与apk文件一起发布?
      可以将数据库文件复制到res\raw目录中,所有在res\raw目录中的文件不会被压缩,这样可以直接提取该目录中的文件。

    如何打开res\raw目录中的数据库文件?
    不能直接打开res\raw目录中的数据库文件,需要在程序第一次启动时将该文件复制到手机内存或SD卡中,然后再打开。

    import android.app.Activity;
    import android.database.Cursor;
    import android.os.Bundle;
    import android.view.View;
    import android.widget.AdapterView;
    import android.widget.Spinner;
    import android.widget.AdapterView.OnItemSelectedListener;
    import android.widget.SpinnerAdapter;
    import android.widget.Toast;
    
    public class MainActivity extends Activity {
    
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
    
            loadSpinner();
        }
    
        private void loadSpinner() {
            Spinner provinceSpinner = (Spinner)findViewById(R.id.province_spinner);
            provinceSpinner.setPrompt("请选择省份");
            provinceSpinner.setAdapter(getSpinnerAdapter(999999));
            provinceSpinner.setOnItemSelectedListener(new OnItemSelectedListener() {
                @Override
                public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
                    Spinner citySpinner = (Spinner)findViewById(R.id.city_spinner);
                    citySpinner.setPrompt("请选择城市");
                    citySpinner.setAdapter(getSpinnerAdapter(id));
                    citySpinner.setOnItemSelectedListener(new OnItemSelectedListener() {
                        @Override
                        public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
                            Spinner countySpinner = (Spinner)findViewById(R.id.county_spinner);
                            countySpinner.setPrompt("请选择县区");
                            countySpinner.setAdapter(getSpinnerAdapter(id));
                            countySpinner.setOnItemSelectedListener(new OnItemSelectedListener() {
                                @Override
                                public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
                                    Cursor cursor = (Cursor)parent.getSelectedItem();
                                    if (cursor != null) {
                                        String country = cursor.getString(cursor.getColumnIndex("region"));
                                        Toast.makeText(MainActivity.this, country + " " + id, Toast.LENGTH_LONG).show();
                                    }
                                }
    
                                @Override
                                public void onNothingSelected(AdapterView<?> parent) {
                                }
                            });
                        }
    
                        @Override
                        public void onNothingSelected(AdapterView<?> parent) {
                        }
                    });
                }
    
                @Override
                public void onNothingSelected(AdapterView<?> parent) {
                }
            });
        }
    
        private SpinnerAdapter getSpinnerAdapter(long code) {
            DBHelper helper = DBHelper.getInstance(this);
            SpinnerAdapter adapter = helper.getListByParentCode(this, String.valueOf(code));
            helper.close();
            return adapter;
        }
    }
    

      

    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    
    import android.content.Context;
    import android.database.Cursor;
    import android.database.sqlite.SQLiteDatabase;
    import android.database.sqlite.SQLiteException;
    import android.database.sqlite.SQLiteOpenHelper;
    import android.util.Log;
    import android.widget.SimpleCursorAdapter;
    
    public class DBHelper extends SQLiteOpenHelper {
        private static String DB_PATH = "/data/data/name.dohkoos.linkage/databases/";
        private static String DB_NAME = "xzqh.db";
        private static DBHelper databaseHelper;
        private static SQLiteDatabase db;
    
        private Context context;
    
        private DBHelper(Context context) {
            super(context, DB_NAME, null, 1);
            this.context = context;
        }
    
        public static DBHelper getInstance(Context context) {
            if (databaseHelper == null) {
                databaseHelper = new DBHelper(context);
                databaseHelper.openDataBase();
    
                if (db == null) {
                    try {
                        db = databaseHelper.getWritableDatabase();
                        databaseHelper.copyDatabase();
                    }
                    catch (Exception e) {
                        Log.d("DBHelper", "Error in database creation");
                    }
    
                    databaseHelper.openDataBase();
                }
            }
            return databaseHelper;
        }
    
        private void copyDatabase() throws IOException {
            InputStream is = context.getResources().openRawResource(R.raw.xzqh);
            OutputStream os = new FileOutputStream(DB_PATH + DB_NAME);
            byte[] buffer = new byte[1024];
            int length;
            while ((length = is.read(buffer)) > 0) {
                os.write(buffer, 0, length);
            }
    
            os.flush();
            os.close();
            is.close();
        }
    
        private void openDataBase() {
            try {
                db = SQLiteDatabase.openDatabase(
                        DB_PATH + DB_NAME,
                        null,
                        SQLiteDatabase.OPEN_READONLY | SQLiteDatabase.NO_LOCALIZED_COLLATORS);
            } catch (SQLiteException e) {
                // database does't exist yet
            }
        }
    
        public SimpleCursorAdapter getListByParentCode(Context context, String parentCode) {
            SimpleCursorAdapter list = null;
            DBHelper dHelper = new DBHelper(context);
            SQLiteDatabase db = dHelper.getReadableDatabase();
            Cursor cursor = db.rawQuery("select code as _id, region from xzqhdm where parent_code = ?", new String[] {parentCode});
            if (cursor.getCount() != 0) {
                list = new SimpleCursorAdapter(context,
                        android.R.layout.simple_spinner_item,
                        cursor,
                        new String[] {"region"},
                        new int[] {android.R.id.text1});
                list.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
            }
            return list;
        }
    
        @Override
        public synchronized void close() {
            if (db != null) {
                db.close();
            }
            super.close();
        }
    
        @Override
        public void onCreate(SQLiteDatabase db) {
        }
    
        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        }
    }

      在代码实现时遇到的难题是如何在选中region的同时得到对应的code。网上有教程说定制自己的adapter,重写bingView,不过有多个spinner就需要声明多个全局变量;还有教程指出可以直接往adapter中传递对象(实现一个类,将code和region作为字段),然后重写对象的toString()方法。后来受到这个帖子的启发,修改了rawQuery中的select语句得以实现Spinner控件中的键值绑定。
    原来的select语句是:

     
    select _id, code, region from xzqhdm where parent_code = ?

      因为传入到CursorAdapter中的Cursor结果集必须包含有列名为_id的列,否则CursorAdapter将不会起作用。而code可以被看作是整数,那么只需要将选出的code当作_id就行了,根据这个想法写出的select语句如下:

     
    select code as _id, region from xzqhdm where parent_code = ?

      这样,但触发Spinner上的ItemSelected事件时就可以通过最后一个参数id得到当前的code了。

    写这篇文章的时候同时也在调试着代码,突然发现其实不需要改写select语句也是可以实现键值绑定的。只要在onItemSelected()方法中使用如下代码就可以取得相应的值了:

    Cursor cursor = (Cursor)parent.getSelectedItem();
    if (cursor != null) {
        int code = cursor.getString(cursor.getColumnIndex("code"));
        String country = cursor.getString(cursor.getColumnIndex("region"));
    }
    
  • 相关阅读:
    【题解】 保镖 半平面交
    【题解】 CF1492E Almost Fault-Tolerant Database 暴力+复杂度分析
    【题解】 闷声刷大题 带悔贪心+wqs二分
    【题解】 「WC2021」表达式求值 按位+表达式树+树形dp LOJ3463
    EasyNVR及EasyRTC平台使用Go语言项目管理GoVendor和gomod的使用总结
    一天一个开发技巧:如何基于WebRTC建立P2P通信?
    HTML5如何实现直播推流?值得学习一下!
    java后端学习-第一部分java基础:Scanner的基本使用
    java后端学习-第一部分java基础:三元运算符、运算符优先级、标识符、关键字和保留字
    java后端学习-第一部分java基础:赋值运算符
  • 原文地址:https://www.cnblogs.com/DswCnblog/p/2807732.html
Copyright © 2020-2023  润新知