当前位置: 移动技术网 > 移动技术>移动开发>Android > Android 个人理财工具三:添加账单页面 上

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

2019年07月24日  | 移动技术网移动技术  | 我要评论

       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。

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 开发个人理财工具 添加账单页面的讲解,后续继续更新相应文章,谢谢大家对本站的支持!

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网