《Android Studio实战 快速高效地构建Android应用》--备忘录实验(1/2)

宁可枝头抱香死,何曾吹落北风中。这篇文章主要讲述《Android Studio实战 快速高效地构建Android应用》--备忘录实验(1/2)相关的知识,希望能为你提供帮助。

  • 通过开发App熟悉android Studio的用法
  • 开发一款用于管理备忘事项列表的App,核心功能:
    • 创建、删除备忘
    • 将某些备忘标记为重要(左侧带颜色标签突出显示)
  • 涉及:操作栏菜单、上下文菜单、用于持久化的本地数据库、支持多选的设备上的多项选择
启动新项目
File|New|New project命名为Reminders,选择Empty Activity
《Android Studio实战 快速高效地构建Android应用》--备忘录实验(1/2)

文章图片

初始化Git仓库
安装、配置Git:https://www.cnblogs.com/hhhqqq/p/12273696.html
  • 创建Git仓库
《Android Studio实战 快速高效地构建Android应用》--备忘录实验(1/2)

文章图片

然后选择项目根目录来创建Git仓库
  • 在Version Control工具窗口中右击Unversioned Files选择Add to VCS将这些文件添加到Git索引
  • 提交文件(Ctrl+K|将项目的修改记录到Git版本控制系统的过程)
    《Android Studio实战 快速高效地构建Android应用》--备忘录实验(1/2)

    文章图片

构建用户界面
visual designer布局
《Android Studio实战 快速高效地构建Android应用》--备忘录实验(1/2)

文章图片

可视化设计器
将左侧PaletteLegacy中的ListView拖到编辑区域放置该控件,右侧Attributes修改该控件各项属性
《Android Studio实战 快速高效地构建Android应用》--备忘录实验(1/2)

文章图片

编辑布局的原始XML
单击底部Text,编辑原始XML
《Android Studio实战 快速高效地构建Android应用》--备忘录实验(1/2)

文章图片

更改背景颜色:
android:background=" #181818" //设置RelativeLayout背景颜色

在XML布局文件中硬编码颜色值并不是最佳方案,更好的方法:在values资源文件夹下定义colors.xml,在里面定义自己的颜色。这样便于编辑而且可以很容易地在整个项目中引用。
将代码修改为:
android:background=" @color/dark_grey"

《Android Studio实战 快速高效地构建Android应用》--备忘录实验(1/2)

文章图片

在错误提示中选择第二项(创建颜色资源)
《Android Studio实战 快速高效地构建Android应用》--备忘录实验(1/2)

文章图片

修改ListView列表项的显示方式
在reslayout文件夹中新建reminders_row,选择LinearLayout(LinearLayout是布局中的最外层元素)作为根ViewGroup来为单个列表项行创建布局,
< ?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=" 50dp" android:orientation=" vertical" android:background=" @color/dark_grey" > < LinearLayout android:orientation=" horizontal" android:layout_width=" match_parent" android:layout_height=" 48dp" > < view android:layout_width=" 10dp" android:layout_height=" match_parent" class=" android.view.View" android:id=" @+id/row_tab" android:background=" @color/green" /> < TextView android:layout_width=" match_parent" android:layout_height=" 50dp" android:text=" Reminder Text" android:id=" @+id/row_text" android:textColor=" @color/white" android:textSize=" 18sp" android:gravity=" center_vertical" android:padding=" 10dp" android:ellipsize=" end" android:maxLines=" 1" /> < /LinearLayout> < view class=" android.view.View" android:layout_width=" fill_parent" android:layout_height=" 1dp" android:background=" #000" /> < view class=" android.view.View" android:layout_width=" fill_parent" android:layout_height=" 1dp" android:background=" #333" /> < /LinearLayout>

《Android Studio实战 快速高效地构建Android应用》--备忘录实验(1/2)

文章图片

向ListView添加条目
修改相应的Activity文件(RemindersActivity.java),声明一个ListView成员、修改onCreate()方法
private ListView mListView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_reminders); mListView = (ListView)findViewById(R.id.reminders_list_view); ArrayAdapter< String> arrayAdapter = new ArrayAdapter< String> ( this,//当前Activity的Context对象 R.layout.reminders_row, //使用哪个布局 R.id.row_text,//布局中的哪个字段来显示数据 new String[]{" first record" ," second record" }//示例条目 ); mListView.setAdapter(arrayAdapter); }

《Android Studio实战 快速高效地构建Android应用》--备忘录实验(1/2)

文章图片

添加操作栏溢出菜单
在res文件夹下新建menu文件夹,右键New|Menu resource file命名为menu_reminders
menu/menu_reminders.xml:
< ?xml version=" 1.0" encoding=" utf-8" ?> < menu xmlns:android=" http://schemas.android.com/apk/res/android" xmlns:app=" http://schemas.android.com/apk/res-auto" > < item android:id=" @+id/action_new" android:title=" New Reminder" android:orderInCategory=" 100" app:showAsAction=" never" /> < item android:id=" @+id/action_exit" android:title=" exit" android:orderInCategory=" 200" app:showAsAction=" never" /> < /menu>

在RemindersActivity.java中添加创建菜单的方法和菜单的点击事件
/** *创建菜单 */ @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.menu_reminders,menu); //通过getMenuInflater()方法得到MenuInflater对象,再调用它的inflate()方法就可以给当前活动创建菜单了,第一个参数:用于指定我们通过哪一个资源文件来创建菜单;第二个参数:用于指定我们的菜单项将添加到哪一个Menu对象当中。 return true; // true:允许创建的菜单显示出来,false:创建的菜单将无法显示。 }/** *菜单的点击事件 */ @Override public boolean onOptionsItemSelected(MenuItem item) {switch (item.getItemId()){ case R.id.action_new: Log.d(getLocalClassName()," create new Reminder" ); return true; case R.id.action_exit: finish(); return true; default: return false; } }

《Android Studio实战 快速高效地构建Android应用》--备忘录实验(1/2)

文章图片

持久化备忘录
  • SQLite数据库
  • 数据模型、数据库代理类、CursorAdapter
    • 数据模型:保存从数据库读取以及写入数据库的数据
    • 数据库代理类:适配器类,把来自App的简单调用转换为对SQLite数据库的API调用
    • CursorAdapter:继承以抽象方式处理数据访问的标准Android类
数据模型
创建数据模型
com.example.dell.reminders右键New Java Class命名为Reminder
Reminder类:
public class Reminder { private int mId; private String mContent; private int mImportant; public Reminder(int id, String content, int important) { mId = id; mContent = content; mImportant = important; }public int getId() { return mId; }public void setId(int id) { mId = id; }public String getContent() { return mContent; }public void setContent(String content) { mContent = content; }public int getImportant() { return mImportant; }public void setImportant(int important) { mImportant = important; } }

创建数据库代理
com.example.dell.reminders右键New Java Class命名为RemindersDbAdapter
public class RemindersDbAdapter { //定义列名 public static final String COL_ID = " _id" ; public static final String COL_CONTENT = " content" ; public static final String COL_IMPORTANT = " important" ; //定义索引值 public static final int INDEX_ID = 0; public static final int INDEX_CONTENT = INDEX_ID + 1; public static final int INDEX_IMPORTANT = INDEX_ID + 2; //用于日志的TAG public static final String TAG = " RemindersDbAdapter" ; //两个数据库API对象 private DatabaseHelper mDbHelper; private SQLiteDatabase mDb; //数据库名称、主表名称、版本的常量 public static final String DATABASE_NAME = " dba_remdrs" ; public static final String TABLE_NAME = " tbl_remdrs" ; public static final int DATABASE_VERSION = 1; //上下文对象 private final Context mCtx; //用于创建数据库的SQL语句 private static final String DATABASE_CREATE = " CREATE TABLE if not exists " + TABLE_NAME + " ( " + COL_ID + " INTEGER PRIMARY KEY autoincrement, " + COL_CONTENT + " TEXT, " + COL_IMPORTANT + " INTEGER ); " ; }

SQLite API
【《Android Studio实战 快速高效地构建Android应用》--备忘录实验(1/2)】DatabaseHelper:用于打开、关闭数据库的SQLite API类,是一个自定义的类,将其实现为RemindersDbAdapter的内部类
private static class DatabaseHelper extends SQLiteOpenHelper{ //构造函数完成数据库初始化 DatabaseHelper(Context context){ //将数据库名和版本号传给超类,由超类完成建立数据库的繁重工作 super(context,DATABASE_NAME,null,DATABASE_VERSION); }public void onCreate(SQLiteDatabase db){ Log.w(TAG,DATABASE_CREATE); db.execSQL(DATABASE_CREATE); }public void onUpgrade(SQLiteDatabase db,int oldVersion, int newVersion){ Log.w(TAG, " Upgrading database from version " + oldVersion + " to " + newVersion + " , which will destroy all old data" ); db.execSQL(" DROP TABLE IF EXISTS " + TABLE_NAME); onCreate(db); } }

使用DatabaseHelper打开和关闭数据库,RemindersDbAdapter构造函数保存了Context实例,并传给DatabaseHelper
public RemindersDbAdapter(Context ctx) { this.mCtx = ctx; }public void open() throws SQLException{ mDbHelper = new DatabaseHelper(mCtx); mDb = mDbHelper.getWritableDatabase(); }public void close(){ if(mDbHelper != null){ mDbHelper.close(); } }

数据库的增删改查:
创建方法使用特殊的ContentValues对象,用于将数据值传给数据库对象的insert方法,数据库会将这些对象转换为SQL insert语句并执行
//数据库的增删改查 public void createReminder(String name, boolean important){ ContentValues values = new ContentValues(); values.put(COL_CONTENT, name); values.put(COL_IMPORTANT, important?1:0); mDb.insert(TABLE_NAME,null,values); }public long createReminder(Reminder reminder){ ContentValues values = new ContentValues(); values.put(COL_CONTENT,reminder.getContent()); values.put(COL_IMPORTANT,reminder.getImportant()); return mDb.insert(TABLE_NAME,null,values); }public Reminder fetchReminderById(int id){ Cursor cursor = mDb.query(TABLE_NAME,new String[]{COL_ID, COL_CONTENT,COL_IMPORTANT},COL_ID + " =?" , new String[]{String.valueOf(id)},null,null,null,null); if(cursor != null) cursor.moveToFirst(); return new Reminder( cursor.getInt(INDEX_ID), cursor.getString(INDEX_CONTENT), cursor.getInt(INDEX_IMPORTANT) ); }public Cursor fetchAllReminders(){ Cursor mCursor = mDb.query(TABLE_NAME,new String[]{COL_ID, COL_CONTENT,COL_IMPORTANT},null,null,null,null,null); if (mCursor != null){ mCursor.moveToFirst(); }return mCursor; }public void updateReminder(Reminder reminder){ ContentValues values = new ContentValues(); values.put(COL_CONTENT,reminder.getContent()); values.put(COL_IMPORTANT,reminder.getImportant()); mDb.update(TABLE_NAME,values, COL_ID+" =?" ,new String[]{String.valueOf(reminder.getId())}); }public void deleteReminderById(int nId){ mDb.delete(TABLE_NAME,COL_ID+" =?" ,new String[]{String.valueOf(nId)}); }public void deleteAllReminders(){ mDb.delete(TABLE_NAME,null,null); }

RemindersDbAdapter最终代码
public class RemindersDbAdapter { //定义列名 public static final String COL_ID = " _id" ; public static final String COL_CONTENT = " content" ; public static final String COL_IMPORTANT = " important" ; //定义索引值 public static final int INDEX_ID = 0; public static final int INDEX_CONTENT = INDEX_ID + 1; public static final int INDEX_IMPORTANT = INDEX_ID + 2; //用于日志的TAG public static final String TAG = " RemindersDbAdapter" ; //两个数据库API对象 private DatabaseHelper mDbHelper; private SQLiteDatabase mDb; //数据库名称、主表名称、版本的常量 public static final String DATABASE_NAME = " dba_remdrs" ; public static final String TABLE_NAME = " tbl_remdrs" ; public static final int DATABASE_VERSION = 1; //上下文对象 private final Context mCtx; //用于创建数据库的SQL语句 private static final String DATABASE_CREATE = " CREATE TABLE if not exists " + TABLE_NAME + " ( " + COL_ID + " INTEGER PRIMARY KEY autoincrement, " + COL_CONTENT + " TEXT, " + COL_IMPORTANT + " INTEGER ); " ; public RemindersDbAdapter(Context ctx) { this.mCtx = ctx; }public void open() throws SQLException{ mDbHelper = new DatabaseHelper(mCtx); mDb = mDbHelper.getWritableDatabase(); }public void close(){ if(mDbHelper != null){ mDbHelper.close(); } }//数据库的增删改查 public void createReminder(String name, boolean important){ ContentValues values = new ContentValues(); values.put(COL_CONTENT, name); values.put(COL_IMPORTANT, important?1:0); mDb.insert(TABLE_NAME,null,values); }public long createReminder(Reminder reminder){ ContentValues values = new ContentValues(); values.put(COL_CONTENT,reminder.getContent()); values.put(COL_IMPORTANT,reminder.getImportant()); return mDb.insert(TABLE_NAME,null,values); }public Reminder fetchReminderById(int id){ Cursor cursor = mDb.query(TABLE_NAME,new String[]{COL_ID, COL_CONTENT,COL_IMPORTANT},COL_ID + " =?" , new String[]{String.valueOf(id)},null,null,null,null); if(cursor != null) cursor.moveToFirst(); return new Reminder( cursor.getInt(INDEX_ID), cursor.getString(INDEX_CONTENT), cursor.getInt(INDEX_IMPORTANT) ); }public Cursor fetchAllReminders(){ Cursor mCursor = mDb.query(TABLE_NAME,new String[]{COL_ID, COL_CONTENT,COL_IMPORTANT},null,null,null,null,null); if (mCursor != null){ mCursor.moveToFirst(); }return mCursor; }public void updateReminder(Reminder reminder){ ContentValues values = new ContentValues(); values.put(COL_CONTENT,reminder.getContent()); values.put(COL_IMPORTANT,reminder.getImportant()); mDb.update(TABLE_NAME,values, COL_ID+" =?" ,new String[]{String.valueOf(reminder.getId())}); }public void deleteReminderById(int nId){ mDb.delete(TABLE_NAME,COL_ID+" =?" ,new String[]{String.valueOf(nId)}); }public void deleteAllReminders(){ mDb.delete(TABLE_NAME,null,null); }private static class DatabaseHelper extends SQLiteOpenHelper{ //构造函数完成数据库初始化 DatabaseHelper(Context context){ //将数据库名和版本号传给超类,由超类完成建立数据库的繁重工作 super(context,DATABASE_NAME,null,DATABASE_VERSION); }public void onCreate(SQLiteDatabase db){ Log.w(TAG,DATABASE_CREATE); db.execSQL(DATABASE_CREATE); }public void onUpgrade(SQLiteDatabase db,int oldVersion, int newVersion){ Log.w(TAG, " Upgrading database from version " + oldVersion + " to " + newVersion + " , which will destroy all old data" ); db.execSQL(" DROP TABLE IF EXISTS " + TABLE_NAME); onCreate(db); } } }

CursorAdapter
最后,需要一种从数据库获取备忘并加入到ListView中的方法,新建java类RemindersSimpleCursorAdapter
public class RemindersSimpleCursorAdapter extends SimpleCursorAdapter { public RemindersSimpleCursorAdapter(Context context, int layout, Cursor c, String[] from, int[] to, int flags) { super(context, layout, c, from, to, flags); }@Override public View newView(Context context, Cursor cursor, ViewGroup parent) { return super.newView(context, cursor, parent); }//ListView会利用屏幕上的单个View对象反复调用此方法,Adapter的职责就是使用列表项来填充这些视图 @Override public void bindView(View view, Context context, Cursor cursor) { super.bindView(view, context, cursor); //调用超类方法,通过游标cursor获取到的值映射到View中的元素ViewHolder holder = (ViewHolder)view.getTag(); if(holder == null){ //检查holder是否绑定到了标签 holder = new ViewHolder(); holder.colImp = cursor.getColumnIndexOrThrow(RemindersDbAdapter.COL_IMPORTANT); holder.listTab = view.findViewById(R.id.row_tab); view.setTag(holder); }//使用当前备忘COL_IMPORTANT常量对应的值来决定颜色1:重要 0:次要 if(cursor.getInt(holder.colImp) > 0){ holder.listTab.setBackgroundColor(context.getResources().getColor(R.color.orange)); } else{ holder.listTab.setBackgroundColor(context.getResources().getColor(R.color.green)); } }//静态内部类 static class ViewHolder{ int colImp; //Important表列的索引 View listTab; //在布局中定义的row_tab视图 } }

调整ReminderActivity
public class RemindersActivity extends AppCompatActivity {private ListView mListView; private RemindersDbAdapter mDbAdapter; private RemindersSimpleCursorAdapter mCursorAdapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_reminders); mListView = (ListView)findViewById(R.id.reminders_list_view); mListView.setDivider(null); mDbAdapter = new RemindersDbAdapter(this); mDbAdapter.open(); Cursor cursor = mDbAdapter.fetchAllReminders(); String[] from = new String[]{RemindersDbAdapter.COL_CONTENT}; int[] to = new int[]{R.id.row_text}; mCursorAdapter = new RemindersSimpleCursorAdapter( RemindersActivity.this, R.layout.reminders_row, cursor, from, to, 0 ); mListView.setAdapter(mCursorAdapter); } }

调整完运行app,将不会在列表中看到任何内容,因为最后的修改插入的是SQLite功能而非示例数据
《Android Studio实战 快速高效地构建Android应用》--备忘录实验(1/2)

文章图片

Ctrl+K提交备忘录实验1的最后一次修改
《Android Studio实战 快速高效地构建Android应用》--备忘录实验(1/2)

文章图片


    推荐阅读