Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android 個人理財工具三:添加賬單頁面 上

Android 個人理財工具三:添加賬單頁面 上

編輯:關於Android編程

       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 開發個人理財工具 添加賬單頁面的講解,後續繼續更新相應文章,謝謝大家對本站的支持!

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved