本例子是用数据库SQLiteDatabase类来存储记事本的数据的,实现了增、删、改、查功能。
且支持多选删除!
通过点击listView中的某一项来从数据库中对相应的项进行操作。关键是怎样找到对应的项。以前(最最初接触android时,呵呵。只知道arrayAdapter这个适配器和烂烂的文件存取的情况下,简直是个奇迹~)写的一个记事本例子,是通过listView里的点击位置position:(0、1、2、3、4.......)对应了文件名:(0、1、2、3、4.......)来对相应的文件进行读取,修改,新建,删除。
但是那种方式有很明显的局限性:当中间一个文件删除后,listView中的条目位置position与文件的编号就会错乱。比如原来是位置在4的条目,由于它上面的一条删除后,它的位置就变为3了。但是它真正对应得文件名却是4.这样,就不能找到对应的文件了。
而且每次新建时的编号必须是递增的。用过的编号就不能再次使用了,局限性太大了。虽然当时解决这问题时是删除一个文件后它在listView中的条目只是置为空,而不是删除,这样就能通过点击空条目来对以前删除过的条目进行新记事,但是也不太符合实际。
在已经接触android近半年后今天,终于在短短的一天时间就写出了当时一个周的记事本。当然用到的东西还很简单,android这条路上还有很多要走。
本来以为还是用ListView的position对应数据库中的id是个不错的办法,但是遗憾的是,数据库中的id没办法在删除后自动重新排序。可能是还没找到方法吧。我放弃了这种通过位置编号来查找的路径了。
一番思考后我发现,时间是一条信息的唯一标识。可以利用时间来查询数据库中的某一项啊!
于是。。。
这个例子用到了好几个我认为以前不知道的东西。
listView也不是原来单单的一条字符串了。基于BaseAdapter的条目,里面有两个TextView一个checkBox.
还有在listView中使用checkBox时会出现复用问题。就是如果不做处理的话,当第一条checkbox点击后滑动到下面,你会发现下面一页的listView条目checkbox也会被选中了。很奇怪啊!在慕课网有节课讲解了这种问题的两种解决办法,我这里用了其中一种。
还有一个函数:// 通知adapter更新数据,重新调用getView方法
this.myAdapter.notifyDataSetChanged();
数据变化后更新listView,要调用这个方法。
增:ContentValues values = new ContentValues();
values.put("content", note.getContent());
values.put("time", note.getTime());
db.insert(MainActivity.TABLE_NAME, null, values);
删:db.delete(MainActivity.TABLE_NAME, "time like?",
new String[] { time });
改:ContentValues values = new ContentValues();
values.put("content", note.getContent());
values.put("time", note.getTime());
db.update(MainActivity.TABLE_NAME, values, "time like?", new String [] {tag});
查:Cursor c = db.query(MainActivity.TABLE_NAME, null, null, null, null,
null, null);
if (c != null) {
String[] colums = c.getColumnNames();
while (c.moveToNext()) {
String content = c.getString(c.getColumnIndex("content"));
String time = c.getString(c.getColumnIndex("time"));
Note note = new Note(content, time);
notes.add(note);
}
}
包括两个界面,listView展示记事列表界面和书写保存界面。
对界面这次用到了:自定义xml背景,button的按下改变背景色,对button添加自定义style等方法。
activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<ListView
android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:dividerHeight="1dp"
android:padding="5dp" >
</ListView>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#ECECEC"
android:orientation="horizontal"
android:paddingBottom="10dp"
android:paddingLeft="5dp"
android:paddingRight="5dp"
android:paddingTop="10dp" >
<Button
android:id="@+id/btn_new"
style="@style/btn_sytle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:onClick="newNote"
android:text="新建记事" />
<Button
android:id="@+id/btn_delete"
style="@style/btn_sytle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:onClick="deleteNote"
android:text="多选删除" />
</LinearLayout>
</LinearLayout>
write_item.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:padding="5dp"
android:orientation="vertical" >
<TextView
android:id="@+id/tv_save_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="00:00"
android:textColor="#8484FF"
/>
<EditText
android:id="@+id/et_content"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:textColor="#0000FF"
android:textSize="18sp"
android:paddingTop="20dp"
android:paddingBottom="20dp"
android:paddingLeft="5dp"
android:paddingRight="5dp"
android:layout_marginBottom="10dp"
android:gravity="left"
android:hint="请写下记事"
/>
<Button
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="保存"
android:textColor="#0000ff"
android:onClick="save"
android:background="@drawable/press_btn"
/>
</LinearLayout>
list_item_view.xml
<?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="wrap_content"
android:padding="5dp" >
<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:ellipsize="end"
android:gravity="left"
android:singleLine="true"
android:text="金坛哈吉积极啊加啊加点击纠结啊是点击纠结啊是"
android:layout_marginRight="30dp"
android:textColor="#0000FF"
android:textSize="18sp" />
<CheckBox
android:id="@+id/check_box"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="@id/tv_title"
android:layout_alignParentRight="true"
android:layout_marginRight="1dp"
android:visibility="visible"
android:focusable="false"
android:layout_alignParentTop="true"
/>
<TextView
android:id="@+id/tv_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_below="@id/check_box"
android:gravity="bottom"
android:text="12:34"
android:layout_marginBottom="2dp"
android:textColor="#8484FF"
android:textSize="12sp" />
</RelativeLayout>
bg_choosed.xml文件:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
<solid android:color="#66FFFFFF"/>
<stroke android:width="1dp"
android:color="#FFFFFF"
/>
</shape>
bg_unchoosed.xml文件:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle"
>
<solid android:color="#00000000" />
<padding
android:bottom="5dp"
android:left="5dp"
android:right="5dp"
android:top="5dp" />
<stroke
android:width="2dp"
android:color="#668484FF" />
</shape>
press_btn.xml文件:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/bg_choosed" android:state_pressed="true"></item>
<item android:drawable="@drawable/bg_unchoosed"></item>
</selector>
styles.xml文件中添加:
<style name="btn_sytle">
<item name="android:layout_width"> 0dp</item>
<item name="android:layout_height"> wrap_content</item>
<item name="android:layout_weight">1</item>
<item name="android:layout_margin">2dp</item>
<item name="android:textSize">16sp</item>
<item name="android:background">@drawable/press_btn</item>
<item name="android:minHeight">0dp</item>
<item name="android:minWidth">0dp</item>
<item name="android:textColor">#0000ff</item>
</style>
java代码部分:
包括两个activity、一个note类、一个dataBaseUtils类
MainActivity.java
package com.fxj.notebook_with_database;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
import com.fxj.notebook_with_database.data.DataBaseUtils;
import com.fxj.notebook_with_database.data.Note;
public class MainActivity extends ActionBarActivity {
private List<Note> notes;
private ListView listView;
private SQLiteDatabase db;// 数据库
private int deleteFlag = 1;// 第几次点击“多选删除”按钮的标记
public final static String TABLE_NAME = "studb";// 数据库表名
public final static int NEW = 2;// 新建记事的标记
public final static int OLD = 1;// 查看或修改旧记事的标记
boolean visflag = false;// “多选删除”按钮隐藏/显示的标记
private MyAdapter myAdapter;// 适配器
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
initData();
}
private void initData() {
// 创建数据库stu.db
db = openOrCreateDatabase("stu.db", MODE_PRIVATE, null);
// 执行创建表单语句
db.execSQL("create table if not exists "
+ TABLE_NAME
+ "(_id integer primary key autoincrement,content text not null,time text not null)");
if (notes == null) {
// 从数据库中加载数据
notes = DataBaseUtils.getDataFromDatabase(db);
}
myAdapter = new MyAdapter();
listView.setAdapter(myAdapter);// 为ListView设置适配器
// 为list条目添加监听
listView.setOnItemClickListener(new MyListItemClickListener());
}
@Override
protected void onResume() {
refrushView();
super.onResume();
}
private void initView() {
listView = (ListView) findViewById(R.id.list);
}
/**
* 刷新显示页面
*/
public void refrushView() {
notes = DataBaseUtils.getDataFromDatabase(db);
myAdapter.notifyDataSetChanged();
}
/**
* 新建记事
*
* @param view
*/
public void newNote(View view) {
// 跳转到书写界面
Intent intent = new Intent(MainActivity.this, WriteActivity.class);
intent.putExtra("tag", NEW);// 指明新建记事标记
startActivity(intent);
}
/**
* 删除记事
*
* @param view
*/
public void deleteNote(View view) {
// 获取删除按钮
Button btnDelete = (Button) findViewById(R.id.btn_delete);
// 如果当前显示的是“多选删除”
if (deleteFlag == 1) {
// 将按钮文字变为“确定删除”
btnDelete.setText("确定删除");
// 改变标记
deleteFlag = 2;
// checkBox显示
visflag = true;
// 通知adapter更新数据,重新调用getView方法
this.myAdapter.notifyDataSetChanged();
} else if (deleteFlag == 2) {// 如果当前显示的是“确定删除”
// 从数据库中删除选中的条目
DataBaseUtils.deleteFromDataBase(db, getSelectItem(notes));
/*
* 此处循环遍历删除不能用for循环, 因为删除自身时,自身的notes.size()也会同时递减,导致不能遍历完全
* 这也是我发现的for循环的一个局限性 for (int i = 0; i < notes.size(); i++) { if
* (notes.get(i).isCheck()) { notes.remove(i); } }
*/
// 从list集合中删除选中的条目
for (Iterator iterator = notes.iterator(); iterator.hasNext();) {
if (((Note) iterator.next()).isCheck()) {
iterator.remove();
}
}
// 将按钮文字变为“多选删除”
btnDelete.setText("多选删除");
// 改变删除按钮标记
deleteFlag = 1;
// checkBox隐藏
visflag = false;
// 通知adapter更新数据,重新调用getView方法
this.myAdapter.notifyDataSetChanged();
}
}
/**
* 找出被选择的条目,添加到被选中项集合
*
* @param notes
* @return
*/
public List<Note> getSelectItem(List<Note> notes) {
List<Note> selectNotes = new ArrayList<Note>();
for (int i = 0; i < notes.size(); i++) {
if (notes.get(i).isCheck()) {
selectNotes.add(notes.get(i));
}
}
return selectNotes;
}
/**
* 点击条目监听事件
*
* @author Administrator
*
*/
private class MyListItemClickListener implements OnItemClickListener {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
// 获取点击条目上的时间字符串
TextView tvTime = (TextView) view.findViewById(R.id.tv_time);
String time = tvTime.getText().toString();
// 将信息传过去
Intent intent = new Intent(MainActivity.this, WriteActivity.class);
intent.putExtra("tag", OLD);
intent.putExtra("time", time);// 根据时间加载具体的note信息
startActivity(intent);
}
}
private class MyAdapter extends BaseAdapter {
@Override
public int getCount() {
return notes.size();
}
@Override
public Object getItem(int position) {
return notes.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
final int pos = position;
if (convertView == null) {
convertView = LinearLayout.inflate(MainActivity.this,
R.layout.list_item_view, null);
}
// 获取组件
TextView tvTitle = (TextView) convertView
.findViewById(R.id.tv_title);
TextView tvTime = (TextView) convertView.findViewById(R.id.tv_time);
final CheckBox checkBox = (CheckBox) convertView
.findViewById(R.id.check_box);
// 为组件赋值
final Note note = notes.get(pos);
tvTitle.setText(note.getContent());
tvTime.setText(note.getTime());
// 设置checkbox的状态,解决复用的错乱问题
checkBox.setChecked(note.isCheck());
checkBox.setOnClickListener(new android.view.View.OnClickListener(){
@Override
public void onClick(View v) {
note.setCheck(checkBox.isChecked());
}
});
if (visflag) {
checkBox.setVisibility(View.VISIBLE);
} else {
checkBox.setVisibility(View.INVISIBLE);
}
return convertView;
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
} else if (id == R.id.menu_exit) {
exitAlert();
}
return super.onOptionsItemSelected(item);
}
// 退出系统时,弹出提示对话框
public void exitAlert() {
AlertDialog.Builder builder = new Builder(MainActivity.this);
builder.setTitle("温馨提示");
builder.setMessage("确定退出?");
builder.setPositiveButton("确定", new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
System.exit(0);
}
});
builder.setNegativeButton("取消", new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
return;
}
});
builder.create().show();
}
//按back键返回时
@Override
public void onBackPressed() {
System.out.println("back---------");
exitAlert();
}
}
WriteActivity.java
package com.fxj.notebook_with_database;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.text.TextUtils;
import android.text.format.Time;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.EditText;
import com.fxj.notebook_with_database.data.DataBaseUtils;
import com.fxj.notebook_with_database.data.Note;
public class WriteActivity extends Activity {
private EditText etContent;
private TextView tvTime;
private int tag;
private SQLiteDatabase db;
private String time;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);// 去除标题栏
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);// 全屏显示
setContentView(R.layout.write_item);
initView();
initData();
}
private void initData() {
db = openOrCreateDatabase("stu.db", MODE_PRIVATE, null);
db.execSQL("create table if not exists "
+ MainActivity.TABLE_NAME
+ "(_id integer primary key autoincrement,content text not null,time text not null)");
tag = getIntent().getIntExtra("tag", 0);
time = getIntent().getStringExtra("time");
if (tag == MainActivity.NEW)// 新建记事
{
return;
}
// 如果不是新建记事,则加载记事
Note note = DataBaseUtils.getNoteFromDataBase(db, time);
String content = note.getContent();
etContent.setText(content);
tvTime.setText(time);
etContent.setSelection(content.length());// 设置光标到文字尾
}
private void initView() {
etContent = (EditText) findViewById(R.id.et_content);
tvTime= (TextView) findViewById(R.id.tv_save_time);
}
/**
* 保存按钮点击事件
*
* @param view
*/
public void save(View view) {
// 如果是新建记事的保存
if (tag == MainActivity.NEW) {
if (TextUtils.isEmpty(etContent.getText().toString()))// 如果记事为空,则弹出提示
{
AlertDialog.Builder builder = new Builder(WriteActivity.this);
builder.setTitle("温馨提示");
builder.setMessage("你还没有记事呢!确定退出吗?");
builder.setPositiveButton("确定", new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
finish();
}
});
builder.create().show();
} else {
DataBaseUtils.insertNotes(db, getNote());
finish();
}
} else if (tag == MainActivity.OLD)// 如果是对旧记事进行保存
{
// 以时间为标志,更新数据库中的信息
DataBaseUtils.updateNotes(db, getNote(), time);
finish();
}
// finish();
}
public Note getNote() {
// 获取记事内容
String content = etContent.getText().toString();
// 获取保存时间
String time = getCurrentTime();
// 生成note
Note note = new Note(content, time);
return note;
}
public String getCurrentTime() {
String time = "";
Time t = new Time("GMT+8");
t.setToNow();
int month = t.month + 1;
time = t.year + "年" + month + "月" + t.monthDay + "/" + t.hour + ":"
+ t.minute + ":" + t.second;
return time;
}
}
Note.java文件:
package com.fxj.notebook_with_database.data;
public class Note {
private String content;
private String time;
private boolean check;
public boolean isCheck() {
return check;
}
public void setCheck(boolean check) {
this.check = check;
}
public Note(String content, String time) {
super();
this.content = content;
this.time = time;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getTime() {
return time;
}
public void setTime(String time) {
this.time = time;
}
@Override
public String toString() {
return "Note [content=" + content + ", time=" + time + "]";
}
}
DataBaseUtils.java文件:
package com.fxj.notebook_with_database.data;
import java.util.ArrayList;
import java.util.List;
import android.content.ContentValues;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import com.fxj.notebook_with_database.MainActivity;
public class DataBaseUtils {
/**
* 从数据库中获取数据,转化为list对象返回
*
* @param db
* @return
*/
public static List<Note> getDataFromDatabase(SQLiteDatabase db) {
List<Note> notes = new ArrayList<Note>();
Cursor c = db.query(MainActivity.TABLE_NAME, null, null, null, null,
null, null);
if (c != null) {
String[] colums = c.getColumnNames();
while (c.moveToNext()) {
String content = c.getString(c.getColumnIndex("content"));
String time = c.getString(c.getColumnIndex("time"));
Note note = new Note(content, time);
notes.add(note);
}
}
return notes;
}
/**
* 从数据库中批量删除选中的条目
*
* @param db
*/
public static void deleteFromDataBase(SQLiteDatabase db,
List<Note> selectNotes) {
// 根据时间标志删除
for (int i = 0; i < selectNotes.size(); i++) {
String time = selectNotes.get(i).getTime();
db.delete(MainActivity.TABLE_NAME, "time like?",
new String[] { time });
System.out.println("删除--->"+time);
}
}
/**
* //以时间为标志(根据时间找到要更新的note),更新数据库中的信息
* @param db
* @param note
* @param tag
*/
public static void updateNotes(SQLiteDatabase db, Note note,String tag) {
ContentValues values = new ContentValues();
values.put("content", note.getContent());
values.put("time", note.getTime());
db.update(MainActivity.TABLE_NAME, values, "time like?", new String [] {tag});
}
/**
* 加入新note条目
* @param db
* @param note
*/
public static void insertNotes(SQLiteDatabase db, Note note) {
ContentValues values = new ContentValues();
values.put("content", note.getContent());
values.put("time", note.getTime());
db.insert(MainActivity.TABLE_NAME, null, values);
}
/**
* 根据time 从数据库中获取一个note
* @param db
* @param tag
* @return
*/
public static Note getNoteFromDataBase(SQLiteDatabase db, String tag) {
Note note =null;
Cursor c = db.query(MainActivity.TABLE_NAME, null, "time like?", new String [] {tag}, null, null, null);
if(c!=null)
{
while(c.moveToNext())
{
String content = c.getString(c.getColumnIndex("content"));
String time = c.getString(c.getColumnIndex("time"));
note = new Note(content, time);
}
}
return note;
}
}
运行效果图: