In Hiding
[android] 간단한 주소록(메모) 본문
이미지를 보면 대충 알 수는 있지만 아주 간단한 기능의 주소록이다.
구성은,
- 2개의 Activity : 정보 ListView / 입력창
- 3개의 Class : ListView Class / 입력창 Class / DB생성 Class
- 3개의 Layout xml : main, ListView를 정의하는 row, 입력창을 위한 input
기능은 이미지로도 알 수는 있지만 이미지에 별도 설명을 안 붙일것이라서 글로 쓰면
- 초기화면(ListView)은 DB에 저장된 데이터의 나열 / 다중삭제를 위한 CheckBox가 별도로 붙어있음
- ListView에 표시되는 Data는 성별, 이름, 주소 : 성별은 아이콘으로 표시
- 데이터 추가/삭제는 Menu 키를 눌러 선택할수 있도록
- Menu/추가를 누르면 빈 입력창 Activity가 호출
- 삭제는 CheckBox에서 삭제할 데이터를 선택 후 Menu/삭제를 누르면 처리
- ListView의 항목을 터치하면 터치한 데이터가 입력되어 있는 입력창 Activity를 호출, 수정할수 있도록 한다
- 입력창 Activity는 성별, 이름, 주소, 상세설명으로 구성되고 하단에 저장/취소 버튼을 둔다
- 저장을 누르면 Menu/추가 - 새 데이터 저장, ListView 항목 터치 - modify
- 취소는 다시 ListView로 돌아간다
먼저 xml 파일부터.
1) main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<ListView
android:id="@android:id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"></ListView>
</LinearLayout>
2) row.xml - ListView의 Layout을 정의
?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/linear"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<CheckBox
android:id="@+id/check"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="false"
android:focusable="false"
android:padding="5sp"></CheckBox>
<ImageView
android:id="@+id/image_sex"
android:layout_width="40sp"
android:layout_height="40sp"
android:padding="5sp"></ImageView>
<TextView
android:id="@+id/tv_sex"
android:layout_width="50sp"
android:layout_height="wrap_content"
android:padding="5sp"></TextView>
<TextView
android:id="@+id/tv_name"
android:layout_width="100sp"
android:layout_height="wrap_content"
android:padding="5sp"></TextView>
<TextView
android:id="@+id/tv_address"
android:layout_width="match_parent"
android:layout_height="wrap_content"></TextView>
</LinearLayout>
3) input.xml - 입력창의 Layout을 정의
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:id="@+id/LinearLayout01"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:text="성별"
android:layout_width="80sp"
android:layout_height="wrap_content"></TextView>
<EditText
android:id="@+id/input_sex"
android:layout_width="match_parent"
android:layout_height="wrap_content"></EditText>
</LinearLayout>
<LinearLayout
android:id="@+id/LinearLayout02"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:text="이름"
android:layout_width="80sp"
android:layout_height="wrap_content"></TextView>
<EditText
android:id="@+id/input_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"></EditText>
</LinearLayout>
<LinearLayout
android:id="@+id/LinearLayout03"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:text="주소"
android:layout_width="80sp"
android:layout_height="wrap_content"></TextView>
<EditText
android:id="@+id/input_address"
android:layout_width="match_parent"
android:layout_height="wrap_content"></EditText></LinearLayout>
<LinearLayout
android:id="@+id/LinearLayout04"
android:layout_width="match_parent"
android:layout_height="220sp"
android:orientation="vertical">
<TextView
android:text="상세내용"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5sp"></TextView>
<EditText
android:id="@+id/input_detail"
android:layout_width="match_parent"
android:layout_height="180sp"></EditText>
</LinearLayout>
<LinearLayout
android:id="@+id/LinearLayout05"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Button
android:id="@+id/save"
android:text="저장"
android:layout_width="165sp"
android:layout_height="wrap_content"></Button>
<Button
android:id="@+id/cancel"
android:text="취소"
android:layout_width="match_parent"
android:layout_height="wrap_content"></Button>
</LinearLayout>
</LinearLayout>
여기까지가 Layout 설정을 위한 xml 파일 내용이었다.
지금부터는 3개의 Class 파일.
1) Dbclass.class - DB 생성 기능을 하는 Class
package kr.xxx.address;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
public class Dbclass extends SQLiteOpenHelper {
static final String CREATE_TABLE =
"create table addressdb (" +
"_id integer primary key autoincrement, " +
"sex text not null, " +
"name text not null, " +
"address text not null, " +
"detail text not null);";
static final String DROP_TABLE =
"drop table addressdb;";
public Dbclass (Context c) {
super(c, "addressdb.db", null, 1);
}
@Override
public void onCreate(SQLiteDatabase db) {
// TODO Auto-generated method stub
db.execSQL(CREATE_TABLE);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// TODO Auto-generated method stub
db.execSQL(DROP_TABLE);
}
}
2) AddressView.class - ListView를 담당하는 Class
package kr.xxx.address;
import java.util.ArrayList;
import android.app.ListActivity;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.CursorAdapter;
import android.widget.ImageView;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.TextView;
public class AddressView extends ListActivity {
/** Called when the activity is first created. */
static final String TABLE_NAME = "addressdb";
SQLiteDatabase db;
Cursor cursor;
ListAdapter adapter;
ArrayList<String> isChecked;
Intent intent;
String id;
static final int MENU1_ID=Menu.FIRST;
static final int MENU2_ID=Menu.FIRST+1;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
intent = new Intent(this, InputWindow.class);
}
@Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
Dbclass dbclass = new Dbclass(this);
db = dbclass.getWritableDatabase();
cursor = fetchAllAddress();
startManagingCursor(cursor);
adapter = new HelloCursorAdapter(this, cursor);
setListAdapter(adapter);
cursor.requery();
}
@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
// TODO Auto-generated method stub
super.onListItemClick(l, v, position, id);
intent = new Intent(getApplicationContext(), InputWindow.class);
/* LinearLayout linear = (LinearLayout)v;
TextView vId = (TextView)linear.findViewById(R.id.tv_id);
TextView vSex = (TextView)linear.findViewById(R.id.tv_sex);
TextView vName = (TextView)linear.findViewById(R.id.tv_name);
TextView vAddress = (TextView)linear.findViewById(R.id.tv_address);*/
String pId = cursor.getString(0);
String pSex = cursor.getString(1);
String pName = cursor.getString(2);
String pAddress = cursor.getString(3);
String pDetail = cursor.getString(4);
String[] value = {pId, pSex, pName, pAddress, pDetail};
intent.putExtra("k", value);
startActivity(intent);
cursor.requery();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// TODO Auto-generated method stub
boolean result = super.onCreateOptionsMenu(menu);
menu.add(0, MENU1_ID, Menu.NONE, "추가");
menu.add(0, MENU2_ID, Menu.NONE, "삭제");
//MenuInflater inflater = new MenuInflater(this);
return result;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// TODO Auto-generated method stub
switch (item.getItemId()) {
case MENU1_ID:
String[] value = {null, null, null, "", ""};
intent.putExtra("k", value);
startActivity(intent);
db.close();
break;
case MENU2_ID:
for(String id:isChecked)
deleteAddress(id);
break;
}
return super.onOptionsItemSelected(item);
}
public void setAddress
(String id, String sex, String name, String address, String detail) {
ContentValues values = new ContentValues();
values.put("sex", sex);
values.put("name", name);
values.put("address", address);
values.put("detail", detail);
String[] where = {id};
db.update(TABLE_NAME, values, "_id=?", where);
}
public void deleteAddress (String id) {
String[] where = {id};
db.delete(TABLE_NAME, "_id=?", where);
cursor.requery();
}
public Cursor fetchAllAddress() {
String[] columns = {"_id", "sex", "name", "address", "detail"};
Cursor cur =
db.query(TABLE_NAME, columns, null, null, null, null, "_id DESC");
return cur;
}
class HelloCursorAdapter extends CursorAdapter {
public HelloCursorAdapter(Context context, Cursor c) {
// TODO Auto-generated constructor stub
super(context, c);
isChecked = new ArrayList<String>();
}
@Override
public void bindView(View view, Context context, Cursor cursor) {
// TODO Auto-generated method stub
String strID = cursor.getString(0);
//TextView id = (TextView)view.findViewById(R.id.tv_id);
//id.setText(strID);
//TextView sex = (TextView)view.findViewById(R.id.tv_sex);
//sex.setText(cursor.getString(1));
ImageView sex = (ImageView)view.findViewById(R.id.image_sex);
String svalue = cursor.getString(1);
String female = "female";
String female2 = "여";
sex.setImageResource(R.drawable.maleicon);
if(svalue.equals(female)){
sex.setImageResource(R.drawable.femaleicon);
}
if(svalue.equals(female2)){
sex.setImageResource(R.drawable.femaleicon);
}
TextView name = (TextView)view.findViewById(R.id.tv_name);
name.setText(cursor.getString(2));
TextView address = (TextView)view.findViewById(R.id.tv_address);
address.setText(cursor.getString(3));
CheckBox check = (CheckBox)view.findViewById(R.id.check);
check.setTag(strID);
check.setChecked(isChecked.contains((String)strID));
check.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
CheckBox c = (CheckBox)v;
if(c.isChecked())
isChecked.add((String)c.getTag());
else
isChecked.remove((String)c.getTag());
}
});
}
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
// TODO Auto-generated method stub
LayoutInflater inflater = getLayoutInflater();
View view = inflater.inflate(R.layout.row, null);
return view;
}
}
@Override
protected void onPause() {
// TODO Auto-generated method stub
super.onPause();
db.close();
}
}
3) InputWindow.class - 입력창 Activity에 해당하는 Class
package kr.xxx.address;
import android.app.Activity;
import android.content.ContentValues;
import android.content.Intent;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.RadioButton;
public class InputWindow extends Activity implements OnClickListener {
static final String TABLE_NAME = "addressdb";
Intent returnIntent;
SQLiteDatabase db;
String _id;
EditText sex;
EditText name;
EditText address;
EditText detail;
String[] sID;
//RadioButton males;
//RadioButton females;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.input);
returnIntent = new Intent (this, AddressView.class);
sID = getIntent().getStringArrayExtra("k");
Dbclass dbclass = new Dbclass(this);
db = dbclass.getWritableDatabase();
sex = (EditText)findViewById(R.id.input_sex);
name = (EditText)findViewById(R.id.input_name);
address = (EditText)findViewById(R.id.input_address);
detail = (EditText)findViewById(R.id.input_detail);
//males = (RadioButton)findViewById(R.id.male);
//females = (RadioButton)findViewById(R.id.female);
Button save = (Button)findViewById(R.id.save);
Button cancel = (Button)findViewById(R.id.cancel);
sex.setText(sID[1]);
name.setText(sID[2]);
address.setText(sID[3]);
detail.setText(sID[4]);
save.setOnClickListener(this);
cancel.setOnClickListener(this);
}
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
if(v.getId()== R.id.save){
if(sID[0]==null) {
addAddress(sex.getText().toString(), name.getText().toString(),
address.getText().toString(), detail.getText().toString());
}
else{
setAddress(sID[0], sex.getText().toString(), name.getText().toString(),
address.getText().toString(), detail.getText().toString());
}
startActivity(returnIntent);
}else if(v.getId()==R.id.cancel){
/*sex.setText("");
name.setText("");
address.setText("");
detail.setText("");*/ // case1)입력창 공백처리용
startActivity(returnIntent); //case2)ListActivity 호출용
}
}//Onclick 끝
public String addAddress
(String sex, String name, String address, String detail) {
ContentValues values = new ContentValues();
values.put("sex", sex);
values.put("name", name);
values.put("address", address);
values.put("detail", detail);
Long id = db.insert(TABLE_NAME, null, values);
return id.toString();
}
public void setAddress
(String id, String sex, String name, String address, String detail) {
ContentValues values = new ContentValues();
values.put("sex", sex);
values.put("name", name);
values.put("address", address);
values.put("detail", detail);
String[] where = {id};
db.update(TABLE_NAME, values, "_id=?", where);
}
@Override
protected void onPause() {
// TODO Auto-generated method stub
super.onPause();
db.close();
}
}
- 각각의 코드에 대응하는 설명은 생각나면 쓰겠다.
- Activity는 Intent를 써서 호출했고, 추가 기능시의 Data 전송은 Intent에 배열로 Data를 넣고
getStringArrayExtra를 써서 끄집어냈다. Parcelable이나 직렬화 객체를 써서 Bundle로 넘기는게
더 깔끔하긴 하다는데 100% 이해 못하는 코드는 어거지로 쓰지 않는 주의라서 일단 이렇게 처리.
- 꽤 조잡한 코딩이지만 혹시 이거라도 필요한 사람이 있을까봐 올려본다.