Android 개인 재 테 크 도구 3:계산서 페이지 추가

콜 라 박스 등록 수지 기록 은 마침내 복잡 한 단계 에 들 어 섰 다.이 화면 에서 나 도 많은 자 료 를 찾 았 고 안 드 로 이 드 의 소스 코드 를 열 어 본 후에 야 완성 되 었 다.지금 생각해 보면 구 글 의 소스 오픈 은 정말 현명 하 다.
       앞의 로그 인 페이지 에서 계산서 추가 페이지 로 넘 어 갑 니 다.이 페이지 는 주로 수지 기록 을 등록 하 는 데 쓰 인 다.솔직히 데이터베이스 에 내 역 을 입력 하 는 거 야.
       표 구 조 는 다음 과 같다.
       db.execSQL("CREATE TABLE bills ("
                 + "_ID INTEGER PRIMARY KEY," //id
                 + "fee integer,"                                     //비용.
                 +"acctitemid integer,"                          //장부 유형
                 + "userid integer,"                                //사용자
                 + "sdate TEXT,"                                 //날짜.
                 + "stime TEXT,"                                //시간.
                 + "desc TEXT"                                  //비고
                 + ");");
       주로 이 데 이 터 를 입력 하 는 것 을 볼 수 있다.우선 인 터 페 이 스 를 배치 하 는 것 입 니 다.제 가 지금 생각 하고 있 는 것 은 tablelayot 로 배치 하 는 것 입 니 다.
       마지막 레이아웃 은 다음 그림(그림 1)과 같 습 니 다.

       여기 서 나 는 먼저 장 부 를 설정 해 야 한다.앞에서 우 리 는 이미 장부 의 데 이 터 를 초기 화 했다.
       장 부 는 ExpandableListActivity 2 층 의 구조 여야 합 니 다.데이터베이스 에서 읽 어야 합 니 다.나 는 장부 뒤에 editview 를 놓 고 커서 가 없 는 것 만 읽 었 다.즉,여기 서 입력 할 수 없다.이 editview 의 onclick 이벤트 에서 우 리 는 장부 선택 화면 을 열 었 다.다음 그림:
       그림 2 장부 선택:

       이 인터페이스 에서 서브 노드 를 누 르 면 앞 화면 으로 돌아 가 선택 한 장 부 를 전달 합 니 다.여기에 문제 가 있 습 니 다.만약 사용자 가 입력 해 야 할 장부 가 없다 면 어떻게 합 니까?
       그래서 저 는 dialog 방식 이 아니 라 ExpandableListActivity 를 사 용 했 습 니 다.이 인터페이스 에서 키 노드 가 길 면 관리 장부 메뉴 를 꺼 내 장 부 를 유지 합 니 다.다음 그림 과 같 습 니 다.
       그림 3 장부 선택 메뉴:

       그림 4 장부 편집:

       위의 절 차 는 말 하기 가 매우 간단 하지만,내 가 앤 드 리 오 드 로 작 성 했 을 때 많은 문제 에 부 딪 혔 지만,하나하나 가 나 에 의 해 해결 되 었 다.이것 이 바로 프로 그래 밍 의 즐거움 이다.
       ExpandableList Activity 에 대해 서 는 android 에 있 는 apidemos 에 있 는 ExpandableList 1,ExpandableList 2,ExpandableList 3 를 참고 하 실 수 있 습 니 다.
       이 안 은 이 ui 를 익히 는 데 도움 이 된다.ExpandableList 2 에 서 는 데이터베이스 에서 읽 는 예 입 니 다.물론 안 드 로 이 드 에 있 는 그 건 잘 모 르 겠 어 요.import android.provider.Contacts.People 을 인 용 했 기 때 문 이에 요.연락처 부분의 프레임 워 크 입 니 다.저 는 현재 데이터 베 이 스 를 조작 하 는 것 이 그 와 다 릅 니 다.저 는 모두 sql 로 직접 방문 합 니 다.
       하지만 당신 은 cursor 2 개 만 해결 하면 됩 니 다.Cursor group Cursor child Cursor,다른 것 은 모두 Simple Cursor TreeAdapter 가 도와 주 었 습 니 다.
       Simple Cursor TreeAdapter 를 어떻게 사용 하 는 지 살 펴 보 자.
자바 코드      

//     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 를 사용 해 야 합 니 다.계 정 을 새로 만 드 는 것 은 계 정의 이름 을 입력 해 야 하기 때 문 입 니 다.바로 위의 그림 4 가 표현 한 것 이다.
       alertDialog 는 많은 방법 을 제공 하지만 list,treelist,radio 를 선택 할 수 있 습 니 다.안 타 깝 게 도 text 를 입력 할 수 없습니다.
       여기 api demos 에 있 는 DateWidgets 1.java 와 소스 코드 에 있 는 DatePickerDialog.java 를 참 고 했 습 니 다.
       우 리 는 alertdialog 에서 계승 한 후에 Editview 를 추가 하여 마지막 으로 데 이 터 를 되 돌려 줄 수 있 습 니 다.위 에서 내 가 말 한 자바 두 개 만 똑똑히 보고 처리 하면 간단 하 다.
       주로 반전 함수 의 용법 이다.다음 코드 보기:
자바 코드

// 
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()만 사용 하면됐 습 니 다.
       왜냐하면 나 는 이전에 ExpandableList 1.java 예 에서 그것 을 사용 하면 인 터 페 이 스 를 새로 고 칠 수 있 었 기 때문이다.
       그 예 에서 제 가 배열 을 수정 한 후에 이 방법 을 호출 하면 화면 이 새로 고침 되 고 이 Simple Cursor TreeAdapter 에 서 는 안 될 것 같 습 니 다.
       커서 만 새로 고치 면 될 것 같 아 요.나중에 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");  
 } 
  
} 
        시리즈 글:
                       Android 개인 재 테 크 도구 6:계산서 내 역 표시
                        Android 개인 재 테 크 도구 5:계산서 내 역 표시
                       Android 개인 재 테 크 도구 4:계산서 페이지 추가
                       Android 개인 재 테 크 도구 3:계산서 페이지 추가
                        Android 개인 재 테 크 도구 2:SQLite 를 사용 하여 시작 할 때 데이터 초기 화
                        Android 개인 재 태 크 도구 1:프로젝트 개요 와 시작 인터페이스의 실현
       이상 은 안 드 로 이 드 개발 개인 재 태 크 도구 에 대해 계산서 페이지 의 설명 을 추가 하고 해당 하 는 글 을 계속 업데이트 합 니 다.본 사이트 에 대한 지원 에 감 사 드 립 니 다!

좋은 웹페이지 즐겨찾기