您的位置:首页 > 移动开发 > Android开发

Android 实例-个人理财工具 之三 添加账单页面A

2008-11-23 00:34 836 查看
关键字:android sdk1.0 sqlite intent ExpandableListActivity SimpleCursorTreeAdapter cursor custom dialog

ColaBox 登记收支记录终于进入了复杂阶段了.这个界面我也是查找了很多资料以及打开android的源代码看了后才完成了,现在想来Google的开源真是明智的啊.

从前面的登录页面跳转进入添加账单页面.这个页面主要是用来登记收支记录的.

说白了就是往数据库录入明细.

表结构就是db.execSQL("CREATE TABLE bills ("
+ "_ID INTEGER PRIMARY KEY," //id
+ "fee integer," //费用

+"acctitemid integer," //账目类型
+ "userid integer," //使用者
+ "sdate TEXT," //日期
+ "stime TEXT," //时间
+ "desc TEXT" //备注
+ ");");

可以看到主要是录入这些数据.首先是布置界面,我目前想到的用个tablelayout来布局

最后布局就是如下图这样

图1



在这儿我首先需要设置账目,前面我们已经初始化过账目的数据.

账目应该是一个ExpandableListActivity 2层的结构.需要从数据库里面读取.我在账目后面放了一个editview 只读没有光标的.也就是在这儿不可录入,在该editview的onclick事件里面我们打开账目选择界面.如下图

图2 账目选择



在这个界面中点击子节点就返回前面界面,把选择的账目传递过去.在这有个问题,如果用户需要录入的账目没有怎么办?

所以我这没有用dialog方式而是用了ExpandableListActivity 在这个界面中如果长点某个子节点就弹出管理账目菜单,

来维护账目,如下图所示:

图3账目选择菜单示意 图4 编辑账目





上面这些流程说起来很简单,可是当我用andriod编写时,遇到了很多问题,不过一个个都被我解决了,这正是编程的快乐所在.

关于ExpandableListActivity 大家可以参考android 里面apidemos 里面ExpandableList1,ExpandableList2,ExpandableList3

这里面对熟悉这个ui还是很有帮助的. 在ExpandableList2 里面就是从数据库进行读取的例子. 当然android里面那个我是没太

看明白因为他引用了import android.provider.Contacts.People; 联系人部分的框架,而我目前对数据库的操作和他不一样,我都是直接

sql访问.

但是你只要搞定2个cursor就ok了. Cursor groupCursor childCursor 其他都由SimpleCursorTreeAdapter帮你实现了.

下面我们来看看如何使用SimpleCursorTreeAdapter

//首先要实现groupcursor就是父节点游标,这个其实就是我的acctitem表的

//select * from accitem where pid is null 的结果

Cursor groupCursor = billdb.getParentNode();

// Cache the ID column index

mGroupIdColumnIndex = groupCursor.getColumnIndexOrThrow("_ID");

// Set up our adapter

mAdapter = new MyExpandableListAdapter(groupCursor, this, android.R.layout.simple_expandable_list_item_1,

android.R.layout.simple_expandable_list_item_1,

new String[] { "NAME" }, // Name for group layouts

new int[] { android.R.id.text1 },

new String[] { "NAME" }, //

new int[] { android.R.id.text1 });

setListAdapter(mAdapter);

//然后我要实现childCursor

//其实就是select * from acctitem where id=pid 的结果

public class MyExpandableListAdapter extends SimpleCursorTreeAdapter {

public MyExpandableListAdapter(Cursor cursor, Context context,

int groupLayout, int childLayout, String[] groupFrom,

int[] groupTo, String[] childrenFrom, int[] childrenTo)

{

super(context, cursor, groupLayout, groupFrom, groupTo,

childLayout, childrenFrom, childrenTo);

}

protected Cursor getChildrenCursor(Cursor groupCursor) {

String pid = groupCursor.getLong(mGroupIdColumnIndex) + "";
// Log.v("cola","pid="+pid);
return billdb.getChildenNode(pid);

}

}

//我们看看Billdbhelper里面的cursor

public Cursor getParentNode(){
return db.query("acctitem", new String[]{"_id", "name" }, "pid is null", null, null, null, "pid,_id");

}

public Cursor getChildenNode(String pid){
Log.v("cola","run getchildenNode");
return db.query("acctitem", new String[]{"_id", "name" }, "pid="+pid, null, null, null, "_id");

}

只要这几步一个2级的tree list就可以出现了.

上面其实才是刚开始,后面我们需要使用一个自定义的Dialog 类似于一个inputBox 因为我们新增账目是需要输入账目的名称.

就是上面图4表现的.

虽然alertDialog提供了很多方法,可以选择list,treelist,radio, 可惜就是不能录入text.

这里我参考了api demos 里面的 DateWidgets1.java 和源代码里面DatePickerDialog.java .

我们可以从alertdialog 继承.然后添加一个Editview 最后把数据返回出来.只要把上面我说的2个java看清楚了后处理起来就简单了.

主要是一个回调函数的用法.下面看代码

//

public class Dialog_edit extends AlertDialog implements OnClickListener {

private String text = "";

private EditText edit;

private OnDateSetListener mCallback; //定义回调函数

private LinearLayout layout;

public interface OnDateSetListener { //回调接口

void onDateSet(String text);

}

protected Dialog_edit(Context context, String title, String value,

OnDateSetListener Callback) {

super(context);

mCallback = Callback;

TextView label = new TextView(context);

label.setText("hint");

// setView(label);

edit = new EditText(context);

edit.setText(value);

layout = new LinearLayout(context);

layout.setOrientation(LinearLayout.VERTICAL);

// LinearLayout.LayoutParams param =

// new LinearLayout.LayoutParams(100, 40);

// layout.addView(label, param);

LinearLayout.LayoutParams param2 = new LinearLayout.LayoutParams(200,

50);

layout.addView(edit, param2);

//添加edit

setView(layout);

setTitle(title);

setButton("确定", this);

setButton2("取消", (OnClickListener) null);

}

public void onClick(DialogInterface dialog, int which) {

// Log.v("cola","U click which="+which);

text = edit.getText().toString();

Log.v("cola", "U click text=" + text);

if (mCallback != null)

mCallback.onDateSet(text); //使用回调返回录入的数据

}

}

这样我们就完成了自定义的dialog 我们可以使用它来新增和编辑账目. 对于账目的增删改就是sql的事情了

在这我又遇到一个问题就是我新增一个账目后如何来刷新界面,从而反映账目修改后的变化

在这我开始以为只要使用getExpandableListView().invalidate(); 就可以了,

因为我之前在ExpandableList1.java例子里面,使用它可以刷新界面.

在那个例子里面我修改了数组后调用该方法,界面就刷新了,而在这SimpleCursorTreeAdapter就行不通了,我想

应该只要刷新cursor应该就可以了,后来找到了notifyDataSetChanged 呵呵,果然可以了. 这样账目的录入和管理就搞定了.

下面给出目前最新的代码.

首先是账目管理

package com.cola.ui;

import android.app.AlertDialog;

import android.app.ExpandableListActivity;

import android.content.Context;

import android.content.DialogInterface;

import android.content.Intent;

import android.database.Cursor;

import android.os.Bundle;

import android.provider.Contacts.People;

import android.util.Log;

import android.view.ContextMenu;

import android.view.MenuItem;

import android.view.View;

import android.view.ContextMenu.ContextMenuInfo;

import android.widget.ExpandableListAdapter;

import android.widget.ExpandableListView;

import android.widget.SimpleCursorTreeAdapter;

import android.widget.TextView;

import android.widget.ExpandableListView.ExpandableListContextMenuInfo;

/**

* Demonstrates expandable lists backed by Cursors

*/

public class Frm_Editacctitem extends ExpandableListActivity {

private int mGroupIdColumnIndex;

private String mPhoneNumberProjection[] = new String[] { People.Phones._ID,

People.Phones.NUMBER };

private ExpandableListAdapter mAdapter;

BilldbHelper billdb;

Dialog_edit newdialog;

private ExpandableListContextMenuInfo info;

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setTitle("ColaBox-选择账目");

billdb = new BilldbHelper(this);

// Query for people

Cursor groupCursor = billdb.getParentNode();

// Cache the ID column index

mGroupIdColumnIndex = groupCursor.getColumnIndexOrThrow("_ID");

// Set up our adapter

mAdapter = new MyExpandableListAdapter(groupCursor, this,

android.R.layout.simple_expandable_list_item_1,

android.R.layout.simple_expandable_list_item_1,

new String[] { "NAME" }, // Name for group layouts

new int[] { android.R.id.text1 }, new String[] { "NAME" }, //

new int[] { android.R.id.text1 });

setListAdapter(mAdapter);

registerForContextMenu(getExpandableListView());

}

@Override

public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id)

{

Bundle bundle = new Bundle();

bundle.putString("DataKey", ((TextView)v).getText().toString());//给bundle 写入数据

Intent mIntent = new Intent();

mIntent.putExtras(bundle);

setResult(RESULT_OK, mIntent);

billdb.close();

finish();

return true;

}

@Override

public void onCreateContextMenu(ContextMenu menu, View v,

ContextMenuInfo menuInfo) {

super.onCreateOptionsMenu(menu);

if (ExpandableListView

.getPackedPositionType(((ExpandableListContextMenuInfo) menuInfo).packedPosition) == 1) {

Log.v("cola", "run menu");

menu.setHeaderTitle("菜单");

menu.add(0, 1, 0, "新 增");

menu.add(0, 2, 0, "删 除");

menu.add(0, 3, 0, "编 辑");

}

}

@Override

public boolean onContextItemSelected(MenuItem item) {

info = (ExpandableListContextMenuInfo) item.getMenuInfo();

if (item.getItemId() == 1) {

// Log.v("cola","id"+info.id);

newdialog = new Dialog_edit(this, "请输入新增账目的名称", "",

mDialogClick_new);

newdialog.show();

} else if (item.getItemId() == 2) {

new AlertDialog.Builder(this).setTitle("提示").setMessage("确定要删除'"+((TextView)info.targetView).getText().toString()+"'这个账目吗?")

.setIcon(R.drawable.quit).setPositiveButton("确定",

new DialogInterface.OnClickListener() {

public void onClick(DialogInterface dialog,

int whichButton) {

billdb.Acctitem_delitem((int)info.id);

updatedisplay();

}

}).setNegativeButton("取消",

new DialogInterface.OnClickListener() {

public void onClick(DialogInterface dialog,

int whichButton) {

// 取消按钮事件

}

}).show();

} else if (item.getItemId() == 3) {

newdialog = new Dialog_edit(this, "请修改账目名称",

((TextView) info.targetView).getText().toString(),

mDialogClick_edit);

newdialog.show();

}

return false;

}

private Dialog_edit.OnDateSetListener mDialogClick_new = new Dialog_edit.OnDateSetListener() {

public void onDateSet(String text) {

Log.v("cola", "new acctitem");

billdb.Acctitem_newitem(text,ExpandableListView.getPackedPositionGroup(info.packedPosition));

updatedisplay();

}

};

private Dialog_edit.OnDateSetListener mDialogClick_edit = new Dialog_edit.OnDateSetListener() {

public void onDateSet(String text) {

billdb.Acctitem_edititem(text,(int)info.id);

updatedisplay();

}

};

private void updatedisplay(){

Log.v("cola", "update display");

((MyExpandableListAdapter)mAdapter).notifyDataSetChanged();

}

public class MyExpandableListAdapter extends SimpleCursorTreeAdapter {

public MyExpandableListAdapter(Cursor cursor, Context context,

int groupLayout, int childLayout, String[] groupFrom,

int[] groupTo, String[] childrenFrom, int[] childrenTo) {

super(context, cursor, groupLayout, groupFrom, groupTo,

childLayout, childrenFrom, childrenTo);

}

@Override

protected Cursor getChildrenCursor(Cursor groupCursor) {

String pid = groupCursor.getLong(mGroupIdColumnIndex) + "";

// Log.v("cola","pid="+pid);

return billdb.getChildenNode(pid);

}

@Override

public long getGroupId(int groupPosition) {

// Log.v("cola", "getGroupId " + groupPosition);

Cursor groupCursor = (Cursor) getGroup(groupPosition);

return groupCursor.getLong(mGroupIdColumnIndex);

}

@Override

public long getChildId(int groupPosition, int childPosition) {

// Log.v("cola", "getChildId " + groupPosition + "," +

// childPosition);

Cursor childCursor = (Cursor) getChild(groupPosition, childPosition);

return childCursor.getLong(0);

}

}

}

自定义对话框

package com.cola.ui;

import android.app.AlertDialog;

import android.content.Context;

import android.content.DialogInterface;

import android.content.DialogInterface.OnClickListener;

import android.util.Log;

import android.widget.EditText;

import android.widget.LinearLayout;

import android.widget.TextView;

public class Dialog_edit extends AlertDialog implements OnClickListener {

private String text = "";

private EditText edit;

private OnDateSetListener mCallback;

private LinearLayout layout;

public interface OnDateSetListener {

void onDateSet(String text);

}

protected Dialog_edit(Context context, String title, String value,

OnDateSetListener Callback) {

super(context);

mCallback = Callback;

TextView label = new TextView(context);

label.setText("hint");

// setView(label);

edit = new EditText(context);

edit.setText(value);

layout = new LinearLayout(context);

layout.setOrientation(LinearLayout.VERTICAL);

// LinearLayout.LayoutParams param =

// new LinearLayout.LayoutParams(100, 40);

// layout.addView(label, param);

LinearLayout.LayoutParams param2 = new LinearLayout.LayoutParams(200,

50);

layout.addView(edit, param2);

setView(layout);

setTitle(title);

setButton("确定", this);

setButton2("取消", (OnClickListener) null);

}

public void onClick(DialogInterface dialog, int which) {

// Log.v("cola","U click which="+which);

text = edit.getText().toString();

Log.v("cola", "U click text=" + text);

if (mCallback != null)

mCallback.onDateSet(text);

}

}

数据库管理代码

package com.cola.ui;

import android.content.Context;

import android.database.Cursor;

import android.database.sqlite.SQLiteDatabase;

import android.util.Log;

/**

* Provides access to a database of notes. Each note has a title, the note

* itself, a creation date and a modified data.

*/

public class BilldbHelper {

private static final String TAG = "Cola_BilldbHelper";

private static final String DATABASE_NAME = "cola.db";

SQLiteDatabase db;

Context context;

BilldbHelper(Context _context) {

context=_context;

db=context.openOrCreateDatabase(DATABASE_NAME, 0, null);

Log.v(TAG,"db path="+db.getPath());

}

public void CreateTable_acctitem() {

try{

db.execSQL("CREATE TABLE acctitem ("

+ "_ID INTEGER PRIMARY KEY,"

+ "PID integer,"

+ "NAME TEXT"

+ ");");

Log.v("cola","Create Table acctitem ok");

}catch(Exception e){

Log.v("cola","Create Table acctitem err,table exists.");

}

}

public void CreateTable_bills() {

try{

db.execSQL("CREATE TABLE bills ("

+ "_ID INTEGER PRIMARY KEY,"

+" acctitemid integer,"

+ "fee integer,"

+ "userid integer,"

+ "sdate TEXT,"

+ "stime TEXT,"

+ "desc TEXT"

+ ");");

Log.v("cola","Create Table acctitem ok");

}catch(Exception e){

Log.v("cola","Create Table acctitem err,table exists.");

}

}

public void CreateTable_colaconfig() {

try{

db.execSQL("CREATE TABLE colaconfig ("

+ "_ID INTEGER PRIMARY KEY,"

+ "NAME TEXT"

+ ");");

Log.v("cola","Create Table colaconfig ok");

}catch(Exception e){

Log.v("cola","Create Table acctitem err,table exists.");

}

}

public void InitAcctitem() {

try{

//s.getBytes(encoding);

db.execSQL("insert into acctitem values (1,null,'收入')");

db.execSQL("insert into acctitem values (2,1,'工资')");

db.execSQL("insert into acctitem values (9998,1,'其他')");

db.execSQL("insert into acctitem values (0,null,'支出')");

db.execSQL("insert into acctitem values (3,0,'生活用品')");

db.execSQL("insert into acctitem values (4,0,'水电煤气费')");

db.execSQL("insert into acctitem values (5,0,'汽油费')");

db.execSQL("insert into acctitem values (9999,0,'其他')");

//db.execSQL("insert into bills values(100,135,10000,'','','备注')");

Log.v("cola","insert into ok");

}catch(Exception e)

{

Log.v("cola","init acctitem e="+e.getMessage());

}

}

public void Acctitem_newitem(String text,int type){

Cursor c =db.query("acctitem", new String[]{"max(_id)+1"}, "_id is not null and _id<9998", null, null, null, null);

c.moveToFirst();

int maxid=c.getInt(0);

String sql="insert into acctitem values ("+maxid+","+type+",'"+text+"')";

db.execSQL(sql);

Log.v("cola","newitem ok text="+text+" id="+type+" sql="+sql);

}

public void Acctitem_edititem(String text,int id){

db.execSQL("update acctitem set name='"+text+"' where _id="+id);

Log.v("cola","edititem ok text="+text+" id="+id);

}

public void Acctitem_delitem(int id){

db.execSQL("delete from acctitem where _id="+id);

Log.v("cola","delitem ok id="+id);

}

public void QueryTable_acctitem(){

}

public void FirstStart(){

try{

String col[] = {"type", "name" };

Cursor c =db.query("sqlite_master", col, "name='colaconfig'", null, null, null, null);

int n=c.getCount();

if (c.getCount()==0){

CreateTable_acctitem();

CreateTable_colaconfig();

CreateTable_bills();

InitAcctitem();

}

//getTree();

Log.v("cola","c.getCount="+n+"");

}catch(Exception e){

Log.v("cola","e="+e.getMessage());

}

}

public void close(){

db.close();

}

public Cursor getParentNode(){

return db.query("acctitem", new String[]{"_id", "name" }, "pid is null", null, null, null, "pid,_id");

}

public Cursor getChildenNode(String pid){

Log.v("cola","run getchildenNode");

return db.query("acctitem", new String[]{"_id", "name" }, "pid="+pid, null, null, null, "_id");

}

}

这段代码搞了2个通宵.昨天晚上又被ubuntu 8.04和vmware 5.5 折腾死.我的周末就这样泡汤了.
##############################################
2008-11-23 01:43 湖北武汉

##############################################

备注:

今天看了下android的dialog例子,发现android 带了可输入文字的dialog例子,呵呵,实际上和我自定义的方法就是类似的.

我之前还是demo看的太少了,也就不会走弯路了.

具体可以看AlertDialogSamples.java
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: