안드로이드에서 단위테스트를 위한 Junit 사용하기 (2)

 

일반 Junit test case 가 아닌 안드로이드에서 제공하는 ActivityUnitTestCase 클래스로

Activity 단위별 테스트를 실행해보자.

먼저 테스트를 위해서 서브 패키지를 하나 만든다이것은 실제 개발소스와 테스트소스를

구분하기 위함이다프로젝트를 선택하고 test/src 라는 폴더를 하나 만든다그리고

Build Path 로 들어가서 source 탭을 클릭한다화면에서 Add Folder 를 클릭해 방금

추가한 경로를 입력한다.

이 패키지에 테스트할 ActivityUnitTestCase 클래스를 만든다
01 import android.content.Intent;
02 import android.test.ActivityUnitTestCase;
03 import android.test.suitebuilder.annotation.MediumTest;
04 import android.util.Log;
05 import android.widget.Button;
06  
07 public class MainTest extends ActivityUnitTestCase<main> {
08      
09     private Intent mStartIntent;
10     private Button mStartButton;
11      
12     public MainTest() {
13         super(Main.class);
14          
15     }
16     protected void setUp() throws Exception {
17         super.setUp();
18         mStartIntent = new Intent(Intent.ACTION_MAIN);
19     }
20      
21     @MediumTest
22     public void testInit(){
23         //startActivity(mStartIntent, null, null);
24         Log.d("MainTest""ActivityUnitTestCase test");
25     }
26 }
27 </main>

 

기본골격은 위와 같이 만들며 테스트하고자 하는 함수를 만들때는 함수명 앞에 test~ 라고

붙여주면 된다그리고 클래스를 만들 때 상속 클래스를 ActivityUnitTestCase<T> 

설정하면 된다. T 부분은 실행할 Activity 클래스를 가리킨다

만든 클래스를 돌려보기 위해 파일을 선택하고 오른쪽 마우스를 클릭한뒤 그림과 같이

Android Junit Test 를 선택한다그러면 testInit() 함수를 실행하고 뒤이어 Main Activity 

실행한다그리고 결과가 아래와 같이 Junit 익스플로어에 나타날것이다

안드로이드에서 단위테스트를 위한 Junit 사용하기 (1)

 

[[ 개발환경 ]]

window XP

Android SDK 2.1

JDK 1.5

eclipse galieo

 

이전프로젝트에서는 폭포수 방법론으로 프로세스를 많이 적용해왔다초기에 요구사항

전체를 확실히  정의한후 설계와 구현을 단계별로 진행하게 된다이 방법론은 점점

사라지는 추세이다왜냐하면  이후에 변경되어지는 추가요구사항과 설계를 변경하기가

쉽지 않기 때문이다현재 비지니스 환경은 이렇게 경직되어있지 않고 유동적이므로

언제 요구사항이 변경될지 모른다.

이런 환경에서 최근 주목을 끌고 있는 것이 애자일 방법론이다애자일은 민첩하고

기민하다는 뜻이다  애자일 방법론에 대한 기술을 논의하자면 의도에 벗어난 강좌가

될것 같아 여기서 줄이기로 하고중요한것은 애자일 방법론에서 주로 사용하는 것이

단위테스트 이다이 단위테스트를 위해 java 개발환경에서 주로 사용하는 프레임웍이

junit 이다.

Junit framework  eclipse 플러그인으로 만들어 쉽게 사용할수 있도록 제공해 준다.

Java  Web Application 에서는 많이 사용해봐서 익숙하지만 Android 에서는 처음이라

이렇게 아티클을 작성하게 되었다.

 

안드로이드 SDK 를 보게 되면 내부에 Junit 클래스가 존재한다그러므로 이전에 작업했던

환경설정과 실행법이 같다별 어려움 없이 진행이 가능하며단지 특이한 점은

안드로이드 에서 제공하는 TestCase 들이 여럿있다는 것이다.  DB 테스트를 위해

DBUnit 라는 것이 있듯이 안드로이드에서도 Activity 단위별로 테스트 할수 있는

ActivityUnitTestCase, Service 를 테스트 해볼수 있는 ServiceTestCase 등이 있다.

전부 조사해보지 않아 상세하게 기술 해볼수는 없지만 우선 2편에서 ActivityUnitTestCase

사용법에 대해 대략적인 사용법을 설명하였다.

 

1. Android Junit project 생성

 

안드로이드에서 단위테스트를 시행하기 위한 Junit 설정은 프로젝트 생성부터 다르다.

기존에 있는 프로젝트를 대상으로 Junit 을 실행하는 방법과 프로젝트 자체가 Junit 

시행할수 있는 프로젝트로 나누어 생성할수 있다.

Android Test Project 를 선택하면 아래의 설정화면이 나오는데 Test Target 를 설정하는

곳이 있다현재 만들 프로젝트를 Junit 으로 사용할것인지아니면 이미 만들어진

프로젝트를 상대로 구동할것인지에 대한 내용을 선택한다그리고 Build Target 

선택할때에는 Target 이 되는 SDK와 맞아야 한다

간단한 테스트 프로젝트를 위해 This project 를 선택하고값들을 채운후 Finish 로 셋팅을

마무리 하자그런데 버그인지 모르겠지만 An existing Android project 란에 프로젝트를

선택하지 않으면 Finish 버튼이 활성화 되지 않는다프로젝트를 생성할수 없게 되는것이다.

원인은 모르겠지만 This project 선택하고 프로젝트를 생성해야 되므로 아무 프로젝트나

Browser 를 클릭해 선택하자.

프로젝트가 생성되었으면 Android Junit Test 를 위해 추가된 설정값이 두가지가 있다.

AndroidManifest.xml 을 열어보자. instrumentation 에 android.test.InstrumentationTestRunner

추가 된 것을 볼수 있다.

두번째는 Application 탭에  Uses Library  android.test.runner 를 사용하고 있는 것을

볼수 있다이와 같이 두가지는 Junit을 돌리기 위한 필수 요소 이다이것은 일반

프로젝트에서 볼수 없는 것으로 기존 프로젝트에서 사용하고 싶다면 설정을 해줘야한다

이제 이 프로젝트가 Debug/Run Configurations 에 제대로 설정되어있는지 보아야한다.

Debug/Run Configurations 을 열어보면 Android JUnit Test 란에 프로젝트가 추가된 것을

볼수 있다그리고 오른쪽에 옵션중 Run a single test는 하나의 테스트 클래스를 실행

할수 있는 명령을 내리는 것이고 아래에 Run all tests  package 에 포함된 테스트

클래스 모두를 실행할수 있도록 하는 것이다.

 

2. Test case 프로그램 제작실행

 

이제 환경설정이 끝났으니 Test 클래스를 만들어 실행해본다.

간단하게 Activity 를 실행할수 있는 ActivityUnitTestCase 클래스를 상속받아 만든다.

ActivityUnitTestCase 를 상속받아 만드는 Test Case 클래스는 Activity 클래스를 실행해서

단위테스트하기 위한 의도로 만들어진것이다그러므로  Test  Activity 를 인자로

포함한다public class MainTest extends ActivityUnitTestCase<Main>  와 같이

테스트 할 Main Activity class 가 포함되어있다그리고 생성자에서는 Main.class 

상위클래스로 넘겨줘야한다.

public MainTest() {

           super(Main.class);

}

 

Main.java  MainTest.java 의 전체 내용은 다음과 같다.

 

Main.java

 

import android.app.Activity;

import android.os.Bundle;

import android.util.Log;

 

public class Main extends Activity {

    /** Called when the activity is first created. */

    @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);

       

        Log.d("Main""========================");

    }

}

 

MainTest.java

 

import android.content.Intent;

import android.test.ActivityUnitTestCase;

import android.test.suitebuilder.annotation.MediumTest;

import android.util.Log;

import android.widget.Button;

 

public class MainTest extends ActivityUnitTestCase<Main> {

      

       private Intent mStartIntent;

       private Button mStartButton;

      

       public MainTest() {

             super(Main.class);

            

       }

       protected void setUp() throws Exception {

             super.setUp();

             mStartIntent = new Intent(Intent.ACTION_MAIN);

       }

      

       @MediumTest

       public void testInit(){

             Log.d("MainTest""ActivityUnitTestCase test");

       }

}

 

소스에서 보면 testInit 가 실행되고 다음 Main Activity 클래스를 실행하게 된다.

아래 그림 왼쪽 Junit explore 화면을 보면 테스트가 정상으로 이루어진 것을

볼수 있다이런식으로 테스트할 Activity 클래스들을 모아 단위 테스트 클래스를

만들어서 사용하면 될것이다.

 

다음회는 좀더 상세한 테스트 내용을 기술 하도록 하겠습니다.

웹표준+방탄웹(2권)
카테고리 컴퓨터/IT > 프로그래밍/언어 > 웹프로그래밍 > 웹프로그래밍일반
지은이 댄 씨더홈 (에이콘출판, 2006년)
상세보기

성공적인 웹 사이트를 제작하기 위한 <웹 표준>과 <방탄웹>을 한 권으로 묶어 나왔다. 

『웹 2.0을 이끄는 방탄웹』은 표준화를 어떻게 시작하고 무엇을 표준화 시켜야 하는지 알려주는 가이드 북으로 기존의 웹 사이트들을 사례로 들어 문제점을 지적하여 분석하고 있다

[인터넷 교보문고 제공]

댄 씨더홈

댄 씨더홈 
여러 차례 수상 경력이 있는 웹 디자이너이자 컨설턴트이며 웹 표준 기반의 웹 사이트 디자인 및 구축 분야 전문 저술가이다. 2003년도에 패스트 컴퍼니(Fast Company)와 인크닷컴(Inc.)의 웹 사이트를 CSS 장점을 최대한 살린 웹 표준 기반으로 리뉴얼 하면서 알려지기 시작했다. 

또 웹 관련 기술과 일상적인 이야기들을 전해 매우 유명해진 블로그 심플비츠(SimpleBits)를 운영하고 있다. 블로그와 같은 이름의 컨설팅 회사도 운영하고 있는데, 이 회사에서는 이 책에서 설명한 방법들을 적용해 단순하고도 매력적인 인터페이스 제작분야에 초점을 맞추고 있다. 

드류 맥르란 / 기술 감수 
영국 런던에 거주하는 웹 애플리케이션 개발자로 주간에는 웹 개발 업무를 하고 있으며, 밤에는 기술 서적을 쓰거나 편집하는 일을 한다. 웹 표준 프로젝트(www.webstandards.org)의 멤버이기도 한 그는 PR 등의 다양한 역할을 하고 있다.

[반디앤루니스 제공]

방탄웹
- 이 책에 쏟아진 블로그 글과 서평
- 추천의 글
- 감사의 글
- 지은이 소개
- 옮긴이의 글
- 옮긴이 소개
- 들어가며

1장 글씨 크기를 내 맘대로
흔해 빠진 구축방식
방탄웹이 아닌 이유
최적의 방법 선택하기
방탄웹으로 만들려면?
방탄웹이 좋은 이유
다음단계
키워드 값과 퍼센트 값 사용
요약

2장 자유롭게 크기가 조절되는 내비게이션 메뉴바
흔해 빠진 구축 방식
방탄웹이 아닌 이유
방탄웹으로 만들려면?
방탄웹이 좋은 이유
그 밖의 사례 소개
요약

3장 자유자재로 높낮이가 조절되는 행 만들기
흔해 빠진 구축 방식
방탄웹이 아닌 이유
방탄웹으로 만들려면?
방탄웹이 좋은 이유
세로 확장 사례 하나 더
요약

4장 나만의 Float 활용 비법
흔해 빠진 구축 방식
방탄웹이 아닌 이유
방탄웹으로 만들려면?
방탄웹이 좋은 이유
요약

5장 깨지지 않는 상자 만들기
흔해 빠진 구축 방식
방탄웹이 아닌 이유
방탄웹으로 만들려면?
방탄웹이 좋은 이유
그 밖의 둥근 모서리 기법 소개
요약

6장 이미지나 CSS가 없이도 볼 수 있게 하기
흔해 빠진 구축 방식
방탄웹이 아닌 이유
방탄웹으로 만들려면?
방탄웹이 좋은 이유
스타일 유무 여부에 관계없는 디자인
방탄웹을 만들기 위한 도구 소개
요약

7장 쉽게 변환할 수 있는 테이블 만들기
흔해 빠진 구축 방식
방탄웹이 아닌 이유
방탄웹으로 만들려면?
방탄웹이 좋은 이유
요약

8장 유동적인 레이아웃 만들기
흔해 빠진 구축 방식
방탄웹이 아닌 이유
방탄웹으로 만들려면?

'책 추천' 카테고리의 다른 글

책을 읽자!!  (0) 2011.12.15
JQUERY쿡북TAEYOSCHOICE  (0) 2010.12.29
테스트 주도 개발 책 추천  (0) 2010.12.29
J2EE 컴포넌트 만들기  (0) 2010.12.29

FAQ : 프로그래밍적으로 키보드 숨김/감춤/보기. 액티비티 시작시 키보드 숨김/감춤/보기, EditText선택시 키보드 안뜨게하기 등 소프트 키보드 동작 관련 질문에 대한 답변

1. 키보드 감추기
EditText editText = (EditText) findViewById(R.id.myEdit);
InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(editText.getWindowToken(), 0);

2. 키보드 보여주기
EditText editText = (EditText) findViewById(R.id.myEdit);
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.showSoftInput(editText, InputMethodManager.SHOW_FORCED);

위 코드로 안보이는 경우 아래코드도 시도해보세요
- imm.showSoftInputFromInputMethod (editText .getApplicationWindowToken(),InputMethodManager.SHOW_FORCED);

onCreate등에서 제대로 동작하지 않는다면 
Handler로 post를 해서 위 코드를 실행시켜보세요.

3. 키보드 토글 - 위 두가지 방법으로 안되는 경우 다음과 같은 코드로 동작하는 경우가 있습니다.
imm.toggleSoftInputFromWindow(editText.getApplicationWindowToken(),  InputMethodManager.SHOW_FORCED, 0); 

4. 액티비티 시작시 자동으로 키보드 보여주기
AndroidManifest.xml의 activity 태그의 속성에 android:windowSoftInputMode="stateVisible" 혹은 "stateAlwaysVisible"삽입

5. 액티비티 시작시 자동으로 키보드 보여주지 않기
AndroidManifest.xml의 activity 태그의 속성에 android:windowSoftInputMode="stateHidden" 혹은 "stateAlwaysHidden" 삽입

6. 에디트 텍스트 선택해도 키보드 안뜨게 하기
EditText xml 속성에서 inputType 을 0으로 주면 안뜹니다.

반복되는 질문을 정리하는 FAQ 작업 진행중입니다. 키보드 동작 관련해서 정리할 글입니다. 
잘못된 부분이나 추가할 부분있으면 알려주세요.

MySQL과 SQLite 날짜 함수 비교 MySQL

2008/03/11 10:02

복사 http://blog.naver.com/kim109/50029009005

PHP로 코딩하다보면 가끔씩 SQLite를 쓸 경우도 생긴다.

그런데 날짜 관련된 함수가 MySQL과 다르기때문에 가끔 헤매기도 한다.

그래서 정리된것을 퍼왔다.

 

출처 http://sarabande.info/wiki/PHP/%E6%97%A5%E4%BB%98%E3%81%A8%E6%99%82%E5%88%BB

 

 

  Mysql SQLite
 YYYY-MM-DD HH:MM:SS  NOW() datetime('now', 'localtime')
 YYYY-MM-DD

curdate()

date_format(now(), "%Y-%m-%d") 

date('now', 'localtime')
strftime('%Y-%m-%d', 'now', 'localtime'
 HH:MM:SS

curtime()

date_format(now(),"%H:%i:%S")

time('now', 'localtime')
strftime('%H:%M:%S', 'now', 'localtime')
 YYYY/MM/DD year(curdate()) extract(year FROM curdate())
date_format(curdate(),"%Y")
 strftime('%Y/%m/%d', 'now', 'localtime')
 YYYY year(curdate()) extract(year FROM curdate())
date_format(curdate(),"%Y")
 strftime('%Y', 'now', 'localtime')
 1~12 월 month(curdate()) extract(month FROM curdate())
date_format(curdate(),"%c")
 없음
 1~31 일 dayofmonth(curdate())
extract(day FROM curdate())
date_format(curdate(),"%e")
 없음
 0~6 (0:일요일, 6:토요일) date_format(current_date, "%w")
dayofweek(current_date)-1
 strftime('%w', 'now', 'localtime')
밑의 자료 소스는  
메일 보내드리기 귀찮음 : 비번 : javaexpert

암호는 댓글 요청시 바로 보내드립니다. 수고하세영


Actvity는 총 2개이며 한개는 simple이용한거랑 BaseExpandableListAdapter이용한 거랑 있습니다.

보시다 시피 아주 간단한 ExpandableListView 의 단적인 예입니다.(1시간만에 만든 예제치곤 허접그대로입니다..^^;;;)




<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo ni = cm.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
boolean isWifiAvail = ni.isAvailable();
boolean isWifiConn = ni.isConnected();
ni = cm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
boolean isMobileAvail = ni.isAvailable();
boolean isMobileConn = ni.isConnected();
               
if(isWifiConn==false && isMobileConn==false)
{
             //인터넷에 연결할 수 없습니다. 연결을 확인하세요.
             Log.e("youngik_status", status);
             AlertDialog.Builder alert_internet_status = new AlertDialog.Builder(this);
 alert_internet_status.setTitle( "인터넷연결" );          
 alert_internet_status.setMessage( "인터넷연결을 확인하세요" );
     alert_internet_status.setPositiveButton( "닫기", new DialogInterface.OnClickListener() {
     public void onClick( DialogInterface dialog, int which) {
                       dialog.dismiss();   //닫기
      }
      });
     alert_internet_status.show();
   
}

'Android > Tip&Tech' 카테고리의 다른 글

안드로이드 키보드 보이기/안보이기  (0) 2011.01.13
MySQL과 SQLite 날짜 함수 비교 MySQL  (0) 2011.01.13
[펌] Notification 알람 관련 팁  (0) 2011.01.10
xml에 color설정하는 법  (0) 2011.01.05
Translucent  (0) 2011.01.04
출처 : http://icess.egloos.com/3341178 

알림기능을 다루기 위해서는 시스템 서비스인 NotificationManager와 Notification객체를 사용한다.

1. Notification객체 생성
Notification클래스는 생성자에 상단 상태표시줄에 보여질 아이콘, 타이틀 문구, 시간을 인자로 넘겨준다.
Notification notify = new Notification(R.drawable.my_icon, "Notification!", System.currentTimeMillis();

2. Intent객체 생성
상태표시줄을 끌어내려 확장했을때 알림을 선택할 경우 다른 activity를 실행하도록 설정한다.
Intent goto = new Intent(my_notification.this, my_notification.class);
3. PendingIntent객체 생성
PendingIntent intentBack = PendingIntent.getActivity(Notifications.this, 0, toLaunch, 0);
4. 생성한 Notification객체의 setLatestEventInfo()메서드 실행
상태표시줄을 끌어내려 확장했을때 표시될 타이틀, 내용, 선택시 실행될 intent객체 지정
notify.setLatestEventInfo(ctx, "Title", "Text-1234567890", intentBack);
5. NotificationManager 인스턴스 생성
NotificationManager notifier = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
6. NotificationManager의 인스턴스의 notify()메서드로 Notification객체 전달
각 알림을 구별할 수 있도록 id와 Notification객체 전달
notifier.notify(0x1001, notify);

* 같은 Notification객체로 중복된 알림이 있을 경우 상태표시줄에 알림 횟수를 표시해줄 수 있다.
notify.number = 2;
* 알림의 삭제
알림을 삭제하기 위해서는 알림의 id를 지정하여 삭제할 수 있다.
notifier.cancel(0x1001);
또한, Nofitication객체의 flags속성에 FLAG_AUTO_CANCEL을 지정해 줄 경우 사용자가 해당 알림을 선택시 즉시 삭제된다.
notify.flags |= Notification.FLAG_AUTO_CANCEL;

* 알림의 사용자 피드백
- 진동(Vibrator)
Vibrator를 사용하기 위해서는 AndroidManifest.xml에 아래 권한을 추가해줘야 한다.
<uses-permission android:name="android.permission.VIBRATE"></uses-permission>

진동의 설정은 홀수 배열은 진동의 시간, 짝수 배열은 진동이 멈춰있는 시간이다.
다음은 100ms진동 후 100ms진동이 멈추고, 이후 200ms간 진동이 울리고, 200ms동안 진동이 멈추게 된다.
  notify.vibrate = new long[] {100, 100, 200, 200, 300, 300, 400, 400, 500, 500};
이 패턴을 잘 활용하면 사용자에게 다양한 피드백을 전달할 수 있다.
FLAG_INSISTENT플래그를 설정할 경우 자용자가 알림을 제거할때까지 반복 재생된다.

- 지시등(LED)
LED는 Vibrator와 달리 LED를 켜고 끄는 시간만 지정해주고 사용자가 알림을 제거할때까지 반복된다.
notify.flags |= Notification.FLAG_SHOW_LIGHTS;
notify.ledARGB = Color.GREEN;
notify.ledOffMS = 1000;
notify.ledOnMS = 1000;

- 소리(Sound)
notify.sound = Uri.parse("file:/system/media/audio/ringtones/sample.ogg");
FLAG_INSISTENT플래그를 설정할 경우 자용자가 알림을 제거할때까지 반복 재생된다.

* 사용자 정의 알림 만들기
용자는 자신만의 알림화면을 구성할 수 있다.
알림에 표시될 별도의 layout을 생성한 후 아래와 같이 지정하면 된다.
RemoteViews remote = new RemoteViews(getPackageName(), R.layout.mynoti);
remote.setTextViewText(R.id.txxTitle, "Title");
remote.setTextViewText(R.id.txxText, "Text-1234567890");
notify.contentView = remote;

'Android > Tip&Tech' 카테고리의 다른 글

MySQL과 SQLite 날짜 함수 비교 MySQL  (0) 2011.01.13
안드로이드 네트워크 상태 확인!!  (0) 2011.01.12
xml에 color설정하는 법  (0) 2011.01.05
Translucent  (0) 2011.01.04
1. SurfaceView는 무엇인가?  (3) 2011.01.04
MySQL 계정 생성 MySQL

2010/05/04 11:21

복사 http://blog.naver.com/agapeuni/60106595218


//이러면 되긴한다..
CREATE USER 'USERID'@'localhost' IDENTIFIED BY 'PASSWORD';
GRANT ALL PRIVILEGES ON *.* TO 'USERID'@'localhost';
GRANT GRANT OPTION ON *.* TO 'USERID'@'localhost';

- 관리자 로그인

$ mysql -uroot -p비밀번호 mysql


- 계정 생성

mysql> insert into user ( host, user, password ) values ( 'localhost', '사용자명', password('패스워드') );


- 데이터베이스 생성

mysql> create database 디비명;


- 데이터베이스 권한 주기

mysql> insert into db ( host, db, user, select_priv, insert_priv, update_priv, delete_priv, create_priv, drop_priv) values ( 'localhost', '디비명', '사용자명', 'y', 'y', 'y', 'y', 'y', 'y' );


- 새로 적용

mysql> flush privileges;

 

 

[출처] http://antop.tistory.com/33


출처 : http://fanpro.springnote.com/pages/5306953

xml에 color설정하는 법

http://developer.android.com/intl/fr/guide/topics/resources/available-resources.html

res/values/colors.xml이라는 파일을 만들고 아래와 같이 지정하면 된다.

 

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <resources>         
  3. <color name="dim">#77000000</color>
  4. <color name="transparent">#00000000</color> 
  5. </resources> 

 

이렇게 지정한 color는 android:textColor="@color/dim" 과 같은 식으로 사용이 가능하다.

 

xml에 color state list 설정하는 법

http://androidappdocs-staging.appspot.com/reference/android/content/res/ColorStateList.html

color를 xml에 지정하기 위해서는 res/color라는 폴더를 만든 후 xml파일을 생성하면 된다.

ex) res/color/font_set_a.xml 아래의 예는 

 

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <selector xmlns:android="http://schemas.android.com/apk/res/android">
  3. <item android:state_focused="true" android:color="#cccccc" />
  4. <item android:state_pressed="true" android:color="#cccccc" />
  5. <item android:state_active="true" android:color="#333333" />
  6. <item android:color="#333333" />
  7. </selector>

 

이렇게 선언한 셀렉터는 "@color/font_set_a"와 같이 사용이 가능하다.

 

스타일 설정

위와 같이 선언한 색상들과 폰트크기등을 합쳐서 스타일을 만들 수가 있는데

res/values/styles.xml파일을 생성 후

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <resources>
  3. <style name="font_set_a">
  4. <item name="android:textColor">@color/font_set_a</item>
  5. <item name="android:textSize">36px</item>
  6. </style>
  7. <style name="font_set_b">
  8. <item name="android:textColor">@color/font_set_a</item>
  9. <item name="android:textSize">24px</item>
  10. </style>
  11. </resources>

위와 같이 묶어서 스타일을 지정할 수 있다. 이렇게 만든 스타일은 style="@style/font_set_a"와 같은식으로 사용가능하다.

 

액티비티의 테마지정(1)

액티비티는 기본적으로 title과 body로 구분되는 불투명한 스타일이다.

이를 변경할 수 있는데 해당 스타일은 아래와 같으며 manifest.xml의 <activity .../> 내에 지정하면 된다.

android:theme="@android:style/Theme.NoTitleBar" 타이틀바 제거

android:theme="@android:style/Theme.NoTitleBar.Fullscreen" 타이틀바 + 인디케이터 제거

android:theme="@android:style/Theme.Translucent.NoTitleBar.Fullscreen" 타이틀바 + 인디케이터 제거 + 투명하게 설정

 

액티비티의 테마를 xml로 지정하기(2)

values/styles.xml에 아래와 같이 속성을 지정

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <resources>
  3.  <style name="WebTheme" parent="android:Theme">
  4.              <item name="android:windowNoTitle">true</item>
  5.              <item name="android:windowFullscreen">true</item>
  6.              <item name="android:windowBackground">@android:color/white</item>
  7. </style>  

 

activity의 속성에 theme를 지정

  1. android:theme="@style/WebTheme"

 

'Android > Tip&Tech' 카테고리의 다른 글

안드로이드 네트워크 상태 확인!!  (0) 2011.01.12
[펌] Notification 알람 관련 팁  (0) 2011.01.10
Translucent  (0) 2011.01.04
1. SurfaceView는 무엇인가?  (3) 2011.01.04
AlertDialog 활용  (0) 2011.01.03
출처 : http://comxp.tistory.com/50
▶ Translucent


실행화면


소스 위치 : src/com/example/android/apis/app/Translucent.java

어떻게 activity를 반투명 하도록 하는지 보여주는 예제인데 특별한 게 없는 일반 Activity로 보이지만 AndroidManifest.xml에서 테마가 설정되어
이전 배경이 희미하게나 보인다. 뒤에 설명할 TransucentBluer와 Wallpaper와 비교하기 위함인것 같다.

AndroidManifest.xml 에서 테마로 Translucent 가 설정 되어 있다.
        <activity android:name=".app.TranslucentActivity"
                android:label="@string/activity_translucent"
                android:theme="@style/Theme.Translucent">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.SAMPLE_CODE" />
            </intent-filter>
        </activity>

Styles.xml에 Theme.Translucent가 정의 되어 있으며 부모로 android:style/Theme.Translucent을 설정했다. -> 불투명 테마 제공
    <style name="Theme.Translucent" parent="android:style/Theme.Translucent">
        <item name="android:windowBackground">@drawable/translucent_background</item>
        <item name="android:windowNoTitle">true</item>
        <item name="android:colorForeground">#fff</item>
    </style>

Translucent Class와 매치되는 XML은 translucent_background.xml (Translucent.java)
        setContentView(R.layout.translucent_background);

translucent_background.xml 파일
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/text"
    android:layout_width="fill_parent" android:layout_height="fill_parent"
    android:gravity="center_vertical|center_horizontal"
    android:text="@string/translucent_background"/>

'Android > ApiDemos' 카테고리의 다른 글


출처 : http://eddykudo.com/96

SurfaceView를 알기 쉽게 설명하기 위해 인터넷을 찾다 보니까 아주 좋은 글과 그림이 있어 원문을 그대로 인용하겠습니다(그림은 조금 손봤습니다). 

'Android Application에서 View는 GDI Thread를 통해 Surface에 그려지게 됩니다. 만약 View에 동영상 또는 카메라 프리뷰와 같이 그려지는 양이 매우 많거나 빠른 화면 변화를 원한다면 SurfaceView를 사용해야 합니다. SurfaceView의 내용은 GDI Thread를 통해서 Surface에 그려지지 않고 다른 Thread를 통해서 그려지기 때문입니다. SurfaceView는 아래 그림과 같이 Window의 아래쪽에 위치하며, Windows를 뚫어서(Punched) 자신이 보여지게끔 합니다. 단, 해당 Window 위에 다른 View가 있는 경우 블렌딩(blended)이 되어 보여지게 됩니다.' 

 

[출처] 청하가 제안하는 소프트웨어 엔지니어로써 재미있게 사는 법  http://sozu.tistory.com/35 

이해가 가시나요? SurfaceView의 핵심적인 요소를 그림을 곁들여 아주 간결하게 설명한 글이라고 생각됩니다. 조금 더 부연 설명을 하자면, 위에서 GDI라는 말이 나오는데 Graphic Device Interface의 약자로 그래픽을 기반으로 하는 사용자 인터페이스를 의미하는 용어입니다. 요즈음은 DOS처럼 텍스트를 기반으로 하는 인터페이스는 거의 사용하지 않기 때문에 그냥 UI(User Interface)라고만 해도 그건 GDI를 의미한다고 생각하셔도 됩니다. 컴퓨터를 보던지, 폰을 보던지 모두 그래픽 환경에 아이콘을 기본으로 하고 있으니까요. 

Surface는 하나의 그래픽 버퍼로써 SurfaceView에 실제로 그림을 그리는 등의 작업을 하는 것은 SurfaceHolder라고 하는 콜백(Callback) 함수 입니다. 콜백 함수는 정의해 두기만 하면 사용자가 직접 호출하지 않더라도 운영체제가 알아서 호출해 주는 함수를 의미하는 용어입니다. 지난 강좌에 사용한 Touch나 KeyDown 이벤트 핸들러, 앞으로 만들어 갈 메뉴 등이 모두 콜백함수입니다. 

인터넷에 SurfaceView와 SurfaceHolder의 관계를 그림으로 잘 표현한 것이 있어 그것도 인용하도록 하겠습니다.
 
 

[출처] 커니의 안드로이드 이야기  http://androidhuman.tistory.com/307 

위의 그림과 같이 SurfaceHolder를 이용해서 Surface라는 버퍼에 그림을 그리면 그것이 SurfaceView에 반영이 되고 그 결과가 사용자의 View에 표시되는 방식입니다. 전문적인 용어로는 더블 버퍼링이라고 하죠. 더블 버퍼링은 이미지 등을 (처리 속도가 느린) View에 직접 그리는 것이 아니라, (처리 속도가 빠른) 메모리에서 처리한 다음 (복사하듯이) 메모리에서 View로 고속 전송을 하는 개념입니다. 


2. SurfaceView class 만들기 

이론이야 어떻든 일단 프로그램을 만들어봐야죠? 새로운 프로젝트를 시작합니다. 여기에서는 설명을 쉽게 하기 위해서 프로젝트를 
Shooting01로 하기로 합니다. 

 


새 프로젝트가 만들어지면 Package Explorer(또는 Project Explorer)에서 패키지 이름(src 바로 아래에 있는 것)을 마우스 오른쪽 버튼으로 클릭하고 [New - Class] 항목을 선택합니다. 

 


[New Java Calss] 창이 나타나면 Name란에 GameView를 입력하고 Superclass를 설정하기 위해 [Browse...] 버튼을 클릭합니다. 

 


[Superclass Selection] 창이 나타나면 [Choose a type] 란에 'sur'과 같이 몇 문자만 입력하면 이클립스는 자동 완성 기능이 있으므로 [Matching Items] 항목에 'SurfaceView'라는 항목이 나타납니다. 우리는 그것을 지정합니다. 

 

 


Supperclass가 자동으로 입력이 되었습니다. 다음에는 Interface를 만들기 위해 위의 창에서[Add...] 버튼을 클릭합니다. 마찬가지 방법으로 'sur'를 입력한 다음 SurfaceHolder를 선택합니다. 

 


SurfaceHolder가 Interfaces 항목에 추가되었습니다. 아래 그림에서 빨간색으로 표시되어 있는 .Callback은 자동으로 만들어 주지 않으므로 직접 입력해야 합니다. 

 


여기 까지는 초심자가 SurfaceView를 만드는 과정이고, SurfaceView를 만드는데 익숙해지면 위의 Superclass와 Interface를 직접 입력하는 것이 더 빠를 수 있습니다. 새로운 GameView가 만들어졌습니다. 에러 표시가 보이는군요. 빨간색 x표를 클릭하면 생성자를 지정하는 창이 나타납니다. 우리는 2번 째 항목을 선택합니다. 

 


이제 프로그램은 다음과 같이 나타납니다. 알아보기 쉽게 메소드 위에 주석을 달고, arg0, arg2 등과 같이 표시된 인수를 이해하기 쉽도록 바꾸어 두었습니다. 또, 이클립스가 만든 소스에서  surfaceCreated()와 surfaceChanged()의 위치를 서로 바꾸었습니다. 별다른 이유는 없구요, 프로그램의 흐름상 생성자 다음에 surfaceCreated()가 오는 것이 순서가 맞는 것 같아서입니다. 아, 인수와 메소드의 순서를 바꾸는 것은 우리가 프로그램을 읽기 쉽게 하는 것이지 프로그램의 성능과는 전혀 상관이 없습니다. 

 

위와 같이 메소드 위에 그 기능을 제목(Title)과 같은 형식으로 주석을 달아두면 전체의 기능이 한 눈에 들어오므로 프로그램을 쉽게 알아볼 수 있습니다. 물론 개발자는 조금 번거로울 수 있겠지요(사실은 하나 만든 다음 나머지는 죄다 복사해다 쓰는 것이니까 크게 힘들 것도 없어요). 


3. SurfaceView를 사용하기 위한 준비 

SurfaceView를 움직이는 것은 SurfaceHolder인데 우리는 아직 SurfaceHolder를 만들지 않았으므로 생성자(GameView())에서 다음과 같이 입력하여 SurfaceHolder를 만들고 콜백 함수를 등록합니다. 

 


위의 2문장은 SurfaceView를 사용하기 위해 기본적으로 필요한 것이므로 공식처럼 알고 있어야 합니다. 이것으로 SurfaceView를 직접 다루는 SurfaceHolder를 만들었습니다. 이제는 SurfaceHolder를 움직일 스레드를 만들어야 합니다. 


4. Thread 만들기 

프로그램의 적당한 위치(저는 주로 맨 끝을 사용합니다)에 다음과 같이 입력합니다. 스레드는 class로 작성합니다. 스레드 class의 기본 구조는 다음과 같습니다. class 선언부, 생성자, 실제로 반복 처리될 run() 이라는 메소드. 스레드는 자동으로 만들어 주지 않으므로 우리가 직접 입력해야 합니다. 

 


위의 스레드는 혼자서 동작하는 것은 아니고 SurfaceView에서 호출해 줘야 실행을 합니다. 스레드는 SurfaceHolder를 이용해서 그림을 그리고, 또 비트맵 이미지를 읽기 위해서는 Context가 필요할 것이므로 SurfaceView로 부터 이와 관련된 자료를 함수의 호출인자(Argument) 넘겨받던지 아니면 이들을 전역변수로 만들어 서로 공유하도록 해야 합니다. 

어떤 방법을 사용하느냐는 프로그램의 상황에 따라 다르므로 어떤 것이 더 효율적이라고 단정할 수는 없습니다. 우리의 프로젝트는 강좌가 진행됨에 따라 Touch나 Key Event에서도 SurfaceHolder를 사용할 수 있으므로 Context와 SurfaceHolder를 SurfaceView 레벨의 전역변수로 사용하는 것이 프로그램의 구성이 간편해 질 수 있습니다. 

그렇다면 SurfaceView에서 다음과 같은 전역변수를 만들어야 합니다. 인수로 넘어오는 context, holder 등과 구분하기 위해 변수명 앞에 접두어 'm'을 붙였습니다. 

 


이제 다음과 같이 Thread를 기동시킵니다. 

 


mThread.start()에 의해서 우리가 만든 스레드의 run() 메소드가 실행됩니다. 이제 할 일은 스레드에서 화면을 지지고 볶고 하는 것만 남았군요. 일단은 화면에 뭔가를 그려봅시다. 다음의 이미지를 화면에 보여주려 합니다. 

                galaxy.png 
 


일단 이미지를 읽어서 canvas.drawBitmap()으로 뿌려줘야 하므로 Bitmap이 하나 필요합니다. 그림을 그리는 것은 run()에서 처리할 것이므로 Bitmap을 스레드 레벨 전역변수로 선언하고 생성자에서 이미지를 읽어옵니다. 

 


5. 스레드로 canvas에 출력하기  

스레드로 SurfaceView에 출력하는 것은 조금 복잡합니다. 일단 코드를 보시죠. 가장 기본적인 내용만 적었습니다. 

 


위의 순환문은 종료 조건이 없으므로 무한히 반복하는 구조로 되어 있습니다. SurfaceHolder의 버퍼를 canvas에 할당하고 비트맵 이미지를 그린 다음 최종적으로(finally) 버퍼의 내용을 SurfaceView에 출력합니다. 이제 프로그램을 실행해 봅니다. 

 


에구~ Hellow World가 나타났네요, 왜 그렇죠? 그리고 보니까 우리가 SurfaceView만 만들었지 정작 메인 Activity에서 View를 설정하지 않았군요. 지난번 강좌에서는 우리가 만든 View를 변수 형식으로 호출했는데 이번 강좌부터는 View 형식으로 호출해 보도록 합니다. 물론 지난번 강좌처럼 setContentView(new GameView(..))와 같은 형식으로도 호출할 수 있습니다. 

[res/layout/main.xml]을 열고 다음과 같이 입력합니다. LinearLayout을 사용할 수도 있지만 FrameLayout이 속도면에서 다소 이득이 있으므로 FrameLayout을 사용했습니다. 


 

다시 프로그램을 실행해 봅니다. 

 


이제 이미지가 나타났습니다. 그런데 이미지가 화면보다 조금 작군요. 게임의 배경이 이렇게 한쪽으로 몰려서는 곤란하겠죠? 단말기(폰)의 해상도가 각기 다른만큼 배경 이미지는 단말기의 크기에 맞도록 스케일을 조정할 필요가 있습니다. 

지난번 강좌에서 사용했던 화면의 폭과 높이를 구하는 함수를 사용할겁니다. 프로그램을 다음과 같이 수정합니다. 

 


맨 마지막 문장을 잘 보시기 바랍니다. Bitmap.createScaledBitmap()이라는 함수를 사용하고 있지요? 원본 비트맵을 width, height만큼 늘리거나 줄여서 새로운 비트맵을 만드는 것입니다. width와 height가 화면의 크기이므로 이미지가 화면의 크기만큼 확대가 될 것입니다. 프로그램을 실행하니까 화면에 꽉찬 이미지가 나타났습니다. 

 

  
여기서 한 가지 알고 넘어가야 할 것은 위의 getSystemService로 구한 것은 Device의 폭과 높이이지 View의 폭과 높이가 아니라는 사실입니다. 무슨 말이냐 하면 getSystemService로 구한 값은 Device의 해상도가 480x800이라는 의미인데, 우리가 만든 View는 타이틀과 StatusBar가 View의 일부분을 차지하고 있으므로 순수한 View의 높이는 50~76 pixel 정도 작습니다. 물론 타이틀과 StatusBar를 없애고 전체 화면을 사용하도록 하면 같은 값이 되겠죠. 

프로그램을 만들 때 타이틀과 StatusBar를 없애지 않아야 할 경우에는 View의 높이는 50~76 정도 작게 된다는 것을 염두에 두고 좌표를 설정해야 한다는 것을 알고 있어야 합니다. 

다음은 전체 소스입니다. xml은 간단한 거라서 따로 싣지 않았습니다. 


package com.Shooting01;

import android.content.*;
import android.graphics.*;
import android.util.*;
import android.view.*;
import android.view.SurfaceHolder.Callback;

public class GameView extends SurfaceView implements Callback {
     Context            mContext;
     SurfaceHolder   mHolder;
     GameThread     mThread;

     //-------------------------------------
     //      생성자
     //-------------------------------------
     public GameView(Context context, AttributeSet attrs) {
          super(context, attrs);

          SurfaceHolder holder = getHolder();
          holder.addCallback(this);

          mHolder = holder;                             // 생성한 holder를 전역변수에 저장
          mContext = context;                        // 인수로 넘어 온 context를 전역변수에 저장 
          mThread = new GameThread();         // GameThread 생성
     }

     //-------------------------------------
     //   SurfaceView가 만들어질 때 호출됨
     //-------------------------------------
     @Override
     public void surfaceCreated(SurfaceHolder holder) {
          mThread.start();                             // Thread 시작
     }

     //-------------------------------------
     //    SurfaceView의 크기가 바뀔 때 호출됨
     //-------------------------------------
     @Override
     public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

     }

     //-------------------------------------
     //   SurfaceView가 종료될 때 호출됨
     //-------------------------------------
     @Override
     public void surfaceDestroyed(SurfaceHolder holder) {

     }
 
//-------------------- 여기서 부터는 스레드 영역 ----------------------------
 
      class GameThread extends Thread {
           Bitmap imgBack;
   
           //-------------------------------------
           //    Thread Constructor
           //-------------------------------------
           public GameThread() {
                Display display = ((WindowManager) mContext.getSystemService(mContext.WINDOW_SERVICE))
                                         .getDefaultDisplay();
                int width  = display.getWidth();                          // 화면의 폭
                int height = display.getHeight();                         // 화면의 높이

                imgBack = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.galaxy);
                imgBack = Bitmap.createScaledBitmap(imgBack, width, height, true);      // 이미지 확대
           }
 
           //-------------------------------------
           //    Thread run
           //-------------------------------------
           public void run() {
                 Canvas canvas = null;                                                 // canvas를 만든다
                while (true) {
                       canvas = mHolder.lockCanvas();                           // canvas를 잠그고 버퍼 할당
                       try {
                              synchronized (mHolder) {                               // 동기화 유지
                                     canvas.drawBitmap(imgBack, 0, 0, null);    // 버퍼에 그리기
                             }
                       } finally {
                              mHolder.unlockCanvasAndPost(canvas);         // canvas의 내용을 View에 전송  
                       }
                } // while
           } // run
         
      } // End of Thread

} // End of GameView
                        



이제 SurfaceView와 스레드에 대해 어느 정도 개념이 잡히셨나요? 위에서 작성한 내용은 가장 기본적인 것으로 아직 설명하지 않는 부분이 많이 있는데,그건 다음 강좌로 넘어가야 할 것 같군요. SurfaceView가 어려운(어렵다기 보다 절차가 번거로운) 건 사실이지만 자꾸 반복해 봄으로써 완전하게 자기 것으로 만들 수 있으리라 생각합니다. 그럼 오늘 강좌는 여기서 마칩니다. 



출처 : http://neodreamer.tistory.com/411
AlertDialog 는 사용자에게 메세지나 경고를 알리기 위한 기능으로 Android 에서 지원하는 Dialog 이다. Toast 와는 다르게 Dialog 라서 Activity의 Focus를 가져간다.

대부분의 Dialog 는 Activity의 onCreateDialog() 함수에서 생성하는 것을 권장하고 있다. onCreateDialog() 에서 생성된 Dialog 는 Activity 에서 관장하고 있으며 Activity 객체들()을 상속 받는다.
showDialog() 가 호출되면 생성되지 않은 Dialog의 경우 onCreateDialog() 함수에서 생성이 되고 이후에 호출이 되어질 때에는 새로 생성하지 않고 기존 인스턴스를 그대로 이용한다. 다이얼로그가 호출되기 전에 Dialog 에 변화를 주려면 onPrepareDialog() 함수에서 처리 한다. onCreateDialog 에서 생성한 Dialog는 Activity 에서 항상 갖고 있는 객체로 더이상 필요가 없을 경우에는 시스템 시소스 확보를 위해 removeDialog() 를 호출하여 제거해 주는 것이 좋다.

간단하게 사용자에게 경고를 하기 위한 Dialog 라면 시스템이 관리하지 않고 그냥 간단하게 사용하는 것이 리소스 관리 측면에서 더 유용해 보인다.

AlertDialog 는 사용자에게 아주 간단하고 쉽게 경고 메세지를 보여 줄 수 있는 Dialog 이다. 하지만 Custom View 까지 지원하여 아주 많은 것을 표현해 줄 수 있다.

AlertDialog 는 아래의 요소를 갖을 수 있다.
  • Icon
  • Title
  • Message or ListView (두가지를 함께 지원하지 않음)
  • Custom View
  • Button (최대 3개)
Message 를 갖는 AlertDialog

Message 를 갖는 AlertDialog

ListView 를 갖는 AlertDialog

ListView 를 갖는 AlertDialog


AlertDialog 가 갖을 수 있는 모든 요소는 필요 요소가 없다. 모든 요소를 제거하고 AlertDialog 를 호출하면 Activity의 Focus를 가져오고 화면에는 아무것도 표시가 되지 않는다.

AlertDialog 를 생성하는 방법은 AlertDialog.Builder 클래스를 이용하면 된다.

아주 간단한 AlertDialog 생성하기
간단한 AlertDialog

간단한 AlertDialog




구성 요소중 Icon 과 Title 을 없애면 두 영역이 사라지지만 Icon 없이 Title 을 지정하면 기본 Icon 이 표시된다.
Icon과 Title을 제거한 AlertDialog

Icon과 Title을 제거한 AlertDialog

Icon 없이 Title 만 지정한 AlertDialog

Icon 없이 Title 만 지정한 AlertDialog



AlertDialog 에서 제공하는 ListView 활용하기
AlertDialog.Builder 에 있는 setSingleChoiceItems 함수를 이용하며 AlertDialog 에서 제공하는 ListView 를 사용할 수 있다.
ListView를 갖는 AlertDialog

ListView를 갖는 AlertDialog





Custom View 를 얹은 AlertDialog
Custom View 를 얹은 AlertDialog

Custom View 를 얹은 AlertDialog


Custom View XML



싱글쓰레드로 이루어진 상당히 간단한 UDP 에코 서버랑 클라이언트 파일 2개임

한개는 UDP 서버랑
다른 한개는 UDP 클라이언트이다

그럼 참고파일은

JQUERY쿡북TAEYOSCHOICE
카테고리 컴퓨터/IT > 프로그래밍/언어 > 프로그래밍일반
지은이 JQUERY 코어 커뮤니티 (비제이퍼블릭, 2010년)
상세보기


'책 추천' 카테고리의 다른 글

책을 읽자!!  (0) 2011.12.15
웹표준 + 방탄웹(2권)  (0) 2011.01.14
테스트 주도 개발 책 추천  (0) 2010.12.29
J2EE 컴포넌트 만들기  (0) 2010.12.29
출처 : http://cafe.naver.com/sunschool.cafe?iframe_url=/ArticleRead.nhn%3Farticleid=4408

우선 안드로이드 어플에서 서버로 이미지 파일을 전송하게 하려면 서버측에서 이미지 파일을 받아서 저장해주는 

프로그램이 필요하다. 

 

multipart/form-data 를 이용하면 파일을 업로드하는 프로그램을 작성할 수 있다.

 com.oreilly.servlet 패키지의 MultipartRequest 클래스를 이용하여 쉽게 파일 업로드를  구현할 수 있다.
http://www.servlets.com/cos/cos-05Nov2002.zip 사이트에서 cos-05Nov2002.zip 파일을 다운로드 받아서
압축을 풀어 cos.jar 파일을 <Tomcat>/common/lib 에 복사합니다.   
***************************************************************************

 

<%@ page import="java.io.*,com.oreilly.servlet.*,com.oreilly.servlet.multipart.*"%>

<% request.setCharacterEncoding("euc-kr"); %> 

<html>
<head><title>upload test</title></head>
<body>
<h3>파일 upload</h3>

<% 
        String dir=application.getRealPath("/upload");
        int max= 5*1024*1024;

        //최대크기 max바이트, dir 디렉토리에 파일을 업로드하는 MultipartRequest
        //객체를 생성한다.

        MultipartRequest m = new MultipartRequest(request,dir,max,"UTF-8",

                                               new  DefaultFileRenamePolicy());
%>

<c:set var="file1" value='<%= m.getFilesystemName("file1")%>' />   // 파일이름을 file1 이라는 파라메터로 넘겨받음
<c:set var="ofile1" value='<%= m.getOriginalFileName("file1") %>' />

<p>

<li>제목: ${subject}<br>
<li>업로드파일1: <a href=/upload/${file1}>${ofile1}</a><br>

</body>
</html>

 

 

 

카메라를 이용해 사진을 찍고, 찍어진 사진은 일단 뷰로 화면에 표시되고, 화면에 표시되는 동안

이미지파일을 서버에 전송한뒤, 전송이 완료되면 다시 카메라를 이용해 사진을 찍을 수 있도록 한다.

 

먼저 HelloCamera를 실행하기 위한 Layout

 

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
   xmlns:android="http://schemas.android.com/apk/res/android"
   android:layout_width="fill_parent"
   android:layout_height="fill_parent"
>
 
  <SurfaceView
     android:id="@+id/surface_view"
     android:layout_gravity="center"
     android:layout_height="fill_parent"
     android:layout_width="fill_parent"
     android:visibility="visible"/>
 

  <ImageView
     android:layout_height="fill_parent"
     android:layout_width="fill_parent"
     android:visibility="invisible"
     android:id="@+id/image_view" />
</FrameLayout>

 

카메라와 인터넷, 셔트를 사용하기 위한 AndroidManifest.xml 권한설정

 

    <uses-permission android:name="android.permission.CAMERA" />
    <uses-feature android:name="android.hardware.camera" />
    <uses-feature android:name="android.hardware.camera.autofocus" />
    <uses-permission android:name="android.permission.INTERNET" />

 

 

카메라 촬영및 서버로 이미지 파일 업로드를 처리하는 Activity . HelloCamera.java 첨부파일 참조

 

   

package kim.android.test;
import java.io.DataOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.hardware.Camera;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.ImageView;
import android.widget.Toast;

 

public class HelloCamera extends Activity {

    private static final String TAG = "HelloCamera";

    // 카메라 제어
    private Camera mCamera;
    // 촬영 사진보기
    private ImageView mImage;
    // 처리중 

    private boolean mInProgress;
    //카메라에 찍힌 이미지 데이터
    byte[] data;
    DataOutputStream dos;

   
    // 카메라 미리보기 SurfaceView의 리스너
    private SurfaceHolder.Callback mSurfaceListener =
        new SurfaceHolder.Callback() {

            public void surfaceCreated(SurfaceHolder holder) {
                // SurfaceView가 생성되면 카메라를 연다.
                mCamera = Camera.open();
                Log.i(TAG, "Camera opened");
                try {
                     mCamera.setPreviewDisplay(holder);
                } catch (Exception e) {
                         e.printStackTrace();
                 }
            }

            public void surfaceDestroyed(SurfaceHolder holder) {
                // SurfaceView가 삭제되는 시간에 카메라를 개방
                mCamera.release();
                mCamera = null;
                Log.i(TAG, "Camera released");
            }

            public void surfaceChanged(SurfaceHolder holder,
                                       int format,
                                       int width,
                                       int height) {
                // 미리보기 크기를 설정
                Camera.Parameters parameters =
                                     mCamera.getParameters();
                parameters.setPreviewSize(width, height);
                mCamera.setParameters(parameters);
                mCamera.startPreview();
                Log.i(TAG, "Camera preview started");
            }
        };

   

    // 카메라 셔트가 눌러질때
    private Camera.ShutterCallback mShutterListener =
        new Camera.ShutterCallback() {

            // 이미지를 처리하기 전에 호출된다.
            public void onShutter() {
                Log.i(TAG, "onShutter");
                if (mCamera != null && mInProgress == false) {
                    // 이미지 검색을 시작한다. 리스너 설정
                    mCamera.takePicture(
                        mShutterListener,  // 셔터 후
                        null, // Raw 이미지 생성 후
                        mPicutureListener); // JPE 이미지 생성 후
                    mInProgress = true;

                }
            }

        };

   
 
    // JPEG 이미지를 생성 후 호출
    private Camera.PictureCallback mPicutureListener =
        new Camera.PictureCallback() {

            public void onPictureTaken(byte[] data, Camera camera) {
                Log.i(TAG, "Picture Taken");
                if (data != null) {
                    Log.i(TAG, "JPEG Picture Taken");
    
                    //  적용할 옵션이 있는 경우 BitmapFactory클래스의 Options()
                    //  메서드로 옵션객체를 만들어 값을 설정하며
                    //  이렇게 만들어진 옵션을 Bitmap 객체를 만들때 네번째
                    //  아규먼트로 사용한다.
                    //
                    //  처리하는 이미지의 크기를 축소
                    //  BitmapFactory.Options options =
                    //      new BitmapFactory.Options();
                    //  options.inSampleSize = IN_SAMPLE_SIZE;
                   HelloCamera.this.data=data;
                   Bitmap bitmap =
                        BitmapFactory.decodeByteArray(data,
                                                      0,
                                                      data.length,
                                                      null);
                    //이미지 뷰 이미지 설정
                    mImage.setImageBitmap(bitmap);
                    doFileUpload();  //서버에 이미지를 전송하는 메서드 호출
                    Toast.makeText(HelloCamera.this, "서버에 파일을 성공적으로 전송하였습니다",
                      Toast.LENGTH_LONG).show();
                    // 정지된 프리뷰를 재개
                    camera.startPreview();
                    mInProgress = false;

                    // 처리중 플래그를 떨어뜨림
                   
                }
            }

        };

      
       public void doFileUpload() {
       try {
        URL url = new URL("http://192.168.10.2:8080/image_upload.jsp");
        Log.i(TAG, "http://localhost/image_upload.jsp" );
        String lineEnd = "\r\n";
        String twoHyphens = "--";
        String boundary = "*****";

        // open connection
        HttpURLConnection con = (HttpURLConnection)url.openConnection();   
        con.setDoInput(true); //input 허용
        con.setDoOutput(true);  // output 허용
        con.setUseCaches(false);   // cache copy를 허용하지 않는다.
        con.setRequestMethod("POST");
        con.setRequestProperty("Connection", "Keep-Alive");
        con.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + boundary);
       
        // write data
        DataOutputStream dos =
                             new DataOutputStream(con.getOutputStream());
        Log.i(TAG, "Open OutputStream" );
        dos.writeBytes(twoHyphens + boundary + lineEnd);

 

        // 파일 전송시 파라메터명은 file1 파일명은 camera.jpg로 설정하여 전송
        dos.writeBytes("Content-Disposition: form-data; name=\"file1\";filename=\"camera.jpg\"" +

                             lineEnd);

               
        dos.writeBytes(lineEnd);
        dos.write(data,0,data.length);
        Log.i(TAG, data.length+"bytes written" );
        dos.writeBytes(lineEnd);
        dos.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);
        dos.flush(); // finish upload...  
      
       } catch (Exception e) {
        Log.i(TAG, "exception " + e.getMessage());
        // TODO: handle exception
       }
       Log.i(TAG, data.length+"bytes written successed ... finish!!" );
       try { dos.close(); } catch(Exception e){}
    

    } 
       
    ImageView view;
    SurfaceView surface;


    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.camera2_layout);

        mImage = (ImageView) findViewById(R.id.image_view);

        surface =
            (SurfaceView) findViewById(R.id.surface_view);
        SurfaceHolder holder = surface.getHolder();
        view=(ImageView)findViewById(R.id.image_view);
       
        // SurfaceView 리스너를 등록
        holder.addCallback(mSurfaceListener);
        // 외부 버퍼를 사용하도록 설정
        holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
 
    }
   
    // 키가 눌러졌을때 카메라 셔트가 눌러졌다고 이벤트 처리설정
    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
    // TODO Auto-generated method stub
 
     if(event.getAction() == KeyEvent.ACTION_DOWN) {
             switch(keyCode) {
                 case KeyEvent.KEYCODE_CAMERA:
                     //videoPreview.onCapture(settings);
                  mShutterListener.onShutter();
                     /* ... */
                     return true;
             }
         }
         return false;
 }


}

'Android > Tip&Tech' 카테고리의 다른 글

1. SurfaceView는 무엇인가?  (3) 2011.01.04
AlertDialog 활용  (0) 2011.01.03
좌표변환 JAVA 소스  (6) 2010.12.13
구글맵<->naver 변환 js  (1) 2010.12.13
[펌][안드로이드]키보드 관련 팁  (0) 2010.12.13

테스트주도개발TDD실천법과도구
카테고리 컴퓨터/IT > 프로그래밍/언어 > JAVA > JAVA일반
지은이 채수원 (한빛미디어, 2010년)
상세보기

'책 추천' 카테고리의 다른 글

책을 읽자!!  (0) 2011.12.15
웹표준 + 방탄웹(2권)  (0) 2011.01.14
JQUERY쿡북TAEYOSCHOICE  (0) 2010.12.29
J2EE 컴포넌트 만들기  (0) 2010.12.29


J2EE(POJO)컴포넌트만들기
카테고리 미분류
지은이 김형준 (구민사, 2006년)
상세보기

서평

옆에 두고 싶은 책
김민재님이 쓰신 서평보기 I 평점 I 조회수(373) I 공감 (0) I 블로그
SI 프로젝트를 하면서 느끼는 것들이지만, 개발자가 하는 고민들이란게 특출나게 틀리는 것들은 별로 없다. 도메인 모델을 잘 설계해서 진정 OO적으로 중복을 제거하고 싶은 욕심과 OR 매핑을 통해 객체 모델과 관계형 DB간에 깔끔한 매핑을 시도하는 것들이 이러한 고민들 중에도 손에 꼽히는 주요 사안일 것이다.현재 수행하고 있는 플젝이 EJB 엔티티빈을 쓰지 않고 세션빈과 OR매핑 프레임워크(iBATIS)를 사용하는데, 이 책을 읽으면서 내 스스로 OR매핑 프레임워크를 만든다면 고...
자바를 공부하면서 이것저것 실제 구현된 것을 보고 싶다면..
임은천님이 쓰신 서평보기 I 평점 I 조회수(447) I 공감 (0) I 블로그
프로젝트 때문에 서울에 올라가는 도중에 이 책을 읽고, 내려오면서 모두 읽어 보았다. POJO라는 게 Plain Old Java Object라는 용어 자체는 알고 있었지만, 실제 업무에서 어떤 걸 POJO라고 하는 지 정확하게 몰랐기 때문에 읽어보게 되었다. 책의 내용은 CBD에 관련된 내용, 설계, 구현 등등에 대해서 다양한 내용들을 적용하면서 하나씩 설명을 하고 있는 구성을 가지고 있다. 또한, 단순히 설명이 아니라 직접적으로 어떻게 구현하는지 하나 하나 설명을 하고 있기 때문에 머리...


'책 추천' 카테고리의 다른 글

책을 읽자!!  (0) 2011.12.15
웹표준 + 방탄웹(2권)  (0) 2011.01.14
JQUERY쿡북TAEYOSCHOICE  (0) 2010.12.29
테스트 주도 개발 책 추천  (0) 2010.12.29
iBATIS시작 IBATIS

2010/10/02 01:58

복사 http://blog.naver.com/poloecko/70094795635

 

데이터 매퍼는 자바빈즈, Map구현체, 원시래퍼타입(String, Integer…) 그리고 SQL문을 위한 XML문서를 매핑하기 위한 XML서술자를

사용하는 매우 간단한 프레임워크를 제공한다.

 

 

 

1.Value객체정의

    POJO타입의 ?파라미터 객체 정의

    파라미터(자바빈즈, Map 또는 원시래퍼)로써 객체를 제공한다.

    파라미터 객체는 update문에서 입력값을 셋팅하기 위해 사용되거나 쿼리문의 where절을 셋팅하기 위해서 사용된다

EmpVO

 

package ex1.vo;

public class EmpVO {
    //DB에서 가져올 컬럼명들을 멤버로 선언
    //사번 이름,직종,입사일

    private String employee_id,first_name,job_id,hire_date;

    public String getEmployee_id() {
        return employee_id;
    }

    public void setEmployee_id(String employee_id) {
        this.employee_id = employee_id;
    }

    public String getFirst_name() {
        return first_name;
    }

    public void setFirst_name(String first_name) {
        this.first_name = first_name;
    }

    public String getHire_date() {
        return hire_date;
    }

    public void setHire_date(String hire_date) {
        this.hire_date = hire_date;
    }

    public String getJob_id() {
        return job_id;
    }

    public void setJob_id(String job_id) {
        this.job_id = job_id;
    }
   
}

 


 2.환경설정 파일(sqlMapConfig.xml) 작성

DB정보
SqlMap파일정보

SQL문을 위한 XML문서를 매핑하기 위한 XML서술자

<?xml version="1.0" encoding="EUC-KR"?>
<!DOCTYPE sqlMapConfig PUBLIC"-//ibatis.apache.org//DTD SQL Map Config 2.0//EN" "http://ibatis.apache.org/dtd/sql-map-config-2.dtd">
<sqlMapConfig>
    <!-- RDBMS의 정보를 입력한다. -->
    <transactionManager type="JDBC" //트랜잭션타입은 JDBC
        <dataSource type="SIMPLE"> //간단한 JDBC로 할경우
            <property name="JDBC.Driver" value="oracle.jdbc.OracleDriver"/> //DB 드라이버
            <property name="JDBC.ConnectionURL" value="jdbc:oracle:thin:@localhost:1521:xe"/>  //DB URL
            <property name="JDBC.Username" value="hr"/> //DB 아이디
            <property name="JDBC.Password" value="1111"/> // DB 패스워드
        </dataSource>
    </transactionManager>

    <!-- sqlMap파일의 정보를 입력한다-->
    <sqlMap resource="ex1\sqlMap\emp.xml"/>
   
</sqlMapConfig>

 

 

3.sqlMap파일작성

SQL문 작성 

 구문타입

 속성 (결과객체,파라미터객체지정)

 사용하는 경우

 <select>

 id,parameterClass,resultClass,parameterMap,resultMap

 데이터조회

 <insert>

 id,parameterMap,resultMap

 데이터입력

 <update>

 id,parameterMap,resultMap

 데이터수정

 <delete>

 id,parameterMap,resultMap

 데이터삭제

 

 

데이터 매퍼프레임워크는 매핑된 구문을 실행하여 PreparedStatement 인스턴스를 생성할것이고

제공된 파라미터객체를 사용해서 파라미터를 셋팅하고 ResultSet으로부터 결과 객체를 생성한다.

<sql.xml>

<?xml version="1.0" encoding="EUC-KR"?>
<!DOCTYPE sqlMap PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN" "http://ibatis.apache.org/dtd/sql-map-2.dtd">
<sqlMap>
    <!-- select절을 수행한 후 모든 결과를 EmpVO로 생성하여 java.util,List로 저장하여 반환하는 SELECT! -->
    <select id="empAll" resultClass="ex1.vo.EmpVO">
        SELECT employee_id,first_name,job_id,hire_date FROM employees
    </select>

    <select id="searchName" resultClass="ex1.vo.EmpVO" parameterClass="String">
        SELECT * FROM employees WHERE first_name = #n#
    </select>
</sqlMap>

 

 

 

 


4.JavaApp생성

  1 ) 환경설정파일 스트림 로드
  2 ) 클라이언트객체생성

  3 ) iBATIS를 활용하여 SQL문 호출

  4 ) 결과확인

       update의 경우에 영향을 미친 rows의 숫자를 반환한다.

       조회작업인 경우에 한 개(single)의 객체 또는 컬렉션 객체를 반환한다.

       파라미터처럼 결과 객체는 자바빈즈, Map 원시타입래퍼또는 XML이 될수 있다.

  package ex1.client;

import com.ibatis.common.resources.Resources;
import com.ibatis.sqlmap.client.SqlMapClient;
import com.ibatis.sqlmap.client.SqlMapClientBuilder;
import ex1.vo.EmpVO;
import java.io.IOException;
import java.io.Reader;
import java.sql.SQLException;
import java.util.List;
import java.util.Scanner;

public class EmpClient {
    public static void main(String[] args) throws IOException, SQLException {
        //1)iBATIS환경설정 파일(sqlMapConfig.xml)을 스트림으로 생성한다
        Reader r = Resources.getResourceAsReader("ex1/config/sqlMapConfig.xml");

        //2)위에서 생성한 스트림을 가지고 sqlMap들만 가져와 sqlMapClient에게 전해준다.
        SqlMapClient smap = SqlMapClientBuilder.buildSqlMapClient(r);

        r.close();

        //3) iBATIS활용-id가 empAll인 select요소를 수행한다.
        List<EmpVO> list = smap.queryForList("empAll");

        //4) 확인
        for (EmpVO vo : list) {
            System.out.println(vo.getEmployee_id()+"/"+vo.getFirst_name());
        }

        System.out.print("이름:");
        Scanner sc = new Scanner(System.in);
        String name = sc.nextLine();

        List<EmpVO> names = smap.queryForList("searchName", name);
         for (EmpVO vo : names) {
            System.out.println(vo.getEmployee_id()+"/"+vo.getFirst_name());
        }
    }
}

 

스크랩하기

덧글 쓰기 엮인글 쓰기

IBATIS’ 카테고리의 다른 글

매핑 구문 (1)

2010.10.02

SQLMap환경설정 파일(sqlMapConfig.xml) (2)

2010.10.02

iBATIS시작 

2010.10.02

iBatis란? (3)

2010.10.01



JSP

 

http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd

 

몇버전 부터인지는 정확히 모르겠고 web.xml에 2.4나 2.5에서 <taglib>를 쓰면 에러메시지가 뜬다.

 

cvc-complex-type.2.4.a:Invalid content was found starting with element 'taglib'

 

 

해결 방법은 <taglib>를 <java-config>태그안에 넣는다.

 

ex.

 <jsp-config>
  <taglib>
   <taglib-uri> ...   </taglib-uri>
   <taglib-location> ... </taglib-location>
  </taglib>
 </jsp-config>

[출처] web.xml taglib error|작성자 알콜진

'jsp' 카테고리의 다른 글

jsp에서 톰켓로그 보여주기(실시간 아님)  (0) 2012.11.27
페이징 처리기법  (0) 2012.11.25
jstl설치하기  (0) 2010.12.22

JSTL 설치하기 JSTL 관련

2010/03/17 14:40

복사 http://blog.naver.com/oppasw/150082827283

JSTL (JSP Tag Library) 는 일반적으로 사용하는 JSP 태그들을 표준화 시킨것이다. 여기에는 아래와 같은 것들이 많이 사용된다.

CORE http://java.sun.com/jstl/core :: c
XML http://java.sun.com/jstl/xml :: x
I18N http://java.sun.com/jstl/fmt :: fmt
SQL http://java.sun.com/jstl/sql :: sql

이러한 tablib 를 jsp page 에서 사용하려면 다음과 같이 넣어주면 된다. 아래의 경우는 예를 들어 core 부분을 사용하기 위하여 넣어 준 경우이다.

예) <%@ taglib prefix="c"  uri="http://java.sun.com/jstl/core"  %>

 

이와 같이 JSP 페이지에 선언하여 사용하기 위해서 JSTL 관련 라이브러리와 tld 파일을 설치 해 주어야 동작하게 된다. 이과정을 JSTL 설치 과정이라 생각하면 될 듯 하다.

JSTL 설치는 그렇게 어렵지 않다. 어떠한 경우 아파치나 톰켓을 설치하는 패키지등이 설치해주는 경우도 있겠지만, 그런경우라 하더라도 다음과 같이 준비해주면 설치가 되었는지 알 수도 있을 것 같다.

 

1. 다운로드

일단 JSTL 을 다운 받을 수 있는 곳은 몇군데 있지만 http://apache.org 에서 받는것을 권장한다. 그 이유는 여기서는 JSTL 만 독자적으로 받아 설치 할 수 있기 때문이다.

http://jakarta.apache.org/site/downloads/downloads_taglibs.html 여기에 가면 중간쯤에 Standard 1.1 Taglib 가 있을 것이다.

바로 받기:

  • Binaries

  • Source

  • 2. 설치하기

    아파치 톰켓이 설치된 폴더에 가면 WEB-INF 라는 폴더가 있을 것이다.

    - WEB-INF/lib 디렉토리에 jstl.jar 와 standard.jar 파일을 넣는다.
    - WEB-INF/tld  디렉토리에 tld 폴더의 내용을 복사한다.

    설치는 다 끝난 것이다. 궂이 윈도우서버나 아파치를 다시 실행 할 필요는 없다.

     

    3. 설정하기

    이렇게 설치된 JSTL 을 사용하기 위해서 우리는 WEB 서버 설정에 넣어 주어야 한다. 넣어주는 것은 URI 에 대한 실제 파일(앞에서 설치/복사한 파일) 을 연결해 준다고 생각하면 된다.

    가령 STL 을 사용하기 위하여 우리는 앞의 예에서

    <%@ taglib prefix="c"  uri="http://java.sun.com/jstl/core"  %>

    라고 web page 소스 위에 넣어 주어야만 한다. 이는 java.sun.com 에 있는 사이트를 연결하라는 것이 아니라 uri 에 들어 있는 것을 하나의 키로 생각하여 라이브러리 경로를 찾아 주는 것이라 생각하면 된다. 그러므로 다음과 같은 내용을 WEB.XML 에 넣어 주도록 한다.

     

    <taglib>

               <taglib-uri>http://java.sun.com/jstl/core</taglib-uri>

               <taglib-location>/WEB-INF/tld/c.tld</taglib-location>

    </taglib>

    <taglib>

                <taglib-uri>http://java.sun.com/jstl/xml</taglib-uri>

                <taglib-location>/WEB-INF/tld/x.tld</taglib-location>

    </taglib>

    <taglib>

                 <taglib-uri>http://java.sun.com/jstl/fmt</taglib-uri>

                 <taglib-location>/WEB-INF/tld/fmt.tld</taglib-location>

    </taglib>

     

    WEB.XML 은 WEB-INF 폴더에 있다.

     

    4. JSP 선언

    앞서 말했듯이 JSTL 을 사용하기 위하여 JSP 페이지에 다음과 같이 선언해주어야 한다.

    <%@ taglib prefix="c"  uri="http://java.sun.com/jstl/core"  %>

     

     

    5. 설치 확인

    설치 확인은 뭐,,, 정해진 것은 없고 , 앞의 선언을 해주고 페이지 한번 돌려 보면 되지 않을까??? 한다.

    스크랩하기

    덧글 쓰기 엮인글 쓰기

    롯데닷컴 다운
    다운, 롯데닷컴, 인터넷 백화점, 신한, 롯데 5%혜택, 포인트 대축제.
    www.lotte.com
    파일 곰기프트
    파일판촉물, 생활용품, 악세사리, 사무문구, 주방용품, 신변잡화
    www.gomgift.com
    다운로드 윙키
    음악다운로드, 전곡무료감상, 실시간음악감상, 한달무제한다운로드, mp3무료다운
    www.winky.co.kr
    JSTL 관련’ 카테고리의 다른 글

    JSTL 사용하기 (2) 

    2010.03.17

    JSTL 사용하기 (1) 

    2010.03.17

    JSTL 답변형 게시판+방명록 소스 

    2010.03.17

    Eclipse 에서 JSTL 사용하기 

    2010.03.17

    SQL Tag Library 

    2010.03.17

    'jsp' 카테고리의 다른 글

    jsp에서 톰켓로그 보여주기(실시간 아님)  (0) 2012.11.27
    페이징 처리기법  (0) 2012.11.25
    web.xml에서 taglib error날때  (0) 2010.12.22

    범죄/수사 스릴러물을 좋아하는 사람들은, 현장작전요원들이 본부에 현장상황을 실시간 영상으로 보내면서 지원을 받거나 하는 장면을 많이 봤을 것이다. 특히, 미국드라마 24에서 수없이 나오는 장면이다.
    만약 당신이 프로요(안드로이드 버젼 2.2)를 사용하고 있다면, IP Webcam 을 통해 당신도 이제 그렇게 할 수 있다. 매우 손쉽게 말이다.

    오른쪽 QR코드를 통해 IP Webcam 어플리케이션을 설치하고, 실행해 보자. Login 과 Password 입력필드가 있으나 거기 쓰여진것 처럼, 로그인은 안해도 된다.
    그리고 그 아래부턴 영상의 사이즈, 초당 프레임 수, 영상의 품질, TCP Port, 그리고 몇가지 체크옵션들이 보이겠지만 어려운 부분은 없으므로 입맛대로 설정하되, 대부분 디폴트로 사용해도 무리는 없다. 단, 3G접속 상태에서는 TCP Port 8080 이 열리지 않아 상대방이 접속을 못하는 경우가 있을 것이므로, 임의의 다른 포트를 할당해 주는 것이 안전할 것이다. (필자는 8555 로 설정해서 성공했다.)
    이제 맨 아래 네가지 버튼이 있다. [Start server] 는 본인의 IP 로 캠영상 스트리밍을 시작하는 것이고, [Stop server] 는 물론 끝내는 것이다. [Instructions/FAQ] 에서 이 어플에 대한 소개와 FAQ를 읽어볼 수 있고, [Copy URL to clipboard] 는 송출되고 있는 스트리밍에 접근할 수 있는 URL주소를 클립보드로 복사하여 MMS나 인스턴트메신져, 트위터 등에 붙여넣어 즉각적으로 전파하기 위해 필요할 것이다
    그럼, [Start server] 를 터치해 보자. 곧바로 캠이 활성화되고 스트리밍이 시작된다. 이제 누구든지 나의 IP 주소만 알면, 위에서 설정한 TCP Port 를 통해 이 캠영상을 실시간으로 볼 수 있는 상태가 된 것이다.
    테스트를 위해 화면에 표시된 URL 을 자신의 PC에서 브라우져에 입력해 보자.
    브라우져창에는 이 캠영상을 보기 위해 선택할 수 있는 방법들이 나열될 것이다.

     * Open stream in media player, such as VLC : 외부의 스트리밍 감상 지원 어플리케이션을 통해 볼 수 있다. 영상을 녹화하는 등의 작업이 필요하다면 VLC 를 설치해 두고 이걸 선택하면 될 것이다.
     * Use java browser plugin : 브라우져에 자바 플러그인이 설치되어 있다면 이게 가장 좋은 성능을 보일 것이다.
     * Use javascript to update frames in browser : 대부분의 브라우져가 지원하는 자바스크립트를 이용해서 보는 것이다.
     * Use browser built-in viewer (not supported by all browsers) : 브라우져 내장 기능을 이용하는 것이며, 현재는 크롬과 파이어폭스에서만 가능하다.
     * (Windows only) Connect to PC for use with Skype and other videochats : 웹캠 기능을 지원하는 메신져에서 상대방에게 중계할 수 있으나, 윈도우즈 운영체제에서만 가능하고, http://ip-webcam.appspot.com/ 에서 어댑터를 다운받아 설치해야한다.
     * Take immediate photo : 클릭하는 순간의 프레임을 스틸로 캡쳐.

     대부분의 브라우져는 자바스크립트를 지원하므로, 시험삼아 세번째 줄에 있는 'Use javascript to update frames in browser' 를 선택해 보자. (만약 자바 플러그인이 설치되어있거나, 크롬 혹은 파이어폭스를 사용한다면 굳이 자바스크립트를 통해 볼 필요는 없다. 처리속도가 가장 딸리기 때문이다.)

     주의할 점은, 유무선공유기를 사용한 Wifi 접속상태에서는 공유기 내부의 IP 를 할당받기 때문에 다른곳에서 해당 IP로 접근할 수 없으므로, 3G망을 이용해야 한다는 것이다.


     이쯤에서 가슴이 벅찬 사람도 있을 것이다... 이것은 매우 다양한 용도로 응용될 수 있을 것이기 때문이다. 부디 유용한 방향으로 활용하길 권장하며 소개를 마치겠다.

    마지막소스 첨부는

    자 이제 마지막 리팩토링이네영..

    책에선 제네릭을 이용한 다양한 형태로의 변환이 되는 자유로운 팩토링을 보였는데 정말 새롭고 유용한 방법인것 같아서 강추!!

    암튼 소스는 다음과 같습니다..

    만약 String값을 이용해서 덧붙이는 기능을 사용하고자 할때에는 이런식으로 바꿔주면 되는군요.

    우선 Test해볼 메소드입니다.(여기서 파일안에 있는 숫자를 순서대로 덧붙이는 메소드입니다)

    @Test public void concatenateOfNumber() throws IOException{
    String concateStr = calculator.concatenateString(filepath);
    assertThat(concateStr,is("1243"));
    }

    public class Calculator {
    public <T> T lineReadTempleter(String filepath,LineCallback<T> callback,T initVal) throws IOException{
    BufferedReader br = null;
    try {
       br = new BufferedReader(new FileReader(filepath));
       String line = null;
       T res = initVal;
       
       while( (line = br.readLine()) != null ){
        res = callback.doSomethingWithLine(line, res);
       }
       return res;
    } catch (IOException ie) {
    // TODO: handle exception
    ie.printStackTrace();
    } catch (Exception e){
    e.printStackTrace();
    } finally {
    if(br!=null){
    try {
    br.close();
    } catch (Exception e2) {
    // TODO: 무시
    }
    }
    }
    return null;
    }
    public Integer calcSum(String filepath) throws IOException{
    LineCallback<Integer> callback = 
    new LineCallback<Integer>(){
    @Override
    public Integer doSomethingWithLine(String line, Integer value) {
    // TODO Auto-generated method stub
    return Integer.parseInt(line) + value;
    }
    };
    return this.lineReadTempleter(filepath, callback, 0);
    }

    public int calcMultiply(String filepath) throws IOException{
    //TODO Auto-generated method stub
    LineCallback<Integer> callback = 
    new LineCallback<Integer>(){
    @Override
    public Integer doSomethingWithLine(String line, Integer value) {
    // TODO Auto-generated method stub
    return Integer.parseInt(line) * value;
    }
    };
    return this.lineReadTempleter(filepath, callback, 1);
    }
    //주어진 String을 합치는 메소드
    public String concatenateString(String filepath) throws IOException{
    LineCallback<String> callback = 
    new LineCallback<String>(){
    @Override
    public String doSomethingWithLine(String line, String value) {
    // TODO Auto-generated method stub
    return value + line;
    }
    };
    return this.lineReadTempleter(filepath, callback, "");
    }
    }

    여기서 주의해서 봐야할껀 템플릿 메소드에 T라고 제네릭코드 가 들어간다는 점..

    암튼 참 도움 많이 되는 책인것 같습니다..

    토비의 스프링 화이팅!!
    3단계에서 보면 calc()랑 multiply()부분에서

    while문에서 가져오는 부분이 중복된다는 걸 볼수 있다.

    이걸 템플릿/콜백 패턴으로 중복 제거하면(어디까지 갈것인가..두둥..==ㅣ)

    public class Calculator {
    public Integer lineReadTempleter(String filepath,LineCallback callback,int initVal) throws IOException{
    BufferedReader br = null;
    try {
       br = new BufferedReader(new FileReader(filepath));
       String line = null;
       Integer res = initVal;
       
       while( (line = br.readLine()) != null ){
        res = callback.doSomethingWithLine(line, res);
       }
       return res;
    } catch (IOException ie) {
    // TODO: handle exception
    ie.printStackTrace();
    } catch (Exception e){
    e.printStackTrace();
    } finally {
    if(br!=null){
    try {
    br.close();
    } catch (Exception e2) {
    // TODO: 무시
    }
    }
    }
    return 0;
    }
    public Integer calcSum(String filepath) throws IOException{
    LineCallback callback = 
    new LineCallback(){
    @Override
    public Integer doSomethingWithLine(String line, Integer value) {
    // TODO Auto-generated method stub
    return Integer.parseInt(line) + value;
    }
    };
    return this.lineReadTempleter(filepath, callback, 0);
    }

    public int calcMultiply(String filepath) throws IOException{
    //TODO Auto-generated method stub
    LineCallback callback = 
    new LineCallback(){
    @Override
    public Integer doSomethingWithLine(String line, Integer value) {
    // TODO Auto-generated method stub
    return Integer.parseInt(line) * value;
    }
    };
    return this.lineReadTempleter(filepath, callback, 1);
    }
    }

    이때 콜백으로 처리된 인터페이스는 다음과 같다.

    public interface LineCallback {
    Integer doSomethingWithLine(String line,Integer value);
    }

    흠냐...대단하단 말밖에 안나온다...^^;

    계속해서 리팩토링 되는 것 같다...(소름끼침..==ㅣ);
    템플릿/콜백 패턴은 간단한 정의로는 중복되는 코드들을 인터페이스등을 통한 추출로 인하여 코드의 간결함과 효율성을 높이는 데 있다고 한다.

    여기 예제에서는 파일입출력시 try/catch/finally등 자원반납에 관해서 모든 메소드가 중복되고 있다.

    그래서 그 부분을 빼고자 하는 것이다.

    암튼 적용한 다음의 소스는 다음과 같다. 
    (참고 : @Before는 junit실행시 서론, @Test는 본론, @after는 결론) 

    JUnit는 main메소드가 없어도 테스트를 실행함..^^

    CalcSumTest.java

    public class CalcSumTest {
    Calculator calculator;
    String filepath;
    @Before public void setUp(){
    calculator = new Calculator();
    filepath = getClass().getResource("numbers.txt").getPath();
    }
    @Test public void sumOfNumber() throws IOException{
    int sum = calculator.calcSum(filepath);
    System.out.println(sum);
    assertThat(sum,is(10));
    }
    }

    그리고 템플릿 메소드와 계산메소드가 있는 계산 클래스
    public class Calculator {
    public Integer calcTemplete(String filepath,BufferedReaderCallback callback) {
    BufferedReader br = null;
    int result = 0;
    try {
       br = new BufferedReader(new FileReader(filepath));
     
       result = callback.doSomethingWithReader(br);
    } catch (IOException ie) {
    // TODO: handle exception
    ie.printStackTrace();
    } catch (Exception e){
    e.printStackTrace();
    } finally {
    if(br!=null){
    try {
    br.close();
    } catch (Exception e2) {
    // TODO: 무시
    }
    }
    }
    return result;
    }
    public Integer calcSum(String filepath){
    BufferedReaderCallback callback = 
    new BufferedReaderCallback(){
    @Override
    public Integer doSomethingWithReader(BufferedReader br){
    // TODO Auto-generated method stub
    int sum = 0;
    try {
    String line = "";
    while( (line = br.readLine()) != null ){
    sum += Integer.parseInt(line);
    }
    } catch (Exception e) {
    // TODO: handle exception
    e.printStackTrace();
    }
    return sum;
    }
    };
    return calcTemplete(filepath,callback);
    }
    }

    그리고 콜백 인터페이스

    public interface BufferedReaderCallback {
    Integer doSomethingWithReader(BufferedReader br);
    }

    그럼 만약 곱하기를 추가한다고 가정하면 어떻게 하면 될까?

    참 간단해진다.

    우선 테스트 코드 하나 넣고
    @Test public void mutiplyOfNumber() throws IOException{
    int multiply = calculator.calcMultiply(filepath);
    assertThat(multiply,is(24));
    }

    그다음 SUM이랑 비슷한 메소드만 카피 앤 패스트 하면 된다.
    public int calcMultiply(String filepath) {
    // TODO Auto-generated method stub
    BufferedReaderCallback callback = 
    new BufferedReaderCallback(){
    @Override
    public Integer doSomethingWithReader(BufferedReader br){
    // TODO Auto-generated method stub
    int multiply = 1;
    try {
    String line = "";
    while( (line = br.readLine()) != null ){
    multiply *= Integer.parseInt(line);
    }
    } catch (Exception e) {
    // TODO: handle exception
    e.printStackTrace();
    }
    return multiply;
    }
    };
    return calcTemplete(filepath,callback);
    }


    package springbook.learningtest.template;

    import java.io.BufferedReader;
    import java.io.FileReader;
    import java.io.IOException;

    public class Calculator {
    public Integer calcSum(String filepath) {
    BufferedReader br = null;
    int sum = 0;
    try {
    br = new BufferedReader(new FileReader(filepath));
    String line = null;
    while( (line=br.readLine())!=null ){
    sum += Integer.parseInt(line);
    }
    br.close();
    } catch (IOException ie) {
    // TODO: handle exception
    ie.printStackTrace();
    } catch (Exception e){
    e.printStackTrace();
    } finally {
    if(br!=null){
    try {
    br.close();
    } catch (Exception e2) {
    // TODO: 무시
    }
    }
    }
    return sum;
    }
    }

    출처 : 1400페이지짜리 '토비의 스프링' 서적
    간단한 파일 입출력 리펙토링 과정을 보여준다.

    우선 기본적으로 알아야 하는 건 JUnit 방법이다..

    검색해보면 금방 알수 있으므로 해보삼^^

    실제 계산하는 Calculator.java

    package springbook.learningtest.template;

    import java.io.BufferedReader;
    import java.io.FileReader;
    import java.io.IOException;

    public class Calculator {
    public Integer calcSum(String filepath) throws IOException{
    BufferedReader br = new BufferedReader(new FileReader(filepath));
    int sum = 0;
    String line = null;
    while( (line=br.readLine())!=null ){
    sum += Integer.parseInt(line);
    }
    br.close();
    return sum;
    }
    }

    이걸 이용하는 구현 클래스는 CalcSumTest.java

    여기서 빨간부분을 주의해서 보도록..

    package springbook.learningtest.template;

    import static org.hamcrest.CoreMatchers.is;
    import static org.junit.Assert.assertThat;

    import java.io.IOException;

    import org.junit.Test;

    public class CalcSumTest {
    @Test
    public void sumOfNumber() throws IOException{
    Calculator calculator = new Calculator();
    int sum = calculator.calcSum(getClass().getResource("numbers.txt").getPath());
    assertThat(sum,is(10));
    }
    }


    여기서 문제점은 try/catch/finally를 안넣어서 중간에 예외가 발생하면 자원반납을 안해줘서 문제가 됨.

    그래서 2단계에선 묶어줌..
    출처 : http://blog.naver.com/lriberio?Redirect=Log&logNo=80068562529

    Spring Framework 다운로드

     

    (2008년 11월 4일 기준)

     

    1. http://www.springsource.org/download 로 간다.

     

    2. http://www.springsource.com/download?project=Spring%20Framework 로 이동된다.

       아래로 조금 스크롤 => Community Download [Download Now] 를 클릭한다.

    3. [No thanks, take me to the download] 클릭

    4. spring-framework-2.5.6-with-dependencies.zip 클릭

    5. 저장 후 압축 해제 아래 경로에 있는 라이브러리 추가 할 것

      - %SRPING_HOME%\dist\modules

     

     
    6. eclipse 안에 build path 추가
     
     
     
    7. 해당 프로젝트에 추가한 라이브러리 설정
     
    [Spring] 이클립스에 스프링 개발환경 셋팅 Spring

    2010/08/25 11:25

    복사 http://skyunoe.blog.me/20112368374

    Java JDK 설치 : http://java.sun.com (version 1.6.20)

    Apache Tomcat 설치 : http://apache.org  (version 7)

    Eclipse IDE 설치 ; http://www.eclipse.org (Eclipse IDE for Java EE Developers 3.6 package)

    Spring Framework 설치 : http://www.springsource.com/download/community?project=Spring%20Framework (version 3.0.4)

     

    1. Help > Install New Software ... 메뉴로 이동하여 클릭해 줍니다.

     

    그럼 아래와 같은 다이얼로그가 생성 됩니다.

     

    2. 좌측 상단의 "Add..." 버튼을 클릭하면 Add Repository 다이얼로그가 나옵니다.

       여기에 아래 그림과 같이 적어 줍니다.

       Spring 업데이트 URL은 http://springide.org/updatesite 입니다.

     

     

    3. Work width 콤보박스에서 2번에서 등록했던 항목을 선택하면 다이얼로그 중앙에 설치할 내역이 보여 집니다.

       그림과 같이 Core, Extensions(Incubation) , Extensions, Resources 를 선택하고 "Next" 버튼을 누릅니다.

       

     

    4. 앞서 선택한 항목에 대한 Detail한 항목이 나옵니다 계속 "Next" 버튼을 눌러줍니다.

     

    5. 약관에 동의하고 "Finish" 버튼을 누르면 설치가 시작됩니다.

     

    6. 설치가 모두 끝나면 Eclipse를 재시작 하라는 메시지가 나옵니다.  재시작 해주시면 됩니다.

     

    7. 이클립스 상단의 File > New > Project 메뉴를 눌러봅니다. 프로젝트 생성란에 Spring이 추가되었습니다.


    + Recent posts