급하게 바코드 인식 관련 프로그램을 만들다 보니 오픈소스를 검색하게 되었고 Google에서 제작한 zxing 이란 것을 발견하게 되었습니다. (GitHub : https://github.com/zxing/zxing)

해당 코드와 관련된 포스팅들이 여럿 나왔지만 다 조금 씩 부족한 부분들이 있어서 정리 차원에서 올립니다.

물론 제가 올린 내용도 부족한 부분이 많습니다.


1. 외부 앱을 이용한 방법


이미 외부 앱을 이용해서 구동하는 방법은 잘 정리된 곳이 있습니다.

관련 포스팅은 http://code.tutsplus.com/tutorials/android-sdk-create-a-barcode-reader--mobile-17162 를 참고하시면 됩니다.

간단하게 정리하자면 Github에서 다운로드 받은 소스 중에 IntentIntegrator.java와 IntentResult.java 두개의 파일만 사용하는 것입니다.

특정 Button의 onClick Event에서 아래 내용을 호출할 수 있도록 하면 됩니다.




그러면 onActivityResult에서 특정 앱에서 Scan한 값을 받게 됩니다.

리턴 받게 된 값은 아래와 같은 형식으로 받으면 됩니다.




이렇게 하는 방법은 매우 쉽지만 외부 앱을 추가로 깔아야 한다는 단점이 있습니다.

자체적으로 카메라를 구동 시키고 바코드나 QR코드를 인식할 수 있다면 좋겠다는 생각에 다른 방법을 찾아 보았습니다.

조금 무식하지만 필요한 소스 코드를 다 포함하고, 자체적으로 구동하는 것이죠.


2. 자체 구현


사실 소스 코드 크기가 좀 되기에 자체 구현하기가 망설여 졌지만 일단 구현하였습니다.

자체 구현 관련되어서 참고한 사이트는 http://fishbear.tistory.com/3 입니다.

그런데 ant로 core.jar 파일을 만들어야 한다는데... build.xml 파일이 없더라는 ㅠㅠ

그래서 더 찾아보니 zxing의 특정 버전부터 maven으로 바뀌었다고 하네요.

그래서 maven으로 jar 파일을 만들었지만... 호출해야 하는 Activity인 CaptureActivity 가 해당 jar 파일 안에 없더군요 ^^;;

어쩔 수 없이 해당 소스코드를 다 lib 프로젝트에 포함 시켰습니다.

이로 인해 생기는 Resource 관련 오류들을 fix하기 위해 zxing 안에 있는 res 파일들을 포함 시켰구요 ㅠㅠ

어째든 에러가 없도록 만든 다음... 다음과 같이 사용을 하면 됩니다.(fq는 AQuery 인스턴스입니다. AQuery를 사용 안하시는 경우는 native로 구현 하세요.)




하지만 이렇게 하게 될 경우 SCAN이란 Activity가 없다는 에러가 발생합니다.

따라서 Manifest 파일에 다음과 같이 정의를 해 줘야 합니다.




이렇게 하게 되면 성공적으로 바코드 인식 프로그램이 내부적으로 뜨게 됩니다.

그리고 바코드 인식 후 onActivityResult에서 다음처럼 받아 사용하면 됩니다.




49374란 숫자는 intent를 띄울 때 넘어가는 request code 같은데 정확하게 저 숫자가 뭘 의미하는지는 모르겠습니다.

다만 구분하기 위한 숫자이기에 특정 constant에 넣어 사용했습니다.


이상 간단하게 정리해본 Bar Code, QR Code 인식 Android 앱 만들기 정리 포스팅이였습니다.






저작자 표시 비영리 변경 금지
신고
크리에이티브 커먼즈 라이선스
Creative Commons License

WRITTEN BY
체리필터
프로그램 그리고 인생...

받은 트랙백이 없고 , 댓글 하나 달렸습니다.
  1. 모바일에선 소스코드가 안 보이네요. PC버젼으로 봐 주세요 ^^
secret

스마트폰에서 Pull to Refresh를 사용하는 것은 매우 흔해진 일이고, 그래서 안드로이드에서도 Pull to Refresh를 구현한 오픈소스가 있다.

현재 프로젝트에서는 handmark.pulltorefresh liabrary를 이용하는데 리스트를 당겼을 시 나오는 폰트의 색깔을 변경하는 것이 어떻게 하는 것인지 몰랐다.

해당 라이브러리의 소스를 분석해서 찾아 들어가 보니 아래와 같은 소스를 만날 수 있었다.


// Text Color attrs need to be set after TextAppearance attrs

if (attrs.hasValue(R.styleable.PullToRefresh_ptrHeaderTextColor)) {

ColorStateList colors = attrs.getColorStateList(R.styleable.PullToRefresh_ptrHeaderTextColor);

if (null != colors) {

setTextColor(colors);

}

}


R.styleable에 정의된 PullToRefresh_ptrHeaderTextColor를 이용한다는 것이었다.

R.styleable이 뭐하는 것인지 또 구글링...

요놈은 attrs.xml 파일에 정의된 내용을 사용하는 것이라는 결론을 내렸다.

attrs.xml 파일 안을 뒤져보니 아래와 같이 ptr에 정의된 내용이 나오더라.


<declare-styleable name="PullToRefresh">


        <!-- A drawable to use as the background of the Refreshable View -->

        <attr name="ptrRefreshableViewBackground" format="reference|color" />


        <!-- A drawable to use as the background of the Header and Footer Loading Views -->

        <attr name="ptrHeaderBackground" format="reference|color" />


        <!-- Text Color of the Header and Footer Loading Views -->

        <attr name="ptrHeaderTextColor" format="reference|color" />


        <!-- Text Color of the Header and Footer Loading Views Sub Header -->

        <attr name="ptrHeaderSubTextColor" format="reference|color" />


ptrHeaderTextColor, ptrHeaderSubTextColor라는 속성을 가진 놈을 어떻게 잘 요리하면 색이 바뀔 듯도 한데... 정확히 사용법을 몰라 또 구글링...

결론은 아래와 같이 layout xml에 정의하면 된다.


 <com.handmark.pulltorefresh.library.PullToRefreshGridView

        xmlns:ptr="http://schemas.android.com/apk/res-auto"

......

ptr:ptrHeaderTextColor="#336699"

ptr:ptrHeaderSubTextColor="#336699"/>


ptr이란 namespace를 정의한 후 해당 속성을 정의하면 된다.

바로 빌드하고 테스트 해 보니 제대로 나오는 것을 확인 ^^


오늘 알게 된 내용도 나 혼자 잊어 버리지 않고자 적어둔 내용이므로, 정리가 매우 불성실하다 ^^

저작자 표시 비영리 변경 금지
신고
크리에이티브 커먼즈 라이선스
Creative Commons License

WRITTEN BY
체리필터
프로그램 그리고 인생...

받은 트랙백이 없고 , 댓글이 없습니다.
secret

보통 android에서 listView를 생성하는 방법은 ArrayAdapter에서 getView를 통해 하나씩 하나씩 각각의 position 정보를 리턴해서 만든다.

만들줄만 알았지, 가져다 쓰는 listView에서 각 개체에 접근하는 법을 몰라 헤메다가 나름 정리해 보았다.


1. Activity가 되었던 Fragment가 되었던 OnScrollListener를 implements 한 후 필요한 method를 구현한다.

2. 필요한 method 중 onScroll과 onScrollStateChanged 에서 필요한 내용에 접근한다.

3. onScroll method에서는 다음과 같은 방법으로 처리


@Override

public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {

for(int i = firstVisibleItem; i<(firstVisibleItem + visibleItemCount); i++) {

}

}


위에서 넘겨주는 파라미터 정보를 사용한다.

view는 전체 listView... firstVisibleItem은 현재 스크롤 상태에서 첫번째 보이는 아이템 키, visibleItemCount는 현재 화면상에 보이는 아이템 개수, totalItemCount는 보이지 않아도 현재 listView에 적채되어 있는 모든 아이템 개수이다.

이 파라미터를 사용하여 필요한만큼 loop를 돌린다.


이때 i의 값이 -1일 경우에는 잘못된 위치 정보이므로 방어 코드를 삽입한다.


if(i == AdapterView.INVALID_POSITION) {

break;

}


4. i 번째 View 객체를 다음과 같은 방법으로 가져온다.


ViewGroup child = (ViewGroup) view.getChildAt(i);


5. 가져온 child 객체에 접근하여 원하는 특정 작업을 한다.


=============================================================================================


그냥 내가 만들어 두고 내가 잊어 버리지 않게 할려고 정리하는 것이므로, 매우 불친절한 설명 --;;

죽어도 못 알아 듣겠다고 생각이 든다면 그때 질문해 주시면 답변 드릴께요 ;;;;


저작자 표시 비영리 변경 금지
신고
크리에이티브 커먼즈 라이선스
Creative Commons License

WRITTEN BY
체리필터
프로그램 그리고 인생...

받은 트랙백이 없고 , 댓글이 없습니다.
secret

일반 EditText에 별도의 submit 버튼을 만들지 말고 Software keyboard에 submit button이 나오도록 하기 위해서는 아래와 같이 작성해야 한다.


<EditText 

..............

       android:imeOptions="actionSearch"

       android:singleLine="true"/>


즉 imeOption에 actionSearch 속성을 주고, 엔터 시 라인이 개행되지 않도록 singleLine을 true로 주어야 한다.

간단하지만, 모르면 헤맬 수 있는 사실. ^^



저작자 표시 비영리 변경 금지
신고
크리에이티브 커먼즈 라이선스
Creative Commons License

WRITTEN BY
체리필터
프로그램 그리고 인생...

받은 트랙백이 없고 , 댓글이 없습니다.
secret

프로젝트 도중 SharedPreference를 사용해서 데이터를 저장하는 부분이 있었다.

그런데 SharedPreference에는 배열 값이 저장이 안되는 듯 해서 정말 그런가 궁금했고, 궁금 증을 해결하기 위해 /data 디렉토리를 뒤져봐야 했다.

하지만 adb나 DDMS를 통한 접근은 Permission denied만 나오고, 접근이 불가한 상태였다.

역시 삽질과 구글링을 통해 해결법을 알아 냈다.


1. 현재 연결되어 있는 장비 알아 낸기


adb devices 명령어를 통해서 연결 된 device 목록을 알아 온다.


2. 해당 장비에 접속하기


adb -s emulator-5554 shell 와 같은 명령어로 해당 장비에 접근한다.


3. 내가 개발 중인 프로젝트 권한으로 변경하기


가령 내가 개발중인 프로젝트의 package 이름이 com.nhnent.project라면, run-as com.nhnent.project 라고 날리면 실행 권한이 app의 권한이 된다. adb로 접속한 유저 권한이 아니라 앱의 권한이므로 app이 접근 가능한 /data 디렉토리 안으로 바로 들어갈 수 있게 된다.


4. shared_prefs 디렉토리 접근하기


보통 SharedPreference 디렉토리는 /data/data/패키지/shared_prefs 이다. 해당 디렉토리로 들어가면, 현재 사용중인 SharedPreference의 xml 파일들이 보인다. 해당 파일을 cat으로 열어봐서 해결하였다.


일단 결론은 SharedPreference에 배열 값은 저장이 안되고 있었다이다.

PUT을 통한 데이터 저장은 xml로 변환이 되지만, 그외 변수에 직접 대입하는 값은 메모리에만 남아 있고, xml로는 변환이 되지 않는다.


오늘 삽질을 통해 얻은 결론!

삽질을 통해야지만, 내 지식이 된다. -.-;;



저작자 표시 비영리 변경 금지
신고
크리에이티브 커먼즈 라이선스
Creative Commons License

WRITTEN BY
체리필터
프로그램 그리고 인생...

받은 트랙백이 없고 , 댓글이 없습니다.
secret

View 화면이 상, 하, 좌, 우에서 날라 들어오거나 다시 들어가는 간단한 애니메이션이 필요해서 검색 중 http://developer.android.com/guide/topics/graphics/view-animation.html 를 발견하게 되었다.

이를 응용해서 현재 개발중인 프로젝트에 사용하였다.


관련 소스는 아래와 같다.

자세한 소스 분석은 언제나 그렇듯이 알아서 ^^


res/anim 아래 animation xml 파일을 만든다. 아래와 같이 from x가 100%에서 시작하면 오른쪽에 숨어 있다가 to x인 0의 위치, 즉 원래 화면 안으로 들어오는 부분이다. 따라서 이름도 slide_in_from_right.xml로 만들었다.

이처럼 100%, -100% 그리고 X, Y만 바꿔가면 상, 하, 좌, 우 애니메이션을 만들 수 있다.


<?xml version="1.0" encoding="utf-8"?>

<translate xmlns:android="http://schemas.android.com/apk/res/android"

    android:duration="@android:integer/config_longAnimTime"

    android:fromXDelta="100%p"

    android:toXDelta="0" />


그리고 나서 위 링크에서 볼 수 있는 것처럼 아래와 같이 사용하면 된다.


Animation inFromRightAni = AnimationUtils.loadAnimation(this, R.anim.slide_in_from_right);

view.startAnimation(inFromRightAni);



저작자 표시 비영리 변경 금지
신고
크리에이티브 커먼즈 라이선스
Creative Commons License

WRITTEN BY
체리필터
프로그램 그리고 인생...

받은 트랙백이 없고 , 댓글 하나 달렸습니다.
  1. 요즘은 XE개발 안하시나요 ㅠ
secret

구글링을 통해서 GPS의 좌표를 통한 거리 구하는 공식을 어렵게 찾아 적용했다.

내용은 아래와 같다.


if(oldCoordinate != null) {

// TODO 거리 누적...

double theta = oldCoordinate.getLongitude() - Double.parseDouble(lp.getLongitude());

double dist = Math.sin(Utility.deg2rad(oldCoordinate.getLatitude())) * Math.sin(Utility.deg2rad(Double.parseDouble(lp.getLatitude()))) +

Math.cos(Utility.deg2rad(oldCoordinate.getLatitude())) * Math.cos(Utility.deg2rad(Double.parseDouble(lp.getLatitude()))) * Math.cos(Utility.deg2rad(theta));

if(dist < -1 || dist > 1) {

logger.d("dist : %s", dist);

}

dist = Math.acos(dist);

dist = Utility.rad2deg(dist);

dist = dist * 60 * 1.1515; // statute miles. 단위는 기본 마일.

dist = dist * 1.609344;

if(dist != Double.NaN) {

totalDist += dist*1000;

}

} else {

oldCoordinate = new Coordinate();

}

if(!"".equals(lp.getAltitude())) oldCoordinate.setAltitude(Double.parseDouble(lp.getAltitude()));

if(!"".equals(lp.getLatitude())) oldCoordinate.setLatitude(Double.parseDouble(lp.getLatitude()));

if(!"".equals(lp.getLongitude())) oldCoordinate.setLongitude(Double.parseDouble(lp.getLongitude()));


하지만 dist 값이 -1보다 작거나 1보다 큰 값이 반환되는 경우 Math.acos에 잘못된 파라미터로 들어가게되고, acos는 NaN을 반환하게 된다.

팀 동료와 고민하면서 구글링하게 된 결과 나온 것은 아래와 같다.


float[] distance = new float[3];

if(oldCoordinate != null) {

Location.distanceBetween(oldCoordinate.getLatitude(), oldCoordinate.longitude,

Double.parseDouble(lp.getLatitude()), Double.parseDouble(lp.getLongitude()), distance);

totalDist += distance[0];

} else {

oldCoordinate = new Coordinate();

}

if(!"".equals(lp.getAltitude())) oldCoordinate.setAltitude(Double.parseDouble(lp.getAltitude()));

if(!"".equals(lp.getLatitude())) oldCoordinate.setLatitude(Double.parseDouble(lp.getLatitude()));

if(!"".equals(lp.getLongitude())) oldCoordinate.setLongitude(Double.parseDouble(lp.getLongitude()));


그냥 Location 안에 static으로 선언 된 distanceBetween 메소드를 이용하면 된다.

알기까지 무지막지한 삽질...

알고나면 허무한 ㅠㅠ

저작자 표시 비영리 변경 금지
신고
크리에이티브 커먼즈 라이선스
Creative Commons License

WRITTEN BY
체리필터
프로그램 그리고 인생...

받은 트랙백이 없고 , 댓글이 없습니다.
secret

eclipse 또는 adt를 통해 android를 개발하다 보면 에뮬레이터가 늦게 떠서 개발에 어려운 경우가 있다.

이럴 경우 다음과 같은 방법으로 에뮬레이터의 속도를 빠르게 할 수 있다.


1. Window > Android SDK Manager를 연다.

2. SDK Manager에서 다음의 package를 설치 한다.



자신의 버전에 맞는 SDK에서 Intel x86 칩셋 이미지를 다운 받는다. 이미 설치 되어 있을 경우에는 설치할 필요가 없다.

가장 하단의 Extras에 있는 Intel x86 Emulator Accelerator (HAXM)도 다운 받는다.

자신의 컴퓨터에 따라 칩셋 이름이 달라질 수 있다.(아마도)


3. Window > Android Virtual Device Manager을 연다.

4. 이미 만들어진 AVD가 있다면 Edit를 누르고, 없다면 New를 눌러 AVD를 설정한다.



위에서 보는 것처럼 CPU/ABI를 Intel Atom(x86)으로 설정한다. 물론 자신의 CPU 칩셋에 따라 옵션이 다를 수 있다. 기본은 ARM으로 설정되어 있다.


이렇게 할 경우 에뮬레이터의 실행 속도가 빨라지게 된다.

다만 내 경우에는 위와 같이 할 경우 아래와 같은 에러 메시지가 떨어졌다.


[2013-05-16 18:08:07 - Emulator] HAX is not working and emulator runs in emulation mode


이와 관련해서 구글링 하니 다음과 같은 내용을 찾을 수 있었다.


http://blog.83rpm.com/archives/1045


HAX를 사용하기 위해 intel에서 프로그램을 다운받아 설치해야 한다는 것이다.

하지만 그래도 에러 발생 ^^; 똑같은 에러 메시지를 검색하니 다음과 같은 내용이 보여진다.


http://answer.beautifultablet.com/android-sdk/hax-is-not-working-and-emulator-runs-in-emulation-mode/


다른 내용은 자세히 보지 않아 모르겠고 "If your computer does not support Intel Virtualization Technology then it will come out this error." 라는 부분을 보면, Intel 가상화 기술을 지원하지 않는다 라는 메시지가 보인다.

즉 지원하지 않는 CPU? 인 것으로 보인다.

이럴 경우에는 그냥 ARM으로 하라는 친절한(?) 설명까지 ^^;;

결국 HAX를 이용한 에뮬레이터 가속은 현재 PC에서는 힘들어 보여서, 기본 셋팅으로 진행할 수 밖에 없었다.




저작자 표시 비영리 변경 금지
신고
크리에이티브 커먼즈 라이선스
Creative Commons License

WRITTEN BY
체리필터
프로그램 그리고 인생...

받은 트랙백이 없고 , 댓글 하나 달렸습니다.
  1. 아.. HAX적용하면 정말정말 빠른데요 ㅜ
secret