2011년 8월 31일 수요일

Android - Spinner 예제


Spinner - Android 에서 사용하는 콤보 박스

사용 예는 아래와 같다.


gradeList = new ArrayList<String>();

gradeList.add("");
gradeList.add("SUN");
gradeList.add("MON");
gradeList.add("TUE");
gradeList.add("WED");
gradeList.add("THU");
gradeList.add("FRI");
gradeList.add("SAT");

ArrayAdapter<String> arrayAdapterGrade = new ArrayAdapter<String>(context, android.R.layout.simple_spinner_item, gradeList);


arrayAdapterGrade.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);


spnrGrade.setPromptId(R.string.grade);


spnrGrade.setAdapter(arrayAdapterGrade);

(spnrGrade : Spinner)



현재 요일을 자동으로 선택하고 싶다면 아래 코드를 추가 하면 된다.

Calendar c = Calendar.getInstance();
position = c.get(Calendar.DAY_OF_WEEK) // 일요일 - 1, 월요일 - 2, 화요일 - 3 ...
spnrGrade.setSelection(position)

위와같이 setSelection(int position)  함수를 이용하면 된다.




현재 선택된 item 을 알고 싶으면

String todayIs = gradeList.get(getSelectedItemPosition());

와 같이 getSelectedItemPosition() 함수를 이용하면 된다.



2011년 8월 26일 금요일

Android - EditText 값 입력 제어 (TextWatcher 사용)

TextWatcher

사용 목적
 - EditText에 값이 입력되는 경우 입력 값의 유효성을 검증하여 입력할지 말지를 결정 한다거나.
  값이 입력될때 무언가를 해주고 싶을때 사용한다.

기타 자세한 설명은...
http://developer.android.com/reference/android/text/TextWatcher.html
를 참고


설명을 보면 알겠지만 TextWatcher 는 interface로 아래 3개의 method를 가지고 있다.

public void afterTextChanged(Editable s) {
// TODO Auto-generated method stub
}


@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
// TODO Auto-generated method stub
}


@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
// TODO Auto-generated method stub
}



사용 예는 아래와 같다

EditText et = new EditText();
et.addTextChangedListener(new TextWatcher() {

@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
// TODO Auto-generated method stub
Log.w("onTextChanged", s.toString());
}

@Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
// TODO Auto-generated method stub
Log.w("onTextChanged", s.toString());
}

@Override
public void afterTextChanged(Editable s) {
// TODO Auto-generated method stub
Log.w("onTextChanged", s.toString());
}
});

위와 같이 하면 et 에 값을 입력할때마다 log가 찍힌다.


본인 같은 경우에는 월(month)를 입력받는 EditText를 만들때 사용했다.
1~12월 사이의 숫자만 입력되야 하기 때문에 아래와같이 코딩했다.

TextWatcher를 상속받은 MonthTextWatcher 를 정의하여 제어 함.

//editTextBeginMonth 는 EditText


MonthTextWatcher endWatcher = new MonthTextWatcher(editTextEndMonth);
editTextBeginMonth.addTextChangedListener(beginWatcher);






//month EditText에 12를 초과하는 값이 못들어가게 제어
private class MonthTextWatcher implements TextWatcher{
EditText et;
String beforeText;

public MonthTextWatcher(EditText et){
this.et = et;
}

@Override
public void afterTextChanged(Editable s) {
// TODO Auto-generated method stub
if(s.toString().length() > 0){
if(Integer.parseInt(s.toString()) > 12){
et.setText(beforeText);
}
}
}


@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
// TODO Auto-generated method stub
beforeText = s.toString();
}


@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
// TODO Auto-generated method stub
}

}





2011년 8월 22일 월요일

SQLite - ... has more than one primary key

DB Table ("T_TIMETABLE ") 생성시 에러 발생

table "T_TIMETABLE" has more than one primary key


CREATE TABLE 구문은...


CREATE TABLE IF NOT EXISTS T_TIMETABLE ( subject_id text primary key, day text primary key, begin_tm text primary key, end_tm text primary key )


SQLite 에서 1개 이상의 칼럼을 기본 키로 설정 하고 싶다면

CREATE TABLE 문을 아래와 같이 사용해야 한다.


CREATE TABLE IF NOT EXISTS T_TIMETABLE ( subject_id text, day text, begin_tm text, end_tm text, PRIMARY KEY ( subject_id, day, begin_tm, end_tm) )

Android - Can't upgrade read-only database from version...

아무 문제가 없을거라고 생각했던 프로그램에서 에러가 났다

내가 한거라고는 그냥 DB Table 생성하는 부분만 코딩했을 뿐인데...

에러 내용은

android.database.sqlite.SQLiteException: Can't upgrade read-only database from version 0 to 1: /data/data/....




원인은...

잘못된 CREATE 문 때문이었다.

CREATE TABLE IF NOT EXISTS T_CONFIG ( config_id text primary key, values text, description text, opt1 text, opt2 text, opt3 text )


SQLite에서 values 라는 칼럼명은 허용이 안된다는걸 알게 되었다.



ps .
아래와 같이 수정하니 에러가 사라졌다.

CREATE TABLE IF NOT EXISTS T_CONFIG ( config_id text primary key, vals text, description text, opt1 text, opt2 text, opt3 text )


2011년 8월 10일 수요일

Java - Singleton (Design Pattern)

어떤 시스템에 단 한개의 인스턴스만 존재하는경우 사용

음.... 어떤 시스템의 테마나 설정값 같은경우 서로다른 화면마다 공통된 값을 적용해야 한다.

이럴때 사용하면 좋은게 싱글톤(Singleton) 패턴 이다.

기본적인 구조는...


public class Theme{
   private static Theme theme = new Theme();

   public static Theme getInstance(){
      return theme;
   }
}

이렇게 설정 클래스 정의하고 아래와 같이 사용하면 된다.

public class Main{
   public static void main(String[] args){
      Theme t1 = Theme.getInstance();
      Theme t2 = Theme.getInstance();
   }
}

위에서의 t1, t2는 서로 동일한 객체 이다.

이와같이 Singleton을 사용하여 동일한 객체를 아무데서나 사용 할 수 있다.

불필요한 작업없이 공통적으로 사용될 설정값, 데이터set 등을 싱글톤으로 정의하고 사용하면 편할듯 하다...

2011년 8월 1일 월요일

Android - Custom View 에 xml 로 속성 부여하기, CUSTOM BUTTON

목적
사용자가 정의한 cutom view를 layout xml에서 정의해서 사용할 경우
사용자가 정의한 custom view의 속성에 값을 layout xml 파일에서 설정 할 수 있다.
(음.. 설명이 어렵군..)

예)
ImageButton이 맘에 들지 않아 ImageView를 상속받은 custom button을 만들려고 한다.


다른부분은 별다른 수정없이 사용 가능하지만


ACTION_DOWN, ACTION_UP 시 이미지를 변화시키는 로직을 custom button 안에 구현하고 싶다.


그러기 위해서 custom view 클래스는 평상시 icon과 눌려졌을때(ACTION_DOWN) icon 에 대한 속성값을 가지고 있어야 하고


이 속성들을 이용해서 onTouchListener를 구성해주면 된다.


위에서 언급한 icon들을 class 파일에서 설정해 줄 수 있지만


왠지 코드가 지저분해지는거 같아 layout xml파일에서 해당 속성을 입력해주고싶다.


뭐 이런 상황에서 사용하는 방법이다.

간단하게 설명하면,

추가할 속성값들을 새로운 xml 파일로 정의하고, 정의된 xml 파일을 layout의 namespace에 추가해서 사용하는 형태인데

이것도 말로 하면 복잡하니까 예를 들어 설명하면


1. res/values/attr.xml - 신규작성 : 신규 속성을 정의할 xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="CustomImageButton">
    <attr name="icon" format="integer" />
        <attr name="icon_selected" format="integer" />
    </declare-styleable>
</resources>



2. CustomImageButton.java - custom button 클래스


package jh;

import jh.R;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageView;

public class CustomImageButton extends ImageView{

private Drawable icon;
private Drawable iconSelected;

public CustomImageButton(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setTouchEvent();
setIcons(context, attrs);
// TODO Auto-generated constructor stub
}

public CustomImageButton(Context context, AttributeSet attrs) {
super(context, attrs);
setTouchEvent();
setIcons(context, attrs);
// TODO Auto-generated constructor stub
}

public CustomImageButton(Context context) {
super(context);
setTouchEvent();

// TODO Auto-generated constructor stub
}


private void setIcons(Context context, AttributeSet attrs){
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CustomImageButton);


icon = a.getDrawable(R.styleable.CustomImageButton_icon);
iconSelected = a.getDrawable(R.styleable.CustomImageButton_icon_selected);
}

private void setIconNormal(){
if (icon != null) {
this.setImageDrawable(icon);
}
}

private void setIconSelected(){
if (iconSelected != null) {
this.setImageDrawable(iconSelected);
}
}

private void setTouchEvent(){
this.setOnTouchListener(new OnTouchListener() {

@Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
if (event.getAction() == MotionEvent.ACTION_DOWN){
setIconSelected();
}else if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL || event.getAction() == MotionEvent.ACTION_OUTSIDE){
setIconNormal();
}

return false;
}
});
}

}




3. res/layout/subject.xml - layout 파일

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res/jh"
android:layout_width="fill_parent"
    android:layout_height="fill_parent" android:background="#fffbfbfb">
 
    <LinearLayout
    android:id="@+id/contentLayout"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_alignParentTop="true"
    android:layout_centerHorizontal="true"
     >
     
        <LinearLayout android:layout_height="wrap_content" android:id="@+id/linearLayout2" android:layout_width="match_parent">
            <Spinner android:layout_height="wrap_content" android:id="@+id/spinner1" android:layout_weight="1" android:layout_width="wrap_content"></Spinner>
         
            <jh.project.whomli.school.custom.CustomImageButton app:icon="@drawable/utilicon_add" app:icon_selected="@drawable/utilicon_add_selected" android:layout_height="wrap_content" android:layout_width="wrap_content" android:id="@+id/subjectBtnAdd" android:src="@drawable/utilicon_add" android:layout_weight="0" android:clickable="true"></jh.project.whomli.school.custom.CustomImageButton>
        </LinearLayout>

    </LinearLayout>

</RelativeLayout>




뭐 이런식으로 사용하면 된다.

뭔가 단순하면서도 유용할듯하다.