• 快速入门GreenDao框架并实现增删改查案例


    该文章是在QiTang博客基础上改造而成,文章实现思路并非原创,具体参考链接请读者查看:http://itangqi.me/2015/07/26/orm-greendao-summary/

           大家的项目中不可避免的使用到SQLite,为此我们要花费心思编写一个增删改查框架。而一个好的ORM框架则能够给我们带来极大的方便,今天给大家讲解一个非常火热的ORM-GreenDao。

    基本概念

    GreenDao官网地址:http://greenrobot.org/greendao/

    官网对GreenDao的介绍:

           greenDAO is an open source library for Android providing an easy-to-use interface to SQLite to help developers handle data efficiently – relieving developers from dealing with low-level database stuff and saving development time. SQLite is an awesome embedded relational database. Still, writing SQL and parsing query results are quite tedious and time-consuming tasks. greenDAO frees you from these by mapping Java objects to database tables (often called ORM). This way you can store, update, delete, and query for Java objects using a simple object oriented API.

           简单的说就是:greenDAO 是一个将对象映射到 SQLite 数据库中的轻量且快速的 ORM 解决方案。

    这里写图片描述

    greenDAO 设计的主要目标

    • 一个精简的库
    • 性能最大化
    • 内存开销最小化
    • 易于使用的 APIs
    • 对 Android 进行高度优化

    greenDAO 设计的主要特点

    • greenDAO 性能远远高于同类的 ORMLite,具体测试结果可见官网
    • greenDAO 支持 protocol buffer(protobuf) 协议数据的直接存储,如果你通过 protobuf
      协议与服务器交互,将不需要任何的映射。
    • 与 ORMLite 等使用注解方式的 ORM 框架不同,greenDAO 使用「Code
      generation」的方式,这也是其性能能大幅提升的原因。

    Dao项目代码生成

    这里写图片描述

    核心类介绍

    这里写图片描述

    DaoMaster:一看名字就知道它是Dao中的最大的官了。它保存了sqlitedatebase对象以及操作DAO classes(注意:不是对象)。其提供了一些创建和删除table的静态方法,其内部类OpenHelper和DevOpenHelper实现了SQLiteOpenHelper并创建数据库的框架。
    DaoSession:会话层。操作具体的DAO对象(注意:是对象),比如各种getter方法。
    XXXDao:实际生成的某某DAO类,通常对应具体的java类,比如NoteDao等。其有更多的权限和方法来操作数据库元素。
    XXXEntity:持久的实体对象。通常代表了一个数据库row的标准java properties。

    了解了基本概念后我们开始动手完成一个增删改查的项目案例。

    实现过程

    1.在 Android 工程中配置「greenDao Generator」模块

    在 .src/main 目录下新建一个与 java 同层级的「java-gen」目录,用于存放由 greenDAO 生成的 Bean、DAO、DaoMaster、DaoSession 等类。

    这里写图片描述

    这里写图片描述

    配置 Android 工程(app)的 build.gradle,如图分别添加 sourceSets 与 dependencies

    这里写图片描述

    sourceSets {
            main {
                java.srcDirs = ['src/main/java', 'src/main/java-gen']
            }
        }
    compile 'de.greenrobot:greendao:1.3.7'

    1.新建「greenDAO Generator」模块 (纯 Java 工程)

    通过 File -> New -> New Module -> Java Library -> 填写相应的包名与类名 -> Finish

    这里写图片描述

    这里写图片描述

    配置 castielgreendaolb 工程的 build.gradle,添加 dependencie

    这里写图片描述

    注意主句话,配置输出路径

    def outputDir = "../app/src/main/java-gen"

    接着,编写 CastielGreenDao类,注意: 我们的 Java 工程只有一个类,它的内容决定了「GreenDao Generator」的输出,你可以在这个类中通过对象、关系等创建数据库结构,下面我将以注释的形式详细讲解代码内容。

    这里写图片描述

    package com.castiel.dao;
    
    import de.greenrobot.daogenerator.DaoGenerator;
    import de.greenrobot.daogenerator.Entity;
    import de.greenrobot.daogenerator.Schema;
    
    public class CastielGreenDao {
        public static void main(String args[]) throws Exception {
            // 创建了一个用于添加实体(Entity)的模式(Schema)对象。
            // 两个参数分别代表:数据库版本号与自动生成代码的包路径。
            Schema schema = new Schema(1, "greendao");
            schema.setDefaultJavaPackageDao("com.castiel.dao");
    
            // 一旦你拥有了一个 Schema 对象后,你便可以使用它添加实体(Entities)了。
            addNote(schema);
    
            // 最后我们将使用 DAOGenerator 类的 generateAll() 方法自动生成代码,此处你需要根据自己的情况更改输出目录(既之前创建的 java-gen)。
            new DaoGenerator().generateAll(schema, args[0]);
        }
    
        /**
         * @param schema
         */
        private static void addNote(Schema schema) {
            // 一个实体(类)就关联到数据库中的一张表,此处表名为「Student」(既类名)
            Entity note = schema.addEntity("Student");
            // 你也可以重新给表命名
            // note.setTableName("Student2");
    
            // greenDAO 会自动根据实体类的属性值来创建表字段,并赋予默认值
            // 接下来你便可以设置表中的字段:
            // 与在 Java 中使用驼峰命名法不同,默认数据库中的命名是使用大写和下划线来分割单词的。
            note.addIdProperty();
            note.addStringProperty("sName").notNull();
            note.addStringProperty("sAge");
            note.addStringProperty("sSex");
            note.addStringProperty("sClass");
        }
    }

    3.生成 DAO 文件(数据库)

    执行 generator 工程,如一切正常,你将会在控制台看到如下日志,并且在主工程「java-gen」下会发现生成了DaoMaster、DaoSession、StudentDao、Student共4个类文件。

    greenDAO Generator
    Copyright 2011-2013 Markus Junginger, greenrobot.de. Licensed under GPL V3.
    This program comes with ABSOLUTELY NO WARRANTY
    Processing schema version 1...
    Written C:UsershuangshuaiAndroidStudioProjectsCastielGreenDaoappsrcmainjava-gencomcastieldaoStudentDao.java
    Written C:UsershuangshuaiAndroidStudioProjectsCastielGreenDaoappsrcmainjava-gengreendaoStudent.java
    Written C:UsershuangshuaiAndroidStudioProjectsCastielGreenDaoappsrcmainjava-gencomcastieldaoDaoMaster.java
    Written C:UsershuangshuaiAndroidStudioProjectsCastielGreenDaoappsrcmainjava-gencomcastieldaoDaoSession.java
    Processed 1 entities in 153ms
    
    BUILD SUCCESSFUL

    构建Android项目实现增删改查

    先来张项目结构全景图

    这里写图片描述

    再来张项目效果图

    这里写图片描述

    在官网中,提供了一段核心初始化代码,推荐将该段代码放在Application中

    helper = new DaoMaster.DevOpenHelper( this, "notes-db", null);
    db = helper.getWritableDatabase();
    daoMaster = new DaoMaster(db);
    daoSession = daoMaster.newSession();
    noteDao = daoSession.getNoteDao();

    即:在自己的Application中先创建了一个SQLiteOpenHelper并创建连接到一个具体数据库;再根据具体的datebase创建一个master对象用于;最后通过master创建一个数据库的会话操作。

    package com.castiel.dao;
    
    import android.app.Application;
    import android.database.sqlite.SQLiteDatabase;
    
    /**
     * Created by huangshuai on 2016/5/11.
     * Email:huangshuai@wooyun.org
     */
    public class BaseApplication extends Application {
        public DaoSession daoSession;
        public SQLiteDatabase db;
        public DaoMaster.DevOpenHelper helper;
        public DaoMaster daoMaster;
    
        @Override
        public void onCreate() {
            super.onCreate();
            setupDatabase();
        }
    
        private void setupDatabase() {
            // 通过 DaoMaster 的内部类 DevOpenHelper,你可以得到一个便利的 SQLiteOpenHelper 对象。
            // 可能你已经注意到了,你并不需要去编写「CREATE TABLE」这样的 SQL 语句,因为 greenDAO 已经帮你做了。
            // 注意:默认的 DaoMaster.DevOpenHelper 会在数据库升级时,删除所有的表,意味着这将导致数据的丢失。
            // 所以,在正式的项目中,你还应该做一层封装,来实现数据库的安全升级。
            helper = new DaoMaster.DevOpenHelper(this, "student", null);
            db = helper.getWritableDatabase();
            // 注意:该数据库连接属于 DaoMaster,所以多个 Session 指的是相同的数据库连接。
            daoMaster = new DaoMaster(db);
            daoSession = daoMaster.newSession();
        }
    
        public DaoSession getDaoSession() {
            return daoSession;
        }
    
        public SQLiteDatabase getDb() {
            return db;
        }
    
    }

    Activity具体实现

    package com.castiel.dao;
    
    import android.app.Activity;
    import android.app.Dialog;
    import android.database.sqlite.SQLiteDatabase;
    import android.os.Bundle;
    import android.text.TextUtils;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.widget.Button;
    import android.widget.EditText;
    import android.widget.ListView;
    import android.widget.Toast;
    
    import java.util.List;
    
    import de.greenrobot.dao.query.Query;
    import greendao.Student;
    
    /**
     * Created by huangshuai on 2016/5/11.
     * Email:huangshuai@wooyun.org
     * GreenDao增删改查实例
     */
    public class CastielActivity extends Activity implements StudentAdapter.AdapterEnterCallBack{
        // 初始化组件
        public static final String TAG = "WY";
        private List<Student> listStudent;
        private ListView list;
        private EditText etQureyName;
        StudentAdapter studentAdapter;
        private Button btnAdd,btnQurey;
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main_dao);
            list = (ListView) findViewById(R.id.dao_list);
            btnAdd = (Button) findViewById(R.id.btn_add);
            btnQurey = (Button) findViewById(R.id.btn_query);
            etQureyName = (EditText) findViewById(R.id.edit_query);
            listStudent = getStudentDao().loadAll();// 查询全部数据操作
            studentAdapter = new StudentAdapter(CastielActivity.this,listStudent);
    
            list.setAdapter(studentAdapter);
            studentAdapter.setCallback(this);
    
            btnAdd.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    dialogAdd();
                }
            });
    
            btnQurey.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    String curCondition = etQureyName.getText().toString().trim();
                    if (TextUtils.isEmpty(curCondition)) {
                        Toast.makeText(CastielActivity.this,"查询条件不能为空",Toast.LENGTH_SHORT).show();
                    } else {
                        // Query 类代表了一个可以被重复执行的查询
                        Query query = getStudentDao().queryBuilder()
                                .where(StudentDao.Properties.SName.eq(curCondition))
                                .build();
                        // 查询结果以 List 返回
                        List students = query.list();
                        Toast.makeText(CastielActivity.this,"有" + students.size() + "个条件符合",Toast.LENGTH_SHORT).show();
                    }
                    etQureyName.setText("");// 查询后重置条件
                }
            });
        }
    
        /**
         * 通过 BaseApplication 类提供的 getDaoSession() 获取具体 Dao
         * @return
         */
        private StudentDao getStudentDao() {
            return ((BaseApplication) this.getApplicationContext()).getDaoSession().getStudentDao();
        }
    
        /**
         * 通过 BaseApplication 类提供的 getDb() 获取具体 db
         * @return
         */
        private SQLiteDatabase getDb() {
            return ((BaseApplication) this.getApplicationContext()).getDb();
        }
    
        /**
         * 添加操作弹窗
         */
        protected void dialogAdd() {
            final Dialog dataDialog = new Dialog(CastielActivity.this,R.style.myDialogTheme);
            LayoutInflater curInfnfalater = LayoutInflater.from(this);
            View view = curInfnfalater.inflate(R.layout.my_dialog, null);
            Button b_ok,b_cancle;
            final EditText etName,etSex,etClass,etAge;
            etName = (EditText) view.findViewById(R.id.edit_name);
            etSex = (EditText) view.findViewById(R.id.edit_sex);
            etClass = (EditText) view.findViewById(R.id.edit_class);
            etAge = (EditText) view.findViewById(R.id.edit_age);
    
    
            b_ok = (Button) view.findViewById(R.id.btn_ok);
            b_ok.setOnClickListener(new Button.OnClickListener() {
                public void onClick(View v) {
                    Student ss = new Student(null,etName.getText().toString().trim(),etAge.getText().toString().trim(),etSex.getText().toString().trim(),etClass.getText().toString().trim());
                    getStudentDao().insert(ss);
                    studentAdapter.addData(ss);
                    dataDialog.dismiss();
                }
            });
            b_cancle = (Button) view.findViewById(R.id.btn_cancel);
            b_cancle.setOnClickListener(new Button.OnClickListener() {
                public void onClick(View v) {
                    dataDialog.dismiss();
                }
            });
    
    
            dataDialog.setContentView(view);
            dataDialog.show();
        }
    
        /**
         * 修改操作弹窗
         */
        protected void dialogModify(final Student curBean) {
            final Dialog dataDialog = new Dialog(CastielActivity.this,R.style.myDialogTheme);
            LayoutInflater curInfnfalater = LayoutInflater.from(this);
            View view = curInfnfalater.inflate(R.layout.my_dialog, null);
            Button b_ok,b_cancle;
            final EditText etName,etSex,etClass,etAge;
            etName = (EditText) view.findViewById(R.id.edit_name);
            etSex = (EditText) view.findViewById(R.id.edit_sex);
            etClass = (EditText) view.findViewById(R.id.edit_class);
            etAge = (EditText) view.findViewById(R.id.edit_age);
            etName.setText(curBean.getSName());
            etSex.setText(curBean.getSSex());
            etClass.setText(curBean.getSClass());
            etAge.setText(curBean.getSAge());
    
            b_ok = (Button) view.findViewById(R.id.btn_ok);
            b_ok.setOnClickListener(new Button.OnClickListener() {
                public void onClick(View v) {
                    Student ss = new Student(curBean.getId(),etName.getText().toString().trim(),etAge.getText().toString().trim(),etSex.getText().toString().trim(),etClass.getText().toString().trim());
                    getStudentDao().deleteByKey(curBean.getId());
                    getStudentDao().insert(ss);
                    studentAdapter.setData(getStudentDao().loadAll());
                    dataDialog.dismiss();
                }
            });
            b_cancle = (Button) view.findViewById(R.id.btn_cancel);
            b_cancle.setOnClickListener(new Button.OnClickListener() {
                public void onClick(View v) {
                    dataDialog.dismiss();
                }
            });
    
    
            dataDialog.setContentView(view);
            dataDialog.show();
        }
    
        /**菜单弹窗
         */
        protected void dialogMenu(final Student curBean) {
            final Dialog dataDialog = new Dialog(CastielActivity.this,R.style.myDialogTheme);
            LayoutInflater curInfnfalater = LayoutInflater.from(this);
            View view = curInfnfalater.inflate(R.layout.item_dialog, null);
            Button b_modify,b_del;
    
            b_modify = (Button) view.findViewById(R.id.btn_modify);
            b_modify.setOnClickListener(new Button.OnClickListener() {
                public void onClick(View v) {
                    dialogModify(curBean);
                    dataDialog.dismiss();
                }
            });
            b_del = (Button) view.findViewById(R.id.btn_del);
            b_del.setOnClickListener(new Button.OnClickListener() {
                public void onClick(View v) {
                    // 根据Id删除对应数据
                    getStudentDao().deleteByKey(curBean.getId());
                    studentAdapter.setData(getStudentDao().loadAll());
                    dataDialog.dismiss();
                }
            });
    
    
            dataDialog.setContentView(view);
            dataDialog.show();
        }
    
        @Override
        public void onEnterClick(Student bean) {
            dialogMenu(bean);
        }
    }

    列表相关Adapter

    package com.castiel.dao;
    
    import android.content.Context;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.BaseAdapter;
    import android.widget.LinearLayout;
    import android.widget.TextView;
    
    import java.util.List;
    
    import greendao.Student;
    
    /**
     * Created by huangshuai on 2016/5/11.
     * Email:huangshuai@wooyun.org
     * Student列表的Adapter
     */
    public class StudentAdapter extends BaseAdapter {
        private AdapterEnterCallBack callback;
        private LayoutInflater inflater;
        private List<Student> list_student;
    
        public StudentAdapter(Context context, List<Student> list_student) {
            this.inflater = LayoutInflater.from(context);
            this.list_student = list_student;
        }
    
        @Override
        public int getCount() {
            return list_student.size();
        }
    
        @Override
        public Object getItem(int position) {
            return list_student.get(position);
        }
    
        @Override
        public long getItemId(int position) {
            return position;
        }
    
        @Override
        public View getView(final int position, View convertView, ViewGroup parent) {
            StudentViewHodler sv;
            if (convertView == null) {
                sv = new StudentViewHodler();
                convertView = inflater.inflate(R.layout.list_item, null);
                sv.uAge = (TextView) convertView.findViewById(R.id.tv_age);
                sv.uName = (TextView) convertView.findViewById(R.id.tv_name);
                sv.uSex = (TextView) convertView.findViewById(R.id.tv_sex);
                sv.uClass = (TextView) convertView.findViewById(R.id.tv_class);
                sv.litem = (LinearLayout) convertView.findViewById(R.id.ll_item);
    
                convertView.setTag(sv);
            } else {
                sv = (StudentViewHodler) convertView.getTag();
            }
    
            sv.uSex.setText(list_student.get(position).getSSex());
            sv.uName.setText(list_student.get(position).getSName());
            sv.uAge.setText(list_student.get(position).getSAge());
            sv.uClass.setText(list_student.get(position).getSClass());
            sv.litem.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (null != callback) {
                        callback.onEnterClick(list_student.get(position));
                    }
                }
            });
            return convertView;
        }
    
        public void addData(Student data) {
            if (data != null) {
                this.list_student.add(data);
                notifyDataSetChanged();
            }
        }
    
        public void setData(List<Student> data) {
            if (data != null) {
                list_student.clear();
                list_student.addAll(data);
                notifyDataSetChanged();
            }
        }
    
        public class StudentViewHodler {
            TextView uName;
            TextView uSex;
            TextView uAge;
            TextView uClass;
            LinearLayout litem;
        }
    
        public interface AdapterEnterCallBack {
            void onEnterClick(Student bean);
        }
    
        public void setCallback(AdapterEnterCallBack callback) {
            this.callback = callback;
        }
    
    }

    布局文件实现

    item_dialog.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="60dp"
        android:background="@android:color/white"
        android:orientation="horizontal">
    
        <Button
            android:id="@+id/btn_del"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="删除" />
    
        <Button
            android:id="@+id/btn_modify"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="修改" />
    </LinearLayout>

    list_item.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/ll_item"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
    
        <TextView
            android:id="@+id/tv_name"
            android:layout_width="0dp"
            android:layout_height="24dp"
            android:layout_weight="1"
            android:textSize="22sp"
            android:text="姓名" />
    
        <TextView
            android:id="@+id/tv_age"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:textSize="22sp"
            android:text="年龄"/>
    
        <TextView
            android:id="@+id/tv_sex"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:textSize="22sp"
            android:text="性别"/>
    
        <TextView
            android:id="@+id/tv_class"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:textSize="22sp"
            android:text="班级"/>
    
    </LinearLayout>

    main_dao.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal">
    
            <Button
                android:id="@+id/btn_add"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:text="增加数据" />
    
            <Button
                android:id="@+id/btn_query"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:text="姓名查询" />
    
            <EditText
                android:id="@+id/edit_query"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:hint="输入姓名"
                android:textColor="@android:color/black" />
        </LinearLayout>
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal">
    
            <TextView
                android:id="@+id/tv_name"
                android:layout_width="0dp"
                android:layout_height="24dp"
                android:layout_weight="1"
                android:textSize="18sp"
                android:text="姓名" />
    
            <TextView
                android:id="@+id/tv_age"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:textSize="18sp"
                android:text="年龄"/>
    
            <TextView
                android:id="@+id/tv_sex"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:textSize="18sp"
                android:text="性别"/>
    
            <TextView
                android:id="@+id/tv_class"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:textSize="18sp"
                android:text="班级"/>
    
        </LinearLayout>
    
    
        <ListView
            android:id="@+id/dao_list"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"/>
    </LinearLayout>

    my_dialog.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@android:color/white"
        android:orientation="vertical">
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">
    
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content">
    
                <LinearLayout
                    android:layout_width="0dp"
                    android:layout_height="wrap_content"
                    android:layout_weight="1">
    
                    <TextView
                        android:layout_width="0dp"
                        android:layout_height="wrap_content"
                        android:layout_weight="1"
                        android:gravity="center"
                        android:text="姓名:" />
    
                    <EditText
                        android:id="@+id/edit_name"
                        android:layout_width="0dp"
                        android:layout_height="wrap_content"
                        android:layout_weight="1"
                        android:textColor="@android:color/black" />
                </LinearLayout>
    
                <LinearLayout
                    android:layout_width="0dp"
                    android:layout_height="wrap_content"
                    android:layout_weight="1">
    
                    <TextView
                        android:layout_width="0dp"
                        android:layout_height="wrap_content"
                        android:layout_weight="1"
                        android:gravity="center"
                        android:text="性别:" />
    
                    <EditText
                        android:id="@+id/edit_sex"
                        android:layout_width="0dp"
                        android:layout_height="wrap_content"
                        android:layout_weight="1"
                        android:textColor="@android:color/black" />
                </LinearLayout>
            </LinearLayout>
    
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content">
    
                <LinearLayout
                    android:layout_width="0dp"
                    android:layout_height="wrap_content"
                    android:layout_weight="1">
    
                    <TextView
                        android:layout_width="0dp"
                        android:layout_height="wrap_content"
                        android:layout_weight="1"
                        android:gravity="center"
                        android:text="班级:" />
    
                    <EditText
                        android:id="@+id/edit_class"
                        android:layout_width="0dp"
                        android:layout_height="wrap_content"
                        android:layout_weight="1"
                        android:textColor="@android:color/black" />
                </LinearLayout>
    
                <LinearLayout
                    android:layout_width="0dp"
                    android:layout_height="wrap_content"
                    android:layout_weight="1">
    
                    <TextView
                        android:layout_width="0dp"
                        android:layout_height="wrap_content"
                        android:layout_weight="1"
                        android:gravity="center"
                        android:text="年龄:" />
    
                    <EditText
                        android:id="@+id/edit_age"
                        android:layout_width="0dp"
                        android:layout_height="wrap_content"
                        android:layout_weight="1"
                        android:textColor="@android:color/black" />
                </LinearLayout>
            </LinearLayout>
    
        </LinearLayout>
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal">
    
            <Button
                android:id="@+id/btn_ok"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:text="确认" />
    
            <Button
                android:id="@+id/btn_cancel"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:text="取消" />
        </LinearLayout>
    </LinearLayout>

    运行程序,执行增删改查

    这里写图片描述

    这里写图片描述

    项目源码链接:http://download.csdn.net/detail/mynameishuangshuai/9518322

    安卓开发高级技术交流QQ群:108721298 欢迎入群

    微信公众号:mobilesafehome

    (本公众号支持投票)

    Android安全技术大本营

  • 相关阅读:
    sqlalchemy访问Oracle数据库报错:UnicodeDecodeError: 'big5' codec can't decode byte 0xfb in position 2: illegal multibyte sequence
    Mac如何安装FastDfs
    Django执行Sql语句笔记
    跑DRF框架分页源码笔记
    Python Paginator分页学习
    Python Excel笔记
    npm run dev报错解决方法
    npm install --global vue-cli 报错 [..................] / rollbackFailedOptional: verb npm-session abfa82f3041ebc02
    MS17_010漏洞攻击Windows7
    虚拟机启动黑屏
  • 原文地址:https://www.cnblogs.com/itrena/p/5938217.html
Copyright © 2020-2023  润新知