2012/07/16
200개의 단계별 예제로 배우는 안드로이드 4.0
|
새로운 맘으로 다시 공부를 시작해 보려 책을 샀다. 두툼한 책으로 예제 중심으로 되어 있고 최식 버전에 대한 설명도 있다.
안드로이드의 기본 개념부터 구성및 기초 그리고 활용까지 다루고 있다. 작가도 Android Side 운영자이면서 Java관련 서적을 다수 집필한 한 동호 님이다.
목차 보기
PART 1 안드로이드 기본 개념
SECTION 01 안드로이드 개요 _2
SECTION 02 안드로이드 플랫폼 특징 _3
SECTION 03 안드로이드 버전 히스토리 _4
SECTION 04 안드로이드 버전별 시장 분포 _5
SECTION 05 안드로이드 화면 크기와 해상도별 시장 분포 _7
SECTION 06 안드로이드 2.2의 주요 변화 _9
SECTION 07 안드로이드 2.3의 주요 변화 _10
SECTION 08 안드로이드 3.0의 주요 변화 _12
SECTION 09 안드로이드 4.0의 주요 변화 _13
SECTION 10 안드로이드 실행 환경 _16
SECTION 11 안드로이드 개발 환경 _18
SECTION 12 안드로이드 HelloWorld 작성하기 _19
SECTION 13 안드로이드 프로젝트 구조 _27
SECTION 14 안드로이드 에뮬레이터 살펴보기 _39
PART 2 안드로이드 구성요소
SECTION 01 안드로이드 주요 용어 _50
SECTION 02 안드로이드의 4대 주요 컴포넌트 _51
SECTION 03 안드로이드 애플리케이션 구조 _52
SECTION 04 액티비티 살펴보기 _53
SECTION 05 서비스 살펴보기 _58
SECTION 06 브로드캐스트 리시버 살펴보기 _60
SECTION 07 콘텐트 프로바이더 살펴보기 _61
SECTION 08 인텐트와 인텐트 필터 살펴보기 _63
SECTION 09 통지 살펴보기 _71
SECTION 10 컴포넌트 활성화 및 비활성화 _73
PART 3 안드로이드 사용자 인터페이스
SECTION 01 안드로이드 인터페이스 구성요소 _76
SECTION 02 뷰 _77
SECTION 03 뷰 컨테이너 _108
SECTION 04 레이아웃 _128
PART 4 안드로이드 기초
SECTION 01 로그와 뷰 추가 방법 _138
SECTION 02 스타일과 테마 _147
SECTION 03 리소스 _162
SECTION 04 버튼 _170
SECTION 05 에디트텍스트 _181
SECTION 06 스피너 _189
SECTION 07 액티비티 _193
SECTION 08 키/터치 이벤트 _212
SECTION 09 스크롤뷰 _233
SECTION 10 그리드뷰 _241
SECTION 11 갤러리 _245
SECTION 12 뷰플리퍼 _262
SECTION 13 슬라이딩드로어 _270
SECTION 14 레이아웃 _281
SECTION 15 폰트 _291
SECTION 16 토스트 296
SECTION 17 다이얼로그 _307
SECTION 18 상태바 _326
SECTION 19 메뉴 _331
SECTION 20 환경설정 _341
SECTION 21 이미지/그래픽 _367
SECTION 22 웹뷰 _378
PART 5 안드로이드 활용
SECTION 01 액션바(ActionBar) _404
SECTION 02 프래그먼트(Fragment) _441
SECTION 03 스레드(Thread) _489
SECTION 04 리스트뷰 활용하기 _514
SECTION 05 확장 리스트뷰 활용하기 _546
SECTION 06 파일 활용하기 _556
SECTION 07 데이터베이스 활용하기 _572
SECTION 08 인텐트 활용하기 _592
SECTION 09 XML _633
SECTION 10 브로드캐스트 리시버 _641
SECTION 11 SMS 송신 및 수신하기 _651
SECTION 12 콘텐트 프로바이더 활용하기 _670
SECTION 13 위치 정보 활용하기 _677
SECTION 14 구글 맵 활용하기 _714
SECTION 15 전화 _763
SECTION 16 애니메이션 _783
SECTION 17 네트워크 활용하기 _791
SECTION 18 서비스 _816
SECTION 19 애플리케이션 위젯 _837
SECTION 20 SD 카드 _858
SECTION 21 서피스뷰 _864
SECTION 22 기타 _880
부록
A 개발자 등록 및 애플리케이션 마켓 배포 _890
B TIP & TECH 리스트 _904
C 프로젝트 리스트 _907
D API 리스트 _914
E 안드로이드 개발 환경 구축하기 _918
F 이클립스 개발 환경 구성하기 _937
G 이클립스 개발 팁 살펴보기 _940
찾아보기 _944
아직 읽기전이라 서평을 하기는 이른 단계이지만 목차의 구성으로 봐서는 꽤 유용한 책으로 생각된다.
틈틈이 조금 공부하다 한동안 잊고 있었더니 그동한 공부해왔던 내용도 잊었다.
취미 생활격으로 하다보니 시간도 그리 많지 않고 자주 잊어버리곤 하는데 처음부터 다시 시작 하는 맘으로 공부를 해봐야 겠다.
아이들이 표지를 보더니
맛있는 초코렛이라고 달려들었는데 나에게도 이 책이 그렇게 맛있는 모습로 다가와 주었으
Original Post : http://neodreamer-dev.tistory.com/671
2012/07/03
Hello Jelly Bean on Juno (Eclipse 4.2)
새로운 개발 환경도 구축할 겸 해서 Juno로 안드로이드 개발 환경을 구축하였고 언제나 하는 Hello Project를 만들었다.
새로운 프로젝트를 만든는 절차는 크게 바뀌지 않았다.
중간에 UI 관련하여 추가로 설정하는 단계가 추가 되었다.
그리고 Activity 관련 설정도 추가되었다.
마지막 단계에서 "Android Support Library" 문제에 봉착을 하였다.
현재 설치된 버전이 9임에도 검출되지 않았고 UI에서의 지시에 따라 몇번의 Install 시도를 해 보았지만 마지막 단계로 가는 Finish 버튼이 활성화 되지 않았다.
결국 Juno를 종료하고 SDK Manager 에서 이미 설치되어 있던 Version 9를 삭제하고 다시 설치하였다.
다시 실행시킨 Juno에서 프로젝트 생성 단계에 문제가 생기기 않았다.
Hello 프로젝트를 진저브레드와 젤리빈 에뮬레이터에서 실생시켜 보았다.
조정이 가능한지 모르겠지만 젤리빈에서의 작업 영역이 줄어들었다.&
Original Post : http://neodreamer-dev.tistory.com/668
2011/03/07
[Android Dev.] Activity 간 데이터 주고 받기
Intent intentSubActivity = new Intent( this, SubActivity.class );
intentSubActivity.putExtra( "Name", "Intent Data" );
intentSubActivity.putExtra( "Age", 30 );
intentSubActivity.putExtra( "Marriage", false );
startActivity( intentSubActivity );
넘어온 데이터 받기
Intent intent = getIntent();
String strName = intent.getStringExtra( "Name" );
Integer nAge = intent.getIntExtra( "Age", 0 );
Boolean bMarriage = intent.getBooleanExtra( "Marriage", false );
String strMsg;
strMsg = "Name : " + strName + " Age : " + nAge + " Marrige : " + strMarriage;
Log.i( "SubActivity", strMsg );
INFO/SubActivity(xxx): Name : Intent Data Age : 30 Marrige : X
Original Post : http://neodreamer-dev.tistory.com/515
2011/02/24
[Android Dev.] Emulator 단축키 (화면 회전, 볼륨 조절 등)
화면을 회전시켜서 보기위해 방법을 찾던 중 알게된 것들이다.
Emulated Device Key | Keyboard Key |
Home | HOME |
Menu (left softkey) | F2 or Page-up button |
Star (right softkey) | Shift-F2 or Page Down |
Back | ESC |
Call/dial button | F3 |
Hangup/end call button | F4 |
Search | F5 |
Power button | F7 |
Audio volume up button | KEYPAD_PLUS, Ctrl-F5 |
Audio volume down button | KEYPAD_MINUS, Ctrl-F6 |
Camera button | Ctrl-KEYPAD_5, Ctrl-F3 |
Switch to previous layout orientation (for example, portrait, landscape) | KEYPAD_7, Ctrl-F11 |
Switch to next layout orientation (for example, portrait, landscape) | KEYPAD_9, Ctrl-F12 |
Toggle cell networking on/off | F8 |
Toggle code profiling | F9 (only with -trace startup option) |
Toggle fullscreen mode | Alt-Enter |
Toggle trackball mode | F6 |
Enter trackball mode temporarily (while key is pressed) | Delete |
DPad left/up/right/down | KEYPAD_4/8/6/2 |
DPad center click | KEYPAD_5 |
Onion alpha increase/decrease | KEYPAD_MULTIPLY(*) / KEYPAD_DIVIDE(/) |
출처 : http://developer.android.com/guide/developing/tools/emulator.html
<
Original Post : http://neodreamer-dev.tistory.com/509
2010/09/18
[Android Tips] 화면 상태 확인 하기
Android 2.1 이하에서는 getOrientation() 만 동작하며 Android 2.2 이상에서는 getOrientation() 과 getRotation() 이 동작을 한다.
Android 2.1 이하
WindowManager wm = (WindowManager)getSystemService(Context.WINDOW_SERVICE);
Display disp = wm.getDefaultDisplay();
int orientation = disp.getOrientation(); // Android 2.1
Log.i( "Orientation", "orientation : " + orientation );
Android 2.2 이상
WindowManager wm = (WindowManager)getSystemService(Context.WINDOW_SERVICE);
Display disp = wm.getDefaultDisplay();
int rotation = disp.getRotation(); // Android 2.2
Log.i( "Rotation", "rotation : " + rotation );
switch ( rotation )
{
case Surface.ROTATION_0:
Log.i( "Roation", "Portrait : 0" );
break;
case Surface.ROTATION_90:
Log.i( "Roation", "Landscape : 90" );
break;
case Surface.ROTATION_180:
Log.i( "Roation", "Portrait : 180" );
break;
case Surface.ROTATION_270:
Log.i( "Roation", "Landscape : 270" );
break;
}
<Original Post : http://neodreamer-dev.tistory.com/460
[Android Tips] 화면 해상도 알아내기
방법 #1
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
int ScreenWidth = metrics.widthPixels
int ScreenHeight = metrics.heightPixels
<
WindowManager wm = (WindowManager)getSystemService(Context.WINDOW_SERVICE);
Display dsp = wm.getDefaultDisplay();
int height = dsp.getHeight();
int width = dsp.getWidth();
Original Post : http://neodreamer-dev.tistory.com/459
2010/09/15
[Android Dev.] 화면 회전에 대응하는 UI 구성하기
아주 단순한 layout 구성으로 기본적인 TextView 와 버튼 두개로 구성된 UI 이다. 파일 이름은 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"
android:layout_gravity="center_vertical|center_horizontal"
>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello"
/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button 1"
/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button 2"
/>
</LinearLayout>
위의 layout 구성은 아래와 같은 화면이다.
이 화면을 가로(Landscape)로 변경(에뮬레이터에서 Ctrl+F11)을 하면 아래와 같은 화면이 된다. UI 구성이 변하지 않은 화면이 나온다.
세로 방향 구성과는 다르게 가로 방향의 UI 구성을 새로 하기 위해서는 res 폴더에 layout-land 폴더를 만들고 layout 폴더에 있는 구성 파일과 동일한 UI 구성 파일(xml)을 만들어 작성을 하면 화면의 회전에 따라 각각의 UI 구성이 출력 된다.
아래는 layout-land 폴더에 작성한 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"
android:layout_gravity="center_vertical|center_horizontal"
>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello"
/>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_gravity="center_vertical|center_horizontal"
>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button 1"
/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button 2"
/>
</LinearLayout>
</LinearLayout>
이 소스를 실행 시켜서 화면 전환을 해 보면 아래와 같은 변화된 UI 의 화면을 볼 수 있다.
2010/07/05
[Android Dev.] Touch 이벤트 사용하기
Touch 이벤트는 TouchListener 를 등록하여 onTouch 함수를 오버라이드 하여 구현을 하거나 onTouchEvent 함수를 오버라이드 하여 구현할 수 있다.
두 방법간의 큰 차이는 없고 어떠한 함수를 통해서 Touch 이벤트를 핸들링 하는가만 다른 것 같다. Touch Listener 를 등록하여 구현하는 경우는 Activity 에 전달 되는 Touch 에서 전체적으로 핸들링 할 수 있지만 내부 View 의 onTouchEvent 를 오버라이드하여 구현하는 경우에는 해당 뷰의 Touch 이벤트에 국한 된다는 차이가 있는데 이는 Touch 구현 범위에 따라 선택을 하여야 할 것 같다.
ACTION_DOWN | ACTION_MOVE | ACTION_UP |
Touch Listener 를 등록하여 구현하는 방법
import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.OnTouchListener;
import android.widget.LinearLayout;
import android.widget.TextView;
public class TouchTest extends Activity implements OnTouchListener
{
/** Called when the activity is first created. */
TextView tvStatus;
Canvas2D canvas;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
//setContentView(R.layout.main);
LinearLayout layout = new LinearLayout(this);
layout.setOrientation( LinearLayout.VERTICAL );
LinearLayout.LayoutParams param = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.FILL_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT );
layout.setLayoutParams( param );
tvStatus = new TextView(this);
layout.addView( tvStatus );
tvStatus.setText( "Touch Status" );
canvas = new Canvas2D( this );
ViewGroup.LayoutParams canvasParam = new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.FILL_PARENT,
ViewGroup.LayoutParams.FILL_PARENT );
layout.addView( canvas, canvasParam );
canvas.setOnTouchListener( this );
setContentView( layout );
}
class Canvas2D extends View
{
public Canvas2D(Context context)
{
super(context);
}
@Override
public void onDraw( Canvas canvas )
{
// Canvas 배경 설정
canvas.drawColor( Color.parseColor("#888888") );
}
}
@Override
public boolean onTouch( View v, MotionEvent event )
{
if ( v == canvas )
{
Log.i( "event", "Canvas2D onTouch" );
switch (event.getAction())
{
case MotionEvent.ACTION_DOWN:
{
String strMsg;
strMsg = "ACTION_DOWN X: " + event.getX() + " Y:" + event.getY();
tvStatus.setText( strMsg );
}
break;
case MotionEvent.ACTION_MOVE:
{
String strMsg;
strMsg = "ACTION_MOVE X: " + event.getX() + " Y:" + event.getY();
tvStatus.setText( strMsg );
}
break;
case MotionEvent.ACTION_UP:
{
String strMsg;
strMsg = "ACTION_UP X: " + event.getX() + " Y:" + event.getY();
tvStatus.setText( strMsg );
}
break;
}
}
return true;
}
}
onTouchEvent 함수를 오버라이드 하여 구현하는 방법
import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.OnTouchListener;
import android.widget.LinearLayout;
import android.widget.TextView;
public class TouchTest extends Activity
{
/** Called when the activity is first created. */
TextView tvStatus;
Canvas2D canvas;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
//setContentView(R.layout.main);
LinearLayout layout = new LinearLayout(this);
layout.setOrientation( LinearLayout.VERTICAL );
LinearLayout.LayoutParams param = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.FILL_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT );
layout.setLayoutParams( param );
tvStatus = new TextView(this);
layout.addView( tvStatus );
tvStatus.setText( "Touch Status" );
canvas = new Canvas2D( this );
ViewGroup.LayoutParams canvasParam = new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.FILL_PARENT,
ViewGroup.LayoutParams.FILL_PARENT );
layout.addView( canvas, canvasParam );
canvas.setOnTouchListener( this );
setContentView( layout );
}
class Canvas2D extends View
{
public Canvas2D(Context context)
{
super(context);
}
@Override
public void onDraw( Canvas canvas )
{
// Canvas 배경 설정
canvas.drawColor( Color.parseColor("#888888") );
}
@Override
public boolean onTouchEvent(MotionEvent event)
{
Log.i( "event", "Canvas2D onTouch" );
switch (event.getAction())
{
case MotionEvent.ACTION_DOWN:
{
String strMsg;
strMsg = "ACTION_DOWN X: " + event.getX() + " Y:" + event.getY();
tvStatus.setText( strMsg );
}
break;
case MotionEvent.ACTION_MOVE:
{
String strMsg;
strMsg = "ACTION_MOVE X: " + event.getX() + " Y:" + event.getY();
tvStatus.setText( strMsg );
}
break;
case MotionEvent.ACTION_UP:
{
String strMsg;
strMsg = "ACTION_UP X: " + event.getX() + " Y:" + event.getY();
tvStatus.setText( strMsg );
}
break;
}
return true;
}
}
}
<
Original Post : http://neodreamer-dev.tistory.com/450
2010/06/22
[Android Dev.] Activity 추가 및 전환 하기
Activity 추가하기
Activity 를 추가하려면 프로젝트에 Class 를 추가한다.
클래스 추가 대화상자
<?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="Hello SubActivity"
/>
<Button
android:id="@+id/BtnReturnMain"
android:text="Return to Main Activity"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
</LinearLayout>
Activity 전환하기
추가 된 Activity 를 사용하기 위해 AndroidManifest.xml 에 추가를 한다. AndroidManifest.xml 에 Activity 를 추가 하는 것은 수동으로 하는 방법과 자동으로 하는 방법이 있다.
자동으로 하는 방법은 AndroidManifest.xml 파일을 열어 Application 탭에서 Application Nodes 에 Activity 를 추가한다.
추가하고 추가 된 Activity 를 선택하고 오른쪽의 Attributes for Activity 에 Name 를 생성한 Activity 를 할당하여 준다.
이렇게 지정을 하면 AndroidManifest.xml 파일은 아래와 같이 수정이 된다.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.neodreamer.SwitchActivity"
android:versionCode="1"
android:versionName="1.0">
<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".MainActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="SubActivity">
</activity>
</application>
<uses-sdk android:minSdkVersion="8" />
</manifest>
Main Activity 의 Layout 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"
>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello"
/>
<Button
android:id="@+id/BtnCallSub"
android:text="Call Sub Activity"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
</LinearLayout>
Main 에서 SubActivity 호출 코드
@Override
public void onClick(View v)
{
if ( v == btnCallSub )
{
Log.i( "onClick", "Call Sub Activity" );
Intent intentSubActivity = new Intent( this, SubActivity.class );
startActivity( intentSubActivity );
}
}
Sub 에서 MainActivity 로 돌아가는 코드
@Override
public void onClick(View v)
{
if ( v == btnReturnMain )
{
finish();
}
}
2010/05/21
Android 2.2 Froyo SDK 설치하기
업그레이드 도중 tools 설치가 실패하는 경우가 있는데 이는 eclipse 를 실행한 상태에서 업데이트를 실행하여서 그런다. 시스템 부팅후 java및 android 개발 관련 툴을 실행하지 않고 업데이트를 수행하면 잘 된다.
SDK 업데이트를 마치고 eclipse 를 실행하여 업데이트 항목이 있나 확인해 보니 개발 툴 관련 업데이트가 있어 이 또한 설치를 해 주었다.
이제 Froyo 개발 준비가 된 것이다.<
Original Post : http://neodreamer-dev.tistory.com/444
Android NDK, Revision 4 공개
Android NDK, Revision 4 (May 2010)
- Provides a simplified build system through the new ndk-build build command.
- Adds support for easy native debugging of generated machine code on production devices through the new ndk-gdb command.
- Adds a new Android-specific ABI for ARM-based CPU architectures, armeabi-v7a. The new ABI extends the existing armeabi ABI to include these CPU instruction set extensions:
- Thumb-2 instructions
- VFP hardware FPU instructions (VFPv3-D16)
- Optional support for ARM Advanced SIMD (NEON) GCC intrinsics and VFPv3-D32. Supported by devices such as Verizon Droid by Motorola, Google Nexus One, and others.
- Adds a new cpufeatures static library (with sources) that lets your app detect the host device's CPU features at runtime. Specifically, applications can check for ARMv7-A support, as well as VFPv3-D32 and NEON support, then provide separate code paths as needed.
- Adds a sample application, hello-neon, that illustrates how to use the cpufeatures library to check CPU features and then provide an optimized code path using NEON instrinsics, if supported by the CPU.
- Lets you generate machine code for either or both of the instruction sets supported by the NDK. For example, you can build for both ARMv5 and ARMv7-A architectures at the same time and have everything stored to your application's final .apk.
- To ensure that your applications are available to users only if their devices are capable of running them, Android Market now filters applications based on the instruction set information included in your application — no action is needed on your part to enable the filtering. Additionally, the Android system itself also checks your application at install time and allows the installation to continue only if the application provides a library that is compiled for the device's CPU architecture.
- Adds support for Android 2.2, including a new stable API for accessing the pixel buffers of Bitmap objects from native code.
<
Original Post : http://neodreamer-dev.tistory.com/443
Android 2.2 Froyo SDK 공개!!
드디어 Android Froyo 가 공개가 되었다. Froyo 공개 후 SDK 도 공개가 되었다.
Froyo(2.2) 가 기존 2.1 버전에 비해 성능이 20~30배 정도 좋아졌다는데 성능 이외에도 많은 것이 기대 되는 버전이다.
Android 2.2 Platform
Android 2.2 Platform Highlights<
Original Post : http://neodreamer-dev.tistory.com/442
2010/05/13
[Android Dev.] Tab 선택 이벤트 잡기
package com.neodreamer.MyTab;
import android.app.TabActivity;
import android.os.Bundle;
import android.widget.TabHost;
import android.widget.Toast;
import android.widget.TabHost.OnTabChangeListener;
public class MyTab extends TabActivity implements OnTabChangeListener
{
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
TabHost tabHost = getTabHost();
TabHost.TabSpec spec;
// 첫 번째 탭
spec = tabHost.newTabSpec( "Tab 01" );
spec.setIndicator( "Tab 01",
getResources().getDrawable( R.drawable.icon ) );
spec.setContent( R.id.TabView1 );
tabHost.addTab( spec );
// 두 번째 탭
spec = tabHost.newTabSpec( "Tab 02" );
spec.setIndicator( "Tab 02" );
spec.setContent( R.id.TabView2 );
tabHost.addTab( spec );
// 세 번째 탭
spec = tabHost.newTabSpec( "Tab 03" );
spec.setIndicator( "Tab 03" );
spec.setContent( R.id.TabView3 );
tabHost.addTab( spec );
tabHost.setCurrentTab( 0 );
// Tab Change 이벤트 리스너 등록
tabHost.setOnTabChangedListener( this );
}
@Override
public void onTabChanged(String tabId)
{
String strMsg;
strMsg = "onTabChanged : " + tabId;
Toast.makeText( this, strMsg, Toast.LENGTH_SHORT ).show();
}
}
<
Original Post : http://neodreamer-dev.tistory.com/438
2010/05/12
[Android Dev.] SQLite Database 사용하기
Activity 의 Layout 은 버튼하나와 수행 결과를 보여 줄 TextView 만 배치하였다.
<?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="@string/hello"
/>
<Button
android:id="@+id/BtnTestSQLite"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:text="Test SQLite"
/>
<TextView
android:id="@+id/TxtResult"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/>
</LinearLayout>
버튼이 눌려지만 Database 를 테스트하는 명령이 수행되고 그 결과를 TextView에 출력 하였다.
@Override
public void onClick(View v)
{
// 데이터베이스 열기 (생성)
m_db = openOrCreateDatabase( "test.db", Context.MODE_PRIVATE, null );
if ( !m_db.isOpen() )
{
Log.e( "SQLite", "openOrCreateDatabase ... Fail" );
return;
}
Log.i( "SQLite", "openOrCreateDatabase ... OK" );
String strSQL;
try
{
// member 테이블이 존재하면 삭제
strSQL = "DROP TABLE IF EXISTS member;";
m_db.execSQL( strSQL );
// member 테이블이 존재하지 않으면 생성
strSQL =
"CREATE TABLE IF NOT EXISTS member " +
"(" +
" c_name TEXT" +
" , c_alias TEXT" +
" , c_age INTEGER" +
");";
m_db.execSQL( strSQL );
Log.i( "SQLite", "Create Table ... OK" );
// Insert 구문을 이용한 Row 삽입
for ( int i = 0; i < 3; ++i )
{
strSQL =
"INSERT INTO member ( c_name, c_alias, c_age )" +
" VALUES ( 'code_" + Integer.toString( i ) + "'," +
" 'test', " + Integer.toString( i + 2 ) +
" );";
m_db.execSQL( strSQL );
Log.i( "SQLite", "Insert data " + i + " ... OK" );
}
// ContentValues 를 이용한 데이터 삽입
ContentValues cvInsert = new ContentValues();
cvInsert.put( "c_name", "neo" );
cvInsert.put( "c_alias", "dreamer" );
cvInsert.put( "c_age", "20" );
m_db.insert( "member", null, cvInsert );
cvInsert.put( "c_name", "neo2" );
cvInsert.put( "c_alias", "dreamer2" );
cvInsert.put( "c_age", "40" );
m_db.insert( "member", null, cvInsert );
// rawQuery 함수를 이용한 데이터 질의
m_cursor = m_db.rawQuery( "SELECT * FROM member", null );
if ( m_cursor != null )
{
if ( m_cursor.moveToFirst() )
{
String strRow = "--------------------------------\n";
for(int i = 0 ; i < m_cursor.getColumnCount() ; i++ )
{
strRow += m_cursor.getColumnName(i) + " | ";
}
strRow += "\n";
txtResult.setText( strRow );
do
{
strRow = "";
for(int i = 0 ; i < m_cursor.getColumnCount() ; i++ )
{
strRow += m_cursor.getString(i) + " | ";
}
strRow += "\n";
txtResult.setText( txtResult.getText() + strRow );
} while ( m_cursor.moveToNext() );
}
}
m_cursor.close(); // 커서 닫기
// rawQuery 함수에 parameter 를 이용한 데이터 질의
String strParam[] = { "neo" };
m_cursor = m_db.rawQuery( "SELECT * FROM member WHERE c_name = ?", strParam );
if ( m_cursor != null )
{
if ( m_cursor.moveToFirst() )
{
String strRow = "--------------------------------\n";
for(int i = 0 ; i < m_cursor.getColumnCount() ; i++ )
{
strRow += m_cursor.getColumnName(i) + " | ";
}
strRow += "\n";
txtResult.setText( txtResult.getText() + strRow );
do
{
strRow = "";
for(int i = 0 ; i < m_cursor.getColumnCount() ; i++ )
{
strRow += m_cursor.getString(i) + " | ";
}
strRow += "\n";
txtResult.setText( txtResult.getText() + strRow );
} while ( m_cursor.moveToNext() );
}
}
m_cursor.close(); // 커서 닫기
// query 함수를 이용할 데이터 질의
String strColumn[] = { "c_name", "c_age" };
String strSelection = "c_name like 'neo%'";
m_cursor = m_db.query( "member", strColumn, strSelection,
null, null, null, null );
if ( m_cursor != null )
{
if ( m_cursor.moveToFirst() )
{
String strRow = "--------------------------------\n";
for(int i = 0 ; i < m_cursor.getColumnCount() ; i++ )
{
strRow += m_cursor.getColumnName(i) + " | ";
}
strRow += "\n";
txtResult.setText( txtResult.getText() + strRow );
do
{
strRow = "";
for(int i = 0 ; i < m_cursor.getColumnCount() ; i++ )
{
strRow += m_cursor.getString(i) + " | ";
}
strRow += "\n";
txtResult.setText( txtResult.getText() + strRow );
} while ( m_cursor.moveToNext() );
}
}
m_cursor.close(); // 커서 닫기
}
catch ( SQLException e )
{
// SQL 예외 처리
Log.e( "SQLException", e.getMessage() );
}
finally
{
// Database 닫기
m_db.close();
Log.i( "SQLite", "Database Close ... OK" );
}
}
Log를 통해 진행 상황을 모니터링 한 내용이다.
05-12 23:26:20.110: INFO/SQLite(213): openOrCreateDatabase ... OK
05-12 23:26:20.190: INFO/SQLite(213): Create Table ... OK
05-12 23:26:20.200: INFO/SQLite(213): Insert data 0 ... OK
05-12 23:26:20.210: INFO/SQLite(213): Insert data 1 ... OK
05-12 23:26:20.240: INFO/SQLite(213): Insert data 2 ... OK
05-12 23:26:20.400: INFO/SQLite(213): Database Close ... OK
<
Original Post : http://neodreamer-dev.tistory.com/437
2010/05/11
[Android Dev.] 편리한 Eclipse 의 Intellisense(?)
일단 Eclpise 에서 구문 오류가 발생하면 오류 발생 위치에 빨간 물결 무늬의 밑줄을 출력해 주는데 이 오류 부분에 마우스 커서를 올려 놓으면 이 문제를 해결 하기 위한 팝업 윈도우를 보여준다.
아래는 Activity 의 속한 버튼에 대하여 setOnClickListener 함수를 호출하였을때 발생하는 오류에 대한 팝업 윈도우 이다.
팝업 윈도우에서 맨 마지막에 있는 Let '...' implements 'OnClickListener' 메뉴를 선택하게 되면 해당 class 선언문에 implements OnClickListener 구문이 추가 된다. class 에 implements 구문이 추가되면 abstract method(onClick) 개 구현되지 않았아서 클래스 이름에 에러 표시가 되는데 클래스 이름에 마우서 커서를 올려 놓으면 팝업 윈도우가 활성화 되고 method 를 추가 할 수 있는 메뉴가 나온다.
이 윈도우에서 "Add unimplemented methods" 메뉴를 선택하면 아래와 같은 코드가 class 에 추가 된다.
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
}
<Original Post : http://neodreamer-dev.tistory.com/436
[Android Dev.] Import 를 편하게 해주는 Eclipse 기능
Import 되지 않은 위젯을 사용하게 되면 아래 이미지에서 처럼 ...cannot be resolved to a type 이라는 에러가 발생한다.
이 때, Import 되지 않아 에러가 발생한 위젯에 마우스 커서를 올려 놓으면 잠시후에 아래 이미지와 같은 팝업 윈도우가 나타난다.
이 팝업 윈도우에서 맨 위에 있는 Import... 메뉴를 선택하면 해당 위젯이 Import 가 되고 에러가 사라진다.<
Original Post : http://neodreamer-dev.tistory.com/435
2010/05/06
[Android Dev.] Canvas.drawPosText 의 불편한 진실
2010/05/06 - [Dev Story/Android] - [Android Dev.] 2D Drawing
다른 텍스트 출력은 문제가 없는데 drawPosText 함수만 호출하면 문제가 발생하여 그에 대한 원인을 찾느라 시간을 좀 허비했다. API 문서를 좀더 자세히 읽어 봤더라면 시간을 절약할 수 있었을 것이다.
이 함수는 아래와 같은 형태를 갖고 있다.
public void drawPosText(String text, float[] pos, Paint paint)
Parameters
text The text to be drawn
pos Array of [x,y] positions, used to position each character
paint The paint used for the text (e.g. color, size, style)
함수만 보고 이 함수의 기능이 주어진 문자를 주어진 좌표 배열에 출력을 해주는 것이라고 생각하고 아래와 같은 코드로 테스트를 해 보았다.
myPaint.setARGB( 0, 255, 0, 255 );
float[] pos = new float[] {
60, 50,
60, 420
};
canvas.drawPosText( "Android drawPosText", pos, myPaint );
이 코드가 60,50 과 60,420 좌표에 "Android drawPosText"를 그려 줄 것이라고 예상을 했지만 예상을 깨고 에러 화면만을 보여 주었다.
잘못 된 drawPosText 함수 사용에 따른 에러화면
어렵게 예제 자료를 찾아서 확인해 보았더니 drawPosText 함수의 기능을 주어진 문자열의 각 문자를 좌표 배열의 각각의 위치에 출력하는 기능이였다. API 문서에도 아래와 같이 설명이 되어 있었다.
Draw the text in the array, with each character's origin specified by the pos array.
그래서 아래와 같은 코드로 테스트를 해 보았더니 에러 없이 문자를 출력해 주었다. (보라색 비뚤비뚤 Android 글자)
myPaint.setARGB( 128, 255, 0, 255 );
float[] pos = new float[] {
160, 20,
170, 25,
180, 20,
190, 25,
200, 20,
210, 25,
220, 20
};
canvas.drawPosText( "Android", pos, myPaint );
Canvas의 drawPosText 를 이용한 문자 출력
아래 코드를 수행하여 보면 보다 명확하게 알 수 있다.
Paint paint = new Paint();
paint.setColor( Color.GREEN );
float[] pos = new float[] { 60, 50, 60, 420 };
String strMsg = "AB";
canvas.drawPosText( strMsg.toCharArray(), 0, strMsg.length(), pos, paint );
Canvas의 drawPosText 를 이용한 문자 출력
<
Original Post : http://neodreamer-dev.tistory.com/432
[Android Dev.] 2D Drawing
위의 이미지를 출력하기위한 코드이다.
public class My2D extends Activity
{
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE); // 타이틀바 제거
setContentView( new My2DView( this ) );
//setContentView(R.layout.main);
}
class My2DView extends View
{
public My2DView(Context context)
{
super(context);
}
@Override
public void onDraw(Canvas canvas)
{
// Canvas 배경 설정
canvas.drawColor(Color.parseColor("#030303"));
// Bitmap 을 Canvas 에 뿌리기
Bitmap bm = BitmapFactory.decodeResource(
getResources(), R.drawable.icon);
canvas.drawBitmap(bm, 100, 100, null);
// 드로잉을 위핸 Paint 객체 생성
Paint myPaint = new Paint();
myPaint.setAntiAlias( true ); // AntiAliasing 설정
// 선 그리기
myPaint.setColor( Color.parseColor("#FF0000") ); // 선 색상 설정
canvas.drawLine( 10, 10, 100, 100, myPaint );
// 도형 그리기
myPaint.setARGB( 128, 0, 255, 255 ); // 색상 설정
canvas.drawCircle( 200, 300, 100, myPaint ); // 원 그리기
myPaint.setARGB( 128, 255, 0, 255 ); // 색상 설정
canvas.drawCircle( 100, 250, 100, myPaint ); // 원 그리기
myPaint.setARGB( 128, 255, 0, 0 ); // 색상 설정
// 10x10 크기의 모서리가 둥근 사각형 그리기
canvas.drawRoundRect(
new RectF(150.0f, 60.0f, 300.0f, 160.0f),
10.0f, 10.0f, myPaint );
Path myPath = new Path(); // 패스 생성
// 패스에 시계방향 원형 추가
myPath.addCircle( 200, 300, 100, Direction.CW );
myPaint.setARGB( 128, 0, 255, 255 ); // 색상 설정
myPaint.setTextSize( 15 ); // 폰트 크기 설정
// 패스를 따라 5pixel 떨어진 글자 출력
canvas.drawTextOnPath(
"Hello Android 2D",
myPath, 0.0f, -5.0f, myPaint );
// 문자 출력
myPaint.setColor( Color.CYAN ); // 색상 설정
canvas.drawText( "Android drawText", 20, 20, myPaint );
myPaint.setARGB( 0, 255, 0, 255 );
float[] pos = new float[] { 60, 50, 60, 420 };
//canvas.drawPosText( "Android drawPosText", pos, myPaint );
}
}
}
다른 것은 어렵지 않게 되는데 맨 마지막 시도한 drawPosText 는 잘 되지 않는데 이 함수만 실행하면 프로그램이 다운되어 버린다. 관련 자료를 찾고 있는데 쉽지가 않다.<
Original Post : http://neodreamer-dev.tistory.com/431
2010/05/02
[Android Dev.] Thread 사용하기
Android 의 Thread 는 Thread 껍데기를 담당하는 Thread 객체와 실제 실행되는 부분을 담당하는 Runnable 객체로 구성이 되는데 Android 에서는 Multi Thread 를 지원을 하지만 여러 Thread 에서 메인 UI를 제어하지 않고 하나의 Thread 혹은 Handler 라는 객체에서 담당을 하도록 한다.
Thead의 생성의 Thread 객체를 생성할 때, Runnable 객체를 넘겨주어 생성을 한다.
public Thread (Runnable runnable)
Thread 의 테스트를 위해 아래와 같은 메인 UI를 작성하였다.
<?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="@string/hello"
/>
<ProgressBar
android:id="@+id/ProgressBar01"
style="?android:attr/progressBarStyleHorizontal"
android:layout_height="wrap_content"
android:layout_width="fill_parent"/>
<Button
android:text="@+id/Button01"
android:id="@+id/Button01"
android:layout_height="wrap_content"
android:layout_width="fill_parent"/>
</LinearLayout>
Progress bar 와 쓰레드 동작시킬 버튼이다.
아래 소스는 아주 간단하게 버튼이 눌렸을 때 Thread를 생성하여 Progress bar를 진행시키는 코드 이다.
ProgressBar progress01;
Button btn01;
progress01 = (ProgressBar)findViewById( R.id.ProgressBar01 );
btn01 = (Button)findViewById( R.id.Button01 );
btn01.setOnClickListener( this );
public void onClick( View v )
{
if ( v == btn01 )
{
new Thread(new Runnable()
{
public void run()
{
progress01.setProgress( 0 );
progress01.setMax( 100 );
for ( int i = 0; i <= 100; ++i )
{
progress01.setProgress( i );
SystemClock.sleep(100);
}
//Toast.makeText(MyThread.this, "Thread Finished", Toast.LENGTH_SHORT).show();
}
}
).start();
}
}
위의 소스 중에 Toast 메세지를 출력하는 부분이 있는데 이 부분의 주석을 해제하고 실행하면 아래와 같은 예외가 발생을 하는데 왜 그런지는 모르겠고 Backgroud Thread 에서 메인 UI를 제어하려고 시도해서 인 것을 생각이 된다.
Handler 를 이용한 Message Queueing 방식
다음은 Handler 를 이용한 message queueing 방식을 이용하는 Thread 를 생성하여 보았다. Thread 에서 Handler 에게 message 를 보내어 Handler 가 받은 message 를 처리하며 UI 작업을 하도록 하는 것이다.
Handler myHandler = new Handler()
{
public void handleMessage( Message msg )
{
if ( msg.what == -1 )
{
progress01.setProgress( 0 );
progress01.setMax( 100 );
}
else if ( msg.what == -100 )
{
Log.i( "INFO", "Finish Thread!!!" );
Toast.makeText(MyThread.this, "Finish Thread!!!", Toast.LENGTH_SHORT).show();
}
else
{
progress01.setProgress( msg.what );
}
}
};
public void onClick( View v )
{
if ( v == btn01 )
{
new Thread(new Runnable()
{
public void run()
{
Message msg = myHandler.obtainMessage();
msg.what = -1;
myHandler.sendMessage( msg );
for ( int i = 0; i <= 100; ++i )
{
msg = myHandler.obtainMessage();
msg.what = i;
myHandler.sendMessage( msg );
SystemClock.sleep(100);
}
msg = myHandler.obtainMessage();
msg.what = -100;
myHandler.sendMessage( msg );
}
}
).start();
}
}
Handler 에게로 Message를 보내기 위해서는 Handler 에서 obtainMessage 함수를 이용해 Message 객체를 받아와서 필요한 정보를 담아 다시 Handler 에게 보내는 것이다. Handler 는 받은 메세지를 순서대로 handleMessage 함수를 통해 처리한다.
이 때, Handler 에게 Message 를 보내는 방법이 여러가지가 있다.
- final boolean sendMessage(Message msg)
Message 를 Handler 의 Message Queue 에 맨 마지막에 추가한다. - final boolean sendMessageAtFrontOfQueue(Message msg)
Message 를 Handler 의 Message Queue 의 맨 앞에 추가한다. - boolean sendMessageAtTime(Message msg, long uptimeMillis)
Message 를 특정 시각(장비 가동후 지난 시간)이 되면 Queue에 추가한다. - final boolean sendMessageDelayed(Message msg, long delayMillis)
Message 를 특정 시간이 지난 후에 Queue에 추가한다.
Foreground Thread에 post 메세지에 의한 방법
또 다른 방법은 UI 핸들링을 하는 Foreground Thread 를 두고 Background Thread 에서 post 함수를 이용하여 처리하는 방식이다.
Handler myHandler = new Handler();
private Runnable fgTask = new Runnable()
{
@Override
public void run()
{
int nCur = progress01.getProgress();
if ( nCur != progress01.getMax() )
{
nCur++;
progress01.setProgress( nCur );
}
else
{
Toast.makeText( MyThread.this, "Finish Thread", Toast.LENGTH_SHORT).show();
}
}
};
public void onClick( View v )
{
if ( v == btn01 )
{
new Thread(new Runnable()
{
public void run()
{
for ( int i = 0; i <= 100; ++i )
{
myHandler.post( fgTask );
SystemClock.sleep(100);
}
}
}
).start();
}
}
위의 두가지 Thread 운영 방식은 유사하게 동작을 하며 버튼이 눌려지면 Thread 를 동작하여 Progress 바의 진행을 시킨다.
2010/04/29
[Android Dev.] ProgressDialog 사용하기
Android 에서 기본적으로 제공하는 ProgressDialog 를 생성하는 것은 간단하다. 아래의 코드만으로 ProgressDialog 가 생성이 된다.
progDialog1 = new ProgressDialog( this );
progDialog1.setProgressStyle( ProgressDialog.STYLE_HORIZONTAL );
progDialog1.setMessage( "Test" );
progDialog1.setCancelable( true );
하지만 이 ProgressDialog 의 진행상황을 반영하기 위해서는 Thread 를 구현해야 한다. 아직은 java의 Thread를 이해하지 못해서 i티거 님의 블로그에 있는 Android Thread 강좌에서 발췌하여 실행시켜 보았다.
static final int MY_PROGRESS1 = 7;
ProgressDialog progDialog1;
:
:
case R.id.BtnProgress1:
{
showDialog( MY_PROGRESS1 );
new Thread(new Runnable()
{
int nProgress;
@Override
public void run()
{
for(nProgress = 0; nProgress <= 100; ++nProgress )
{
runOnUiThread( new Runnable()
{
public void run()
{
progDialog1.setProgress(nProgress);
}
});
SystemClock.sleep(100);
}
dismissDialog( MY_PROGRESS1 );
}
}).start();
}
break;
Thread 에 대해서는 좀 더 공부를 해 봐야 겠다.<
Original Post : http://neodreamer-dev.tistory.com/428