액티비티는 화면 하나라고 생각하면 된다. 하지만 실제 보이는건 뷰이며 액티비티는 뷰 또는 뷰 그룹을 가져와야 보이는 것이다. 또한 액티비티끼리는 중첩되지가 않는다.

다음은 버튼을 이용한 액티비티의 화면 전환 예제이다.

먼저 xml을 이용하여 서로 다른 화면을 구성해 둔다.

import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.app.Activity;
import android.content.Intent;

public class ImageViewActivity extends Activity{ 
 public void onCreate(Bundle savedInstanceState){
  super.onCreate(savedInstanceState);
  setContentView(R.layout.main);
  Button m_btn = (Button)findViewById(R.id.m_btn);
  m_btn.setOnClickListener(new Button.OnClickListener(){
   public void onClick(View v){
    Intent intent = new Intent(ImageViewActivity.this,subActivity.class);
    startActivity(intent);
   }
  });
 } 
}

위 코드를 보면 버튼을 이용하여 다른 화면을 나타나게 한다. 그리고 위에 인텐트라는 것이 보일 것인데 이는 액티비티간의 전
환 즉, 호출하여 화면을 바꿔 줄 수가 있다.

인텐트 액션 내용을 보면 다음과 같다.

 액션 대상  설명 
ACTION_CALL ACTIVITY 통화 시작
ACTION_EDIT ACTIVITY  테이터 표시 및 편짐
ACTION_MAIN ACTIVITY 메인 액티비티 호출
ACTION_VIEW ACTIVITY  화면 보이기
ACTION_DIAL ACTIVITY 전화 걸기
ACTION_BATTERY_LOW BR  배터리 부족
ACTION_HEADSET_PLUS BR 헤드셋 접속 구분
ACTION_SCREEN_ON BR  화면 열림
ACTION_TIMEZONE_CHANGED BR 타임 존 변경
 
다음은 서브 액티비티 코드이다. 동일한 내용 인 듯 하지만 finish() 라는 함수를 이용하여 화면의 종료를 나타내며 메인 액티비티로 돌아가게 한다.

public class subActivity extends Activity{
 public void onCreate(Bundle savedInstanceSatate){
  super.onCreate(savedInstanceSatate);
  setContentView(R.layout.subactivity);
  Button s_btn = (Button)findViewById(R.id.s_btn);
  s_btn.setOnClickListener(new Button.OnClickListener(){
   public void onClick(View v){
    finish();
   }
  });
 }
}

여기까지 하고 난 다음 또 매니페스트 파일에 내용을 추가 해 줘야 한다.  열어보면 하나의 액티비티만 정의 되어 있을 것이다.

서브 액티비티를 등록 해 줘야 한다는 점을 명심 해야한다.

[Android] SQL Android 2012. 3. 2. 15:40

안드로이드에서 데이터 베이스는 SQLite를 이용한다.

여기에서 SQLiteOpenHelper를 이용하여서 적용시키는데 간단히 코드로 구현을 하면 다음과 같다.

class DBHelper extends SQLiteOpenHelper{
 public DBHelper(Context context){
  super(context,"test.db",null,1);
 }

 @Override
 public void onCreate(SQLiteDatabase db) {
  // TODO Auto-generated method stub
  db.execSQL("CREATE TABLE data(id INTEGER PRIMARY KEY AUTOINCREMENT,"
         + "first TEXT, second TEXT);");
 }

 @Override
 public void onUpgrade(SQLiteDatabase db, int arg1, int arg2) {
  // TODO Auto-generated method stub
  db.execSQL("DROP TABLE IF EXISTS data");
  onCreate(db);
 }
}

다음은 해당하는 내용의 메서드들의 설명이다.

 메서드 내용 
 onCreat DB가 처음 만들어 질 때 호출 되며 테이블 생성 및 초기 레코드 입력 
 onUpgrade DB를 업그레이드 할 경우 호출. 기존 테이블을 삭제하고 새로 생성하거나 ALTER를 이용하여 DB를 수정
 onOpen DB를 열 때 이용
 getReadableDatabase 데이터를 읽기 위해 DB 열기
 getWriteableDatabase 읽고 쓰기 위한 DB 열기
 close DB 닫기


위 내용을 적용하여 CRUD 구문을 구현해보면 다음과 같다.

import android.app.Activity;
import android.app.Service;
import android.content.ContentValues;
import android.content.Context;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.Button;
import android.widget.TextView;

public class ImageViewActivity extends Activity{
 DBHelper m_dbhelper;
 EditText m_txt;
 public void onCreate(Bundle savedInstanceState){
  super.onCreate(savedInstanceState);
  setContentView(R.layout.main);
  
  m_dbhelper = new DBHelper(this);
  m_txt = (EditText)findViewById(R.id.txt);
  
  findViewById(R.id.insert).setOnClickListener(b_listener);
  findViewById(R.id.delete).setOnClickListener(b_listener);
  findViewById(R.id.update).setOnClickListener(b_listener);
  findViewById(R.id.select).setOnClickListener(b_listener);
 } 

 Button.OnClickListener b_listener = new View.OnClickListener() {
  
  @Override
  public void onClick(View v) {
   // TODO Auto-generated method stub
   SQLiteDatabase db;
   ContentValues row;
   switch(v.getId()){
    case R.id.insert :  
     db = m_dbhelper.getWritableDatabase();
     row = new ContentValues();
     row.put("1", "2");
     row.put("3", "4");
     db.insert("data", null, row);
     db.execSQL("INSERT INTO data VALUES (null,'5','6');");
     db.close();
     m_txt.setText("successed insert");
     break;
    case R.id.delete :  
     db = m_dbhelper.getWritableDatabase();
     row = new ContentValues();
     db.delete("data", null, null);     
     //db.execSQL("DELETE FROM data;");
     db.close();
     m_txt.setText("successed delete");
     break;
    case R.id.update :  
     db = m_dbhelper.getWritableDatabase();
     row = new ContentValues();
     row.put("first", "8");
     db.update("data", row, "first='1'", null); 
     //db.execSQL("UPDATE data SET first = '8' WHERE first = '1';");
     db.close();
     m_txt.setText("successed update");
     break;
    case R.id.select :  
     db = m_dbhelper.getWritableDatabase();
     Cursor cursor;
     //cursor = db.query("data", new String[]{"first","second"},null,null,null,null,null);     
     cursor = db.rawQuery("SELECT first, second FROM data", null);
     String result = "";
     while(cursor.moveToNext()){
      String first = cursor.getString(0);
      String second = cursor.getString(1);
      result+=(first+"="+second+"\n");
     }
     if(result.length()==0){
      m_txt.setText("No Data");
     }
     else{
      m_txt.setText(result);
     }
     cursor.close();
     db.close();
     break;
   }
  }
 };
}

이 내용은 프리퍼런스에 의존하여 데이터를 가지고 있을 수 있는 UI 이다.

단 제약이 있다면 PreferenceScreen 영역 안에 레이아웃을 작성해야한다.

다음이 그 xml 내용이다.

<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
    <EditTextPreference
        android:key="age"
     android:title="나이"
     android:summary="몇 살"
     android:defaultValue="19"
     />   
   <CheckBoxPreference
       android:key="male"
     android:title="성별"
     android:summary="남자?"
     android:defaultValue="true"    
    /> 
</PreferenceScreen>

여기 내용은 데이터가 변동 되더라도 자동으로 프리퍼런스에 접근하여 그때 그때 마다 내용을 기억 시킨다.

다음은 그 자바 코드이다.

package imageview.test;

import android.app.Activity;
import android.app.Service;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceActivity;
import android.view.View;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.*;
import java.io.*;

public class ImageViewActivity extends PreferenceActivity{
 TextView v_key, v_value;
 public void onCreate(Bundle savedInstanceState){
  super.onCreate(savedInstanceState);
  addPreferencesFromResource(R.layout.main);
 }
}

[Android] Preference Android 2012. 3. 2. 13:50

프리퍼런스는 일종의 환경 설정 파일과 동일한 형태라 생각하면 된다.

우리는 CS 프로그램을 만들다 보면 ini 와 같은 설정용 파일을 만드는데 안드로이드는 다음과 같이 하면 그런 형태를 만들어 낼 수 있다.

package imageview.test;

import android.app.Activity;
import android.app.Service;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.view.View;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.*;
import java.io.*;

public class ImageViewActivity extends Activity{
 TextView v_key, v_value;
 public void onCreate(Bundle savedInstanceState){
  super.onCreate(savedInstanceState);
  setContentView(R.layout.main);
  v_key = (TextView)findViewById(R.id.key);
  v_value = (TextView)findViewById(R.id.value);
  SharedPreferences ref = getSharedPreferences("ImageViewActivity",Service.MODE_PRIVATE);
  String key = ref.getString("key", "3");
  v_key.setText(key);
  int value = ref.getInt("value", 4);
  v_value.setText("" + value);
 } 
 
 public void onPause(){
  super.onPause();
  SharedPreferences ref = getSharedPreferences("ImageViewActivity",Service.MODE_PRIVATE);
  SharedPreferences.Editor edit = ref.edit();
  String key = v_key.getText().toString();
  int value = 0;  
  try{
  value = Integer.parseInt(v_value.getText().toString());
  }catch(Exception ex){}
  edit.putString("key", key);
  edit.putInt("value", value);
  edit.commit();
 }
}

위에 내용에서 보면 getSharedPreferences 을 이용하여 첫번째 인자 내용의 xml 파일엥서 그 내용을 편집하기 위해 지정한다.

이는 DDMS 에서 패키지 명을 찾아 그 아래 폴더를 찾아보면 나와 있다.

또한 반드시 해야 할 것은 commit 처리이다. 저것을 하지 않으면 저장이 되지 않는다.

[Android] 파일 관리 Android 2012. 2. 29. 15:48

안드로이드 상에서 파일 관리는 자바 코드와 동일한 형식이다.

단 리소스에 추가 한 것만 좀 다른데 아무래도 리소스에 포함해서 하는 것이 좋지 않나 싶다.

실제 배포 경우 파일을 누락하고 하면 문제가 크니까 말이다.

다음은 그 코드 내역이다.

package imageview.test;

import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.view.View;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.*;
import java.io.*;

public class ImageViewActivity extends Activity{
 EditText txt;
 public void onCreate(Bundle savedInstanceState){
  super.onCreate(savedInstanceState);
  setContentView(R.layout.main);
  txt = (EditText)findViewById(R.id.txt);
  findViewById(R.id.save).setOnClickListener(clicklistener);
  findViewById(R.id.load).setOnClickListener(clicklistener);
  findViewById(R.id.res).setOnClickListener(clicklistener);
  findViewById(R.id.delete).setOnClickListener(clicklistener);
 }
 
 Button.OnClickListener clicklistener = new View.OnClickListener() {  
  @Override
  public void onClick(View v) {
   switch(v.getId()){
    case R.id.save :
     try{
      FileOutputStream fos = openFileOutput("text.txt",Context.MODE_WORLD_READABLE);
      String str = "file save test";
      fos.write(str.getBytes());
      fos.close();
      txt.setText("Success");
     }
     catch(Exception btn1ex){}
     break;
    case R.id.load :
     try{
      FileInputStream fis = openFileInput("text.txt");
      byte[] data = new byte[fis.available()];
      while(fis.read(data)!=-1){}
      fis.close();
      txt.setText(new String(data));
     }
     catch(FileNotFoundException btn2ex){txt.setText("File Not Fount");}
     catch(Exception btn2ex){}
     break;
    case R.id.res :
     try{
      InputStream res = getResources().openRawResource(R.raw.test);
      byte[] data = new byte[res.available()];
      while(res.read(data)!=-1){}
      res.close();
      txt.setText(new String(data));
     }
     catch(Exception btn3ex){}
     break;
    case R.id.delete :
     try{
      if(deleteFile("text.txt")){
       txt.setText("Delete");
      }
      else{
       txt.setText("Delete Failed");
      }
     }
     catch(Exception btn4ex){}
     break;
   }
  }
 };
}

스크롤 뷰는 프레임 레이아웃의 하위 클래스이다.

말 그대로 이는 한 화면에 나타내지 못하는 내용들을 보여주기 위해서 이용하는 뷰이다.

예제 코드는 다음과 같다.

XML

<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/scr"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content">
</ScrollView>

Java

package imageview.test;

import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.os.Bundle;
import android.view.View;
import android.widget.*;

public class ImageViewActivity extends Activity{
 public void onCreate(Bundle savedInstanceState){
  super.onCreate(savedInstanceState);
  setContentView(R.layout.main);
  ScrollView svw = (ScrollView)findViewById(R.id.scr);
  svw.addView(new ColorView(this));
 }
}

class ColorView extends View{
 String m_Text="";
 public ColorView(Context context){
  super(context);
 }
 public void onDraw(Canvas canvas){
  Paint pnt = new Paint();
  for(int i=0;i<1024;i+=4){
   pnt.setARGB(255, 255-i/4, 255-i/4, 255);
   canvas.drawRect(0, i,500,i+4,pnt);    
  }
 }
 
 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
  setMeasuredDimension(500,1024);
 }
}

다음은 웹뷰이다.

웹뷰는 C#으로 친다면 WebBrowser 와 같은 역할이다.

간단한 테스트 코드를 보자면 다음과 같다.

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">
    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content">
  <Button
      android:id="@+id/btn1"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content" 
      android:text="go"   
  />  
  <Button
      android:id="@+id/btn2"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="back"
      />
  <Button
      android:id="@+id/btn3"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="forward"
      />
  <Button
      android:id="@+id/btn4"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="local"
      />  
 </LinearLayout>
    <FrameLayout android:layout_width="fill_parent" android:layout_height="wrap_content"> 
  <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" > 
   <WebView
       android:id="@+id/web"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:visibility="visible">   
   </WebView>
  </LinearLayout>
 </FrameLayout>
</LinearLayout>

다음은 자바 코드이다.

package imageview.test;

import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.*;

public class ImageViewActivity extends Activity{
 WebView web;
 public void onCreate(Bundle savedInstanceState){
  super.onCreate(savedInstanceState);
  setContentView(R.layout.main);
  web = (WebView)findViewById(R.id.web);
  web.setWebViewClient(new webClient());
  WebSettings set = web.getSettings();
  set.setJavaScriptEnabled(true);
  set.setBuiltInZoomControls(true);
  web.loadUrl("http://www.google.com");  
 }
 
 class webClient extends WebViewClient{
  public boolean shouldOverriderUrlLoading(WebView view, String url){
   view.loadUrl(url);
   return true;
  }
 }
}

[Android] Custom Widget-2 Android 2012. 1. 26. 15:01

다음은 에디트 + 텍스트 뷰 포함하는 라이너 위젯이다.

예제 코드를 실행 해 보면 입력 문자의 수를 파악 할 수 있다.

XML Code

<?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">
   
    <imageview.test.Edit_Widget
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
    />
</LinearLayout>

Java Code

package imageview.test;

import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.text.*;
import android.util.*;
import android.widget.*;

public class ImageViewActivity extends Activity{
 public void onCreate(Bundle savedInstanceState){
  super.onCreate(savedInstanceState);
  setContentView(R.layout.main);
 }
}

class Edit_Widget extends LinearLayout implements TextWatcher{
 EditText m_edit;
 TextView m_text;
 
 public Edit_Widget(Context context){
  super(context);
  init();
 }
 
 public Edit_Widget(Context context, AttributeSet att){
  super(context, att);
  init();
 }
  
 private void init(){
  setOrientation(LinearLayout.VERTICAL);
  m_edit = new EditText(getContext());
  m_text = new TextView(getContext());
  m_text.setText("Now Length : 0");
  LinearLayout.LayoutParams param = new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);
  addView(m_edit, param);
  addView(m_text, param);
  m_edit.addTextChangedListener(this);
 }

 public void afterTextChanged(Editable arg0) {
 }

 public void beforeTextChanged(CharSequence arg0, int arg1, int arg2,int arg3) {
 }

 public void onTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {
  m_text.setText("Now Length : " + arg0.length());
 }
}
여기에선 잘 살펴보면 TextWatcher를 이용하여 확장 개념으로 적용 한 것이다.

또한 텍스트 위젯들을 XML에 적용해서 하지 않고 바로 코드에 쓴 케이스로 XML에 적용할 경우 findViewById를 이용하여 각기 할당하여 사용하면 된다.

[Android] Custom Widget-1 Android 2012. 1. 26. 13:40

커스텀 위젯은 기존 위젯 클래스를 상속받아 기능을 확장, 수정하는 것을 말한다. 단, ViewGroup Or 파생 클래스 확장하여 내부 위젯 작용까지도 처리를 해야한다.

간단한 예를 보면 다음과 같다. 문자를 입력하면 사운드가 나온다.

물론 사전작업으로 raw에 mp3 파일을 등록한 후 작업한다.

XML Code

<?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">
    <TextView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="input text"
    />
    <imageview.test.SoundEditWidget
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:textSize="12pt"
    />
</LinearLayout>

imageview.test.SoundEditWidget 이 부분을 보면 Package 명이 섞여 있다!! 필자가 공부하는 책엔 이게 뭔지 명시가 되어 있지 않아 개인적으로 만든 Package 이용시 굉장히 헛갈렸다.

Java Code

package imageview.test;

import android.app.Activity;
import android.content.Context;
import android.media.AudioManager;
import android.media.SoundPool;
import android.os.Bundle;
import android.util.AttributeSet;
import android.widget.EditText;

 

public class ImageViewActivity extends Activity{
 public void onCreate(Bundle savedInstanceState){
  super.onCreate(savedInstanceState);
  setContentView(R.layout.main);
 }
}

class SoundEditWidget extends EditText{
 SoundPool m_pool = null;
 int m_click;
 public SoundEditWidget(Context context){
  super(context);
  init(context);
 }
 
 public SoundEditWidget(Context context, AttributeSet att){
  super(context, att);
  init(context);
 }
 
 public SoundEditWidget(Context context, AttributeSet att, int defStyle){
  super(context, att, defStyle); 
  init(context);
 }
 
 private void init(Context context){
  m_pool = new SoundPool(1,AudioManager.STREAM_MUSIC,0);
  m_click = m_pool.load(context, R.raw.aid, 1);
 }
 
 protected void onTextChanged(CharSequence text, int start, int before, int after){
  if(m_pool != null){
   m_pool.play(m_click, 1,1,0,0,1);
  }
 }
}
이 코드들을 작성하다가 팁 하나!! 이클립스를 사용하는 분들은 알겠지만 Ctrl + Shift + O 를 누르면 import 대상들이 자동 import 된다.

[Android] RatingBar Android 2011. 12. 21. 16:02

레이팅바는 흔히 많이 보는 별 모양을 클릭하면서 점수를 입력 받는 것이다.

XML은 다음과 같이 작성을 한다.

<RatingBar
        android:id="@+id/ratingbar1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:stepSize="0.2"
        android:rating="3"
    />

여기에서 stepSize는 클릭 위치에 따라 얼마나 rating을 증가 시킬 것인가 이고 rating은 현재 값 설정이다.

numStars의 경우는 별의 숫자, isIndicator는 편집 가능 유무를 말하며 true로 둘 경우 편집이 불가능 하다.

또한 style="?android:attr/ratingBarStyleSmall 은 별의 형태를 작게 나타내며 읽기 전용으로 변화가 되고, ratingBarStyleIndicator를 적용하면 그냥 읽기 전용으로 적용이 된다.

테스트 할 자바 파일은 다음과 같다.

public class ImageViewActivity extends Activity{
 RatingBar _rating;
 TextView _text;
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
       
        _rating = (RatingBar)findViewById(R.id.ratingbar1);
        _text = (TextView)findViewById(R.id.text);
       
        _rating.setOnRatingBarChangeListener(new RatingBar.OnRatingBarChangeListener() {   
   @Override
   public void onRatingChanged(RatingBar ratingBar, float rating, boolean fromUser) {
    _text.setText("Value : " + rating);
   }
  });
    } 
}

[Android] SeekBar Android 2011. 12. 21. 15:49
C# 으로 치면 Track Bar이다. 이것은 사용자가 조절해서 그 값을 변경 할 수가 있다.

이는 프로그레스를 확장한 서브 클래스 이다.

XML에

<SeekBar
        android:id="@+id/seekbar"
        style="?android:attr/progressBarStyleHorizontal"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:max="100"
        android:progress="50"
    />

추가를 하고 자바 파일은 아래와 같이 작성하고 실행해서 그 결과를 확인 해 보면 어떤 용도인지 알 수가 있을 것이다.

public class ImageViewActivity extends Activity{
 SeekBar _seek;
 TextView _text;
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
       
        _seek = (SeekBar)findViewById(R.id.seekbar);
        _text = (TextView)findViewById(R.id.text);
       
        _seek.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
   
   public void onStopTrackingTouch(SeekBar seekBar) {
   }
   
   public void onStartTrackingTouch(SeekBar seekBar) {
    
   }
   
   public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
    _text.setText("Value : " + progress);
   }
  });
    } 
}