安卓day27数据存储和界面展现 测试 sqlite 事务 listview 适配器 对话框

一、排坑

单元测试类

SQLiteDatabase

重复定义

android Studio里查看db文件

循环体内输出log只显示一条

DB Browse表内只显示类型char[10]

字符串用varchar即可正常显示

更改后需刷新

二、单元测试

  • 黑盒测试
    • 测试逻辑业务
  • 白盒测试

    • 测试逻辑方法
  • 根据测试粒度

    • 方法测试:function test
    • 单元测试:unit test
    • 集成测试:integration test
    • 系统测试:system test
  • 根据测试暴力程度

    • 冒烟测试:smoke test
    • 压力测试:pressure test
public class TestCase extends AndroidTestCase {
    public void test(){
        int result = Utils.add(3, 5);
        //断言:用来检测实际值与期望值是否一致
        assertEquals(8, result);
    }
    public void test2(){
        Utils.chuyi(2, 1);
    }
}
public class Utils {

    public static int add(int i, int j){
        return i + j;
    }
    
    public static void chuyi(int i, int j){
        int result = i / j;
    }
}

androidTest是整合测试。可以运行在设备或虚拟设备上.需要编译打包为APK在设备上运行,可以实时查看细节.
test是单元测试类.运行在本地开发机上,可以脱离Android运行时环境,速度快.

三、SQLite数据库

public class MyOpenHelper extends SQLiteOpenHelper {
    private static final int VERSION=1;
    private static final String DBNAME="people.db";
    private static final String TAG = "MyOpenHelper";
    public MyOpenHelper(Context context) {
        super(context, DBNAME, null, VERSION);
        // TODO Auto-generated constructor stub
    }
    //数据库创建时,此方法会调用
    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL("create table person(_id integer primary key autoincrement, name varchar(10), salary varchar(20), phone integer(20))");
        Log.e(TAG, "onCreate: " );
    }
    //数据库升级时,此方法会调用
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        Log.e(TAG, "onUpgrade: " );
    }
}
public class MainActivity extends Activity {
    private SQLiteDatabase db;
    private MyOpenHelper oh;
    private static final String TAG = "MainActivity";
    private TextView tv1;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tv1=(TextView)findViewById(R.id.tv1);
        oh = new MyOpenHelper(MainActivity.this);
        //如果数据库不存在,先创建数据库,再获取可读可写的数据库对象,如果数据库存在,就直接打开
        insert();
        delete();
        update();
        select();
    }
    public void insert(){
        db = oh.getWritableDatabase();
        db.execSQL("insert into person (name, salary, phone)values(?, ?, ?)", new Object[]{"小志2", "14000", 13888});
        db.execSQL("insert into person (name, salary, phone)values(?, ?, ?)", new Object[]{"小志", "14000", 13888});
        db.execSQL("insert into person (name, salary, phone)values(?, ?, ?)", new Object[]{"小志3", "14000", 13888});
    }
    public void delete(){
        db = oh.getWritableDatabase();
        db.execSQL("delete from person where name = ?", new Object[]{"小志"});
    }

    public void update(){
        db = oh.getWritableDatabase();
        db.execSQL("update person set phone = ? where name = ?", new Object[]{186666, "小志3"});
    }

    public void select(){
        db = oh.getWritableDatabase();
        Cursor cursor = db.rawQuery("select name, salary from person", null);
        StringBuilder sb=new StringBuilder();
        while(cursor.moveToNext()){
            //通过列索引获取列的值
            String name = cursor.getString(cursor.getColumnIndex("name"));
            String salary = cursor.getString(1);
            sb.append(name + ":  " + salary + ";\n");
            //Log.e(TAG, name + ":  " + salary + ";\n");
            //System.out.println(name + ";" + salary);
        }
        Log.e(TAG, sb.toString());
    }
}

使用api实现增删改查

    public void insertApi(){
        db = oh.getWritableDatabase();
        //把要插入的数据全部封装至ContentValues对象
        ContentValues values = new ContentValues();
        values.put("name", "游天龙");
        values.put("phone", "15999");
        values.put("salary", 16000);
        db.insert("person", null, values);
    }

    public void deleteApi(){
        db = oh.getWritableDatabase();
        int i = db.delete("person", "name = ? and _id = ?", new String[]{"小志3", "4"});
        Log.e(TAG, i+"");
    }

    public void updateApi(){
        db = oh.getWritableDatabase();
        ContentValues values = new ContentValues();
        values.put("salary", 26000);
        int i = db.update("person", values, "name = ?", new String[]{"游天龙"});
        Log.e(TAG, i+"");
    }

    public void selectApi(){
        db = oh.getWritableDatabase();
        Cursor cursor = db.query("person", null, null, null, null, null, null, null);
        StringBuilder sb=new StringBuilder();
        while(cursor.moveToNext()){
            String name = cursor.getString(cursor.getColumnIndex("name"));
            String phone = cursor.getString(cursor.getColumnIndex("phone"));
            String salary = cursor.getString(cursor.getColumnIndex("salary"));
            sb.append(name + ";" + phone + ";" + salary+"\n");
        }
        Log.e(TAG, sb.toString());
    }

事务

  • 保证多条SQL语句要么同时成功,要么同时失败
  • 最常见案例:银行转账
    public void transaction(){
        db = oh.getWritableDatabase();
        try{
            //开启事务
            db.beginTransaction();
            ContentValues values = new ContentValues();
            values.put("salary", 12000);
            int result1=db.update("person", values, "name = ?", new String[]{"小志2"});

            values.clear();
            values.put("salary", 86000);
            int result2 = db.update("person", values, "name = ?", new String[]{"游天龙"});

            //int i = 3/0;
            //设置 事务执行成功
            //db.setTransactionSuccessful();
            if (result1>0 && result2>0) {
                db.setTransactionSuccessful(); // 事务默认是失败的,要设置成功,否则数据不会修改
                Log.e(TAG, "成功: ");
            }
        }
        catch (Exception e){
            Log.e(TAG, e.getMessage());
        }
        finally{
            //关闭事务,同时提交,如果已经设置事务执行成功,那么sql语句就生效了,反之,sql语句回滚
            db.endTransaction();
        }
    }

把数据库的数据显示至屏幕

public class Person {
    private String _id;
    private String name;
    private String phone;
    private String salary;
    
    public String get_id() {
        return _id;
    }
    public void set_id(String _id) {
        this._id = _id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getPhone() {
        return phone;
    }
    public void setPhone(String phone) {
        this.phone = phone;
    }
    public String getSalary() {
        return salary;
    }
    public void setSalary(String salary) {
        this.salary = salary;
    }
    @Override
    public String toString() {
        return name + ", " + phone + ", " + salary;
    }
    public Person(String _id, String name, String phone, String salary) {
        super();
        this._id = _id;
        this.name = name;
        this.phone = phone;
        this.salary = salary;
    }
}
public class ShowData extends AppCompatActivity {
    private MyOpenHelper oh;
    private SQLiteDatabase db;
    private List<Person> personList;
    private LinearLayout l1;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_show_data);

        l1=(LinearLayout)findViewById(R.id.l1);
        personList = new ArrayList<Person>();
        //把数据库的数据查询出来
        oh = new MyOpenHelper(this);
        db =  oh.getWritableDatabase();
        Cursor cursor = db.query("person", null, null, null, null, null, null, null);
        while(cursor.moveToNext()){
            String _id = cursor.getString(0);
            String name = cursor.getString(1);
            String salary = cursor.getString(2);
            String phone = cursor.getString(3);

            Person p = new Person(_id, name, phone, salary);
            personList.add(p);
        }
        //把数据显示至屏幕
        for (Person p : personList) {
            //1.集合中每有一条元素,就new一个textView
            TextView tv = new TextView(this);
            //2.把人物的信息设置为文本框的内容
            tv.setText(p.toString());
            tv.setTextSize(18);
            //3.把textView设置为线性布局的子节点
            l1.addView(tv);
        }
    }
}

四、ListView和BaseAdapter

  • 就是用来显示一行一行的条目的
  • MVC结构
    • M:model模型层,要显示的数据 ————people集合
    • V:view视图层,用户看到的界面 ————ListView
    • c:control控制层,操作数据如何显示 ————adapter对象
  • 每一个条目都是一个View对象
public class ShowData2 extends AppCompatActivity {
    private MyOpenHelper oh;
    private SQLiteDatabase db;
    private List<Person> personList;
    private ListView lv;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_show_data2);

        lv=(ListView) findViewById(R.id.lv);
        personList = new ArrayList<Person>();
        //把数据库的数据查询出来
        oh = new MyOpenHelper(this);
        db =  oh.getWritableDatabase();
        Cursor cursor = db.query("person", null, null, null, null, null, null, null);
        while(cursor.moveToNext()){
            String _id = cursor.getString(0);
            String name = cursor.getString(1);
            String salary = cursor.getString(2);
            String phone = cursor.getString(3);

            Person p = new Person(_id, name, phone, salary);
            personList.add(p);
        }
        lv.setAdapter(new MyAdapter());
    }

    class MyAdapter extends BaseAdapter {
        //系统调用,用来获知集合中有多少条元素
        @Override
        public int getCount() {
            return personList.size();
        }
        //由系统调用,获取一个View对象,作为ListView的条目
        //position:本次getView方法调用所返回的View对象,在listView中是处于第几个条目,那么position的值就是多少
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            Person p = personList.get(position);

//            TextView tv = new TextView(MainActivity.this);
            System.out.println("getView调用:" + position + ";" + convertView);
//            tv.setText(p.toString());
//            tv.setTextSize(18);
            View v = null;
            //判断条目是否有缓存
            if(convertView == null){
                //把布局文件填充成一个View对象
                v = View.inflate(ShowData2.this, R.layout.item_listview, null);
            }
            else{
                v = convertView;
            }
            //获取布局填充器对象
//            LayoutInflater inflater = LayoutInflater.from(MainActivity.this);
//            使用布局填充器填充布局文件
//            View v2 = inflater.inflate(R.layout.item_listview, null);

//            LayoutInflater inflater2 = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
//            View v3 = inflater2.inflate(R.layout.item_listview, null);
            //通过资源id查找组件,注意调用的是View对象的findViewById
            TextView tv_name = (TextView) v.findViewById(R.id.tv_name);
            tv_name.setText(p.getName());
            TextView tv_phone = (TextView) v.findViewById(R.id.tv_phone);
            tv_phone.setText(p.getPhone());
            TextView tv_salary = (TextView) v.findViewById(R.id.tv_salary);
            tv_salary.setText(p.getSalary());
            return v;
        }
        @Override
        public Object getItem(int position) {
            return null;
        }
        @Override
        public long getItemId(int position) {
            return 0;
        }
    }
}

 

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
    
    <TextView 
        android:id="@+id/tv_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="名字"
        android:textSize="25sp"
        />
    <LinearLayout 
        android:layout_alignParentRight="true"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        >
        <TextView 
            android:id="@+id/tv_phone"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="号码"
        />
        <TextView 
            android:id="@+id/tv_salary"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="工资"
        />
    </LinearLayout>
</RelativeLayout>

 

  • 屏幕上能显示多少个条目,getView方法就会被调用多少次,屏幕向下滑动时,getView会继续被调用,创建更多的View对象显示至屏幕

    条目的缓存

  • 当条目划出屏幕时,系统会把该条目缓存至内存,当该条目再次进入屏幕,系统在重新调用getView时会把缓存的条目作为convertView参数传入,但是传入的条目不一定是之前被缓存的该条目,即系统有可能在调用getView方法获取第一个条目时,传入任意一个条目的缓存

 

五、适配器

1.什么是适配器?

   适配器:在安卓中,顾名思义就是把数据变成符合界面风格的形式,并且通过ListView显示出来。也就是说适配器是数据和界面之间的桥梁。

   适配器在数据库中的数据(后台)和显示页面(前端)中充当一个转换器的角色,数据库中的数据(如数组,链表,数据库,集合等)通过适配器变成类手机页面能够正常显示的数据。可以看作是界面数据绑定的一种理解。假设把数据、适配器和ListView(页面)比喻成一个MVC模式的话,那么适配器(Adapter)在这中间就充当了Controller的角色。

2.为什么对象设置数据源   

   一般是为ListView提供数据的转换,当然GridView[网格视图]、Spinner[下拉列表]、Gallery[画廊]、ViewPage等都需要使用适配器来为其设置数据源。

ArrayAdapter

    public void arrayAdapter(){
        String[] objects = new String[]{
                "小志",
                "小志的儿子",
                "萌萌"
        };
        lv = (ListView) findViewById(R.id.lv);
        lv.setAdapter(new ArrayAdapter<String>(this, R.layout.item_listview, R.id.tv_name, objects));
    }

SimpleAdapter

    public void simpleadapter(){
        //集合中每个元素都包含ListView条目需要的所有数据,该案例中每个条目需要一个字符串和一个整型,所以使用一个map来封装这两种数据
        List<Map<String, Object>> data = new ArrayList<Map<String,Object>>();
        Map<String, Object> map1 = new HashMap<String, Object>();
        map1.put("photo", R.drawable.photo1);
        map1.put("name", "小志的儿子");
        data.add(map1);

        Map<String, Object> map2 = new HashMap<String, Object>();
        map2.put("photo", R.drawable.photo2);
        map2.put("name", "小志");
        data.add(map2);

        Map<String, Object> map3 = new HashMap<String, Object>();
        map3.put("photo", R.drawable.photo3);
        map3.put("name", "赵帅哥");
        data.add(map3);

        lv = (ListView) findViewById(R.id.lv);
        lv.setAdapter(new SimpleAdapter(this, data, R.layout.item_listview, new String[]{"photo", "name"}, new int[]{R.id.iv_photo, R.id.tv_name}));
    }

六、对话框

public class MainActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
    public void click1(View v){
        Builder builder = new Builder(this);
        //设置图标
        builder.setIcon(android.R.drawable.alert_dark_frame);
        //设置标题
        builder.setTitle("欲练此功必先自宫");
        //设置文本
        builder.setMessage("李志平,想清楚哦");
        
        //设置确定按钮
        builder.setPositiveButton("确定", new OnClickListener() {
            
            @Override
            public void onClick(DialogInterface dialog, int which) {
                Toast.makeText(MainActivity.this, "感谢使用本软件,再见", 0).show();
            }
        });
        
        //设置取消按钮
        builder.setNegativeButton("取消", new OnClickListener() {
            
            @Override
            public void onClick(DialogInterface dialog, int which) {
                Toast.makeText(MainActivity.this, "若不自宫,一定不成功", 0).show();
            }
        });
        //使用创建器,生成一个对话框对象
        AlertDialog ad = builder.create();
        ad.show();
    }

    public void click2(View v){
        Builder builder = new Builder(this);
        builder.setTitle("请选择性别");
        final String[] items = new String[]{
                "男",
                "女"
        };
        
        builder.setSingleChoiceItems(items, -1, new OnClickListener() {
            
            //which:用户所选的条目的下标
            //dialog:触发这个方法的对话框
            @Override
            public void onClick(DialogInterface dialog, int which) {
                Toast.makeText(MainActivity.this, "您选择的是:" + items[which], 0).show();
                //关闭对话框
                dialog.dismiss();
            }
        });
        builder.show();
    }
    
    public void click3(View v){
        Builder builder = new Builder(this);
        builder.setTitle("请选择您觉得帅的人");
        final String[] items = new String[]{
                "侃哥",
                "赵帅哥",
                "赵老师",
                "赵师兄"
        };
        final boolean[] checkedItems = new boolean[]{
                true,
                true,
                false,
                false
                
        };
        
        builder.setMultiChoiceItems(items, checkedItems, new OnMultiChoiceClickListener() {
            
            //which:用户点击的条目的下标
            //isChecked:用户是选中该条目还是取消该条目
            @Override
            public void onClick(DialogInterface dialog, int which, boolean isChecked) {
                checkedItems[which] = isChecked;
                
            }
        });
        
        //设置一个确定按钮
        builder.setPositiveButton("确定", new OnClickListener() {
            
            @Override
            public void onClick(DialogInterface dialog, int which) {
                String text = "";
                for(int i = 0; i < 4; i++){
                    text += checkedItems[i]? items[i] + "," : "";
                }
                Toast.makeText(MainActivity.this, text, 0).show();
                dialog.dismiss();
            }
        });
        builder.show();
    }
}

 

posted @ 2019-02-27 19:19  辉钼矿  阅读(245)  评论(0编辑  收藏  举报