欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android 个人理财工具三:添加账单页面 上

程序员文章站 2024-03-06 18:13:44
       colabox 登记收支记录终于进入了复杂阶段了。这个界面我也是查找了很多资料以及打开androi...

       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)这样:

Android 个人理财工具三:添加账单页面 上

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

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

       图2 账目选择:

Android 个人理财工具三:添加账单页面 上

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

       所以我这没有用dialog方式而是用了expandablelistactivity。在这个界面中如果长点某个子节点就弹出管理账目菜单,来维护账目,如下图所示:

       图3 账目选择菜单:

Android 个人理财工具三:添加账单页面 上

       图4 编辑账目:

Android 个人理财工具三:添加账单页面 上

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

       关于expandablelistactivity 大家可以参考android 里面apidemos 里面expandablelist1、expandablelist2、expandablelist3。

       这里面对熟悉这个ui还是很有帮助的。在expandablelist2 里面就是从数据库进行读取的例子。当然android里面那个我是没太看明白因为他引用了import android.provider.contacts.people; 联系人部分的框架,而我目前对数据库的操作和他不一样,我都是直接sql访问。

       但是你只要搞定2个cursor就ok了,cursor groupcursor childcursor ,其他都由simplecursortreeadapter帮你实现了。

       下面我们来看看如何使用simplecursortreeadapter。

java代码      

//首先要实现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看清楚了后处理起来就简单了。

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

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,呵呵,果然可以了。 这样账目的录入和管理就搞定了。

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

       首先是账目管理:

java代码

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); 
  } 
 } 
} 

       自定义对话框:

java代码

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); 
 } 
} 

       数据库管理代码:

java代码

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");  
 } 
  
} 

        系列文章:

                       android 个人理财工具六:显示账单明细 下

                       android 个人理财工具五:显示账单明细 上

                       android 个人理财工具四:添加账单页面 下

                       android 个人理财工具三:添加账单页面 上

                       android 个人理财工具二:使用sqlite实现启动时初始化数据

                       android 个人理财工具一:项目概述与启动界面的实现

       以上就android 开发个人理财工具 添加账单页面的讲解,后续继续更新相应文章,谢谢大家对本站的支持!