모바일 지자기 정보

 

1. 안드로이드 지자기 정보 활용

sensor magnetic

IPS 에서 지구 자기장 강도를 Finger Print 방식으로 실내에서 위치를 찾는다고 하는데 실제 Android 코드로 어떤 값이 어떤식으로 수집되고 사용되는지 알아보고자 하였다.

Android Sensor 에서는 자기장에 대하여 X,Y,Z 방향에 대한 자기장 강도를 리턴하는 것으로 확인하였으며, 각각의 값은 스마트폰의 회전 등 움직임에 크게 영향을 받기 때문에Finger Print 방식으로 지자기 값을 사용하고자 한다면 자기장의 총량 값을 사용하는 것이 맞는 것으로 보이며, 총량값은 간단하게 아래와 같이 계산된다. (그림에서 보면M값)

Math.sqrt( (Xvalue*Xvalue) + (Yvalue*Yvalue) + (Zvalue*Zvalue) );

K-060

fingerprint 방식으로 건물 전체의 지자기 값을 측정하여 그림으로 표현한다면 위와 같이 될 것 같다. 다만, 지자기 값은 같은 위치에서도 높낮이 방향등에 따라 상당히 예민하게 값이 바뀌기 때문에 이를 보정하기 위한 아이디어들이 필요할 것으로 보인다.

물론 지자기 값을 일반적인 건물에서 사용하기 위한 많은 알고리즘들이 수년전부터 사용화 되어 있다. 다만, 이러한 지자기 데이터는 철골 구조물이 고정적이라는 가정하에 사용되고 있어, 공장과 같이 철골 구조물이 이동하는 경우에는 정보 왜곡이 발생할 수 있어 애로 사항이 발생한다.

이러한 문제를 해결하기 위하여 앞으로 더 자료를 찾아보고자 하는 내용은 아래와 같은 철골 구조물에 의한 자기장 왜곡을 시뮬레이션 할 수 있는가 여부이다.

Magnetic%20Field%20Distortion-web

[참조 논문] Numerical analysis of the magnetic field for arbitrary magnetic susceptibility distributions in 3D  (35.9 달러 -_- ;; 유료..)

This paper demonstrates a method to calculate the magnetic field distribution in and around a 3D object when it is magnetized by a strong homogeneous magnetic field. The numerical technique is based on the explicit finite difference method. The calculation method is validated against analytical solutions for a sphere. As an application cylinders with different ratios of lengths and diameter are studied.

http://www.sciencedirect.com/science/article/pii/0730725X94923574

 

[예제]

public class TestOrientationActivity extends Activity implements SensorEventListener
{
// 센서 관련 객체
SensorManager m_sensor_manager;
Sensor m_acc_sensor, m_mag_sensor;

// 데이터를 저장할 변수들
float[] m_acc_data = null, m_mag_data = null;
float[] m_rotation = new float[9];
float[] m_result_data = new float[3];

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

// 시스템서비스로부터 SensorManager 객체를 얻는다.
m_sensor_manager = (SensorManager)getSystemService(SENSOR_SERVICE);

// SensorManager 를 이용해서 가속센서와 자기장 센서 객체를 얻는다.
m_acc_sensor = m_sensor_manager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
m_mag_sensor = m_sensor_manager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
}

// 해당 액티비티가 포커스를 얻으면 가속 데이터와 자기장 데이터를 얻을 수 있도록
// 리스너를 등록한다.
protected void onResume() {
super.onResume();
m_check_count = 0;

// 센서 값을 이 컨텍스트에서 받아볼 수 있도록 리스너를 등록한다.
m_sensor_manager.registerListener(this, m_acc_sensor, SensorManager.SENSOR_DELAY_UI);
m_sensor_manager.registerListener(this, m_mag_sensor, SensorManager.SENSOR_DELAY_UI);
}

// 측정한 값을 전달해주는 메소드.
public void onSensorChanged(SensorEvent event)
{
if(event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
m_acc_data = event.values.clone();
} else if(event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {
m_mag_data = event.values.clone();
}

// 데이터가 존재하는 경우
if(m_acc_data != null && m_mag_data != null) {
// 가속 데이터와 자기장 데이터로 회전 매트릭스를 얻는다.
SensorManager.getRotationMatrix(m_rotation, null, m_acc_data, m_mag_data);
// 회전 매트릭스로 방향 데이터를 얻는다.
SensorManager.getOrientation(m_rotation, m_result_data);

(float)Math.toDegrees(m_result_data[0]);  //방위
(float)Math.toDegrees(m_result_data[1]);  //경사
(float)Math.toDegrees(m_result_data[2]);  //회전

m_mag_data[0] ; // 자기장 X 방향
m_mag_data[1] ; // 자기장 Y 방향
m_mag_data[2] ; // 자기장 Z 방향

//자기장 총량의 값은 0 ~ 200 , 실질적으로 지구에서는 20 ~ 70
double teslaXYZ = Math.sqrt((m_mag_data[0] *m_mag_data[0] )+(m_mag_data[1] *m_mag_data[1] )+(m_mag_data[2] *m_mag_data[2] ));

…. (중략)

 

[모바일WEB-APP] PhoneGap – SenchaTouch 연동 개발

4. Phone Gap – JqueryMobile FrameWork 연동

(1) 구성

– Sencha Touch 는 js 로 모든 화면이 구성되기 때문에 Client 에도 화면 js 파일이 포함되어야 한다.

모든 서버 파일을 클라이언트로 옮길 수는없기 때문에 Sencha cmd 이용해서 파일을 최적화 하는 과정을

거쳐야 한다.

가) Sencha Build

– 프로젝트 폴더로 이동

– 도스콘솔에서 명령어 실행 : sencha app build package

– build/package/ 폴더의 내용을 Client 에 복사

나) Cleint

– (가) 에서 빌드한 내용을 asset 에 넣고 빌드한다.

첨부파일 : Client 에 포함해야될 Sencha 자원 / Sencha WebSErver 자원

[모바일WEB-APP] PhoneGap – JqueryMobile 연동 개발

4. Phone Gap – JqueryMobile FrameWork 연동

(1) 구성

– Jquery Mobile 로 웹 서버를 개발하였다면 Phonegap 과 연동하여 Hybrid App 으로

만들기 위해서는 몇 가지 과정이 필요하다.

-> 클라이언트는 : Index 파일과 Framework 소스를 Packge 에 포함한다.

Index 파일의 설정을 통해 외부 호스트 접속을 허용한다.

-> 서버는 : 그대로 두면 된다.

가) Client : 로딜 속도를 빠르게 하기위해 무거운 Framework 을 App 에 포함시킨다.

○시작 HTML 세팅

참조 : http://jquerymobile.com/demos/1.2.0/#/demos/1.2.0/docs/pages/phonegap.html

참조 : http://jquerymobile.com/demos/1.2.0/docs/api/globalconfig.html

[예제] JQuery-Mobile 이 외부 동신을 할 수 있도록 세팅을 해주어야 한다.

<script type=”text/javascript”>
$(document).bind(“mobileinit”, function() {
$(“#home”).live(“pagebeforeshow”, function(event, ui) {
btnShowAndHide();
});
//jquery 크로스 도메인 접속 허용
$.support.cors = true;
//Jquery-mobile 크로스 도메인 접속 허용
$.mobile.allowCrossDomainPages = true;
$.mobile.pushStateEnabled = false;
});
</script>

[예제] JQuery-Mobile Index 페이지에서 사용하는 상대 경로는 모두 절대 경로로 바꿔 주어야 한다.

<div data-role=”content”>
<div class=”ui-grid-a”>
<div class=”ui-block-a”>
<a id=”btnLogin”
href=”http://192.168.101.56:8080/jquery-mobile-1.3.0/demo/loginform.html
data-role=”button”
data-icon=”gear”>로그인</a>
<a id=”btnLogout”
href=”javascript:logout();”
data-role=”button”
data-icon=”gear”>로그아웃</a>
</div>
<div class=”ui-block-b”>
<a id=”btnPhoneList”
href=”#”
data-icon=”grid”
data-role=”button”>상품목록</a>
</div>
</div>
</div>

○ Framework 파일

– 서버에서 내려받을 경우 무거운 Frame work 파일을 로컬에 저장하는 것에 큰 목적이 있다.

jquery.mobile-1.3.0.min.css

jquery.mobile-1.3.0.min.js

jquery-1.8.2.min.js

image 폴더

나) 웹서버 :

– 나머지 웹 파일들 처리한다. (Index 파일을 제외하고는 기존과 완전 동일)

[모바일WEB-APP] PhoneGap – 설치하기

4. Phone Gap – 설치

(1) 설치 및 세팅

가) 설치

– http//phonegap.com 에서 최신 jar 파일을 다운로드 받는다.

– 자신이 사용하고자 하는 OS 에 맞는 폴드를 찾아서 들어간다. (여기서는 Android )

– Android 폴더에는 jar 파일, js 파일, xml 폴더가 있따.

– eclipse 에서 Android 프로젝트 하나를 만든다.

– eclipse 에서 자신이 만든 프로젝트에 다음과 같이 자원을 import 한다.

-> jar -> libs 폴더

-> js -> assete/www/

-> xml -> res/

나) 세팅

참고 : http://docs.phonegap.com/en/1.8.1/guide_getting-started_android_index.md.html

Android-Manifest.xml 권한 부여 필요

<uses-sdk
android:minSdkVersion=”10″
android:targetSdkVersion=”10″ />
<supports-screens
android:largeScreens=”true”
android:normalScreens=”true”
android:smallScreens=”true”
android:resizeable=”true”
android:anyDensity=”true” />
<uses-permission android:name=”android.permission.VIBRATE” />
<uses-permission android:name=”android.permission.ACCESS_COARSE_LOCATION” />
<uses-permission android:name=”android.permission.ACCESS_FINE_LOCATION” />
<uses-permission android:name=”android.permission.ACCESS_LOCATION_EXTRA_COMMANDS” />
<uses-permission android:name=”android.permission.READ_PHONE_STATE” />
<uses-permission android:name=”android.permission.INTERNET” />
<uses-permission android:name=”android.permission.RECEIVE_SMS” />
<uses-permission android:name=”android.permission.RECORD_AUDIO” />
<uses-permission android:name=”android.permission.MODIFY_AUDIO_SETTINGS” />
<uses-permission android:name=”android.permission.READ_CONTACTS” />
<uses-permission android:name=”android.permission.WRITE_CONTACTS” />
<uses-permission android:name=”android.permission.WRITE_EXTERNAL_STORAGE” />
<uses-permission android:name=”android.permission.ACCESS_NETWORK_STATE” />
<uses-permission android:name=”android.permission.GET_ACCOUNTS” />
<uses-permission android:name=”android.permission.BROADCAST_STICKY” />

(2) Hello 찍어 보기

가) DroidGap 을 상속 받는 클래스 생성

– 인터넷 주소를 로딩해주면 끝 : super.loadUrl(“file:///android_asset/www/index.html“);

package hybrid.app;

import org.apache.cordova.DroidGap;

import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;

public class MainActivity extends DroidGap {

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
super.loadUrl(“file:///android_asset/www/index.html“);
}
}

안드로이드 기반 OPENCV – Core – Histogram

3-6. CORE – Histogram

이미지에 있어서 히스토그램은 무엇인가? 보통 히스토그램을 보면 X,Y 축 형태의 막대 그래프 형태를 가지고 있음을 알 수 있다.

이미지에서 히스토그램 그래프의 X 축은 Depth 즉 CV_8UC1 이라고 하면 0 ~ 255이 될 것이고, Y 축은 각 Depth 의 빈도가 될 것이다.

만약 CV_8UC4 라고 하면? 히스토그램 그래프가 4개가 나올 것이고 각각의 그래프는 위의 싱글채널 그래프와 동일한 형태로 표현될 것이다.

그럼 Android 기반의 OpenCV 에서 Histogram 을 다루는 방법을 알아보자. 아래는 OPENCV 샘플에 포함된 소스코드로

RED , Green, Blue, 색상, 명도 별 히스토그램을 화면에 출력하는 예제이다.

(1) 히스토그램 이미지를 담기 위한 메트릭스를 생성한다.

mRgba = inputFrame.rgba();

if ((mSizeRgba == null) || (mRgba.cols() != mSizeRgba.width) || (mRgba.height() != mSizeRgba.height))
{
//히스토그램 출력 이미지 편집을 위한 메트릭스 생성
CreateAuxiliaryMats();
}

//히스토그램 막대의 폭을 정의한다.
int thikness = (int) (mSizeRgba.width / (mHistSizeNum + 10) / 5);

if(thikness > 5)
{
thikness = 5;
}

int offset = (int) ((mSizeRgba.width – (5*mHistSizeNum + 4*10)*thikness)/2);

(2) 카메라 이미지의 정보로 RGB 에 해당하는 히스토그램을 생성한다.
// RED 에 대한 히스토그랩, GREEN에 대한 히스토그램, BLUE 에 대한 히스토그램을 그린다.
for(int c=0; c<3; c++)
{

//mRgba : 원본 이미지, mChannels : RGB 중 원하는 채널 선택 , 출력값 : mMat0, mHist, mHistSize, mRanges
Imgproc.calcHist(Arrays.asList(mRgba), mChannels[c], mMat0, mHist, mHistSize, mRanges);
Core.normalize(mHist, mHist, mSizeRgba.height/2, 0, Core.NORM_INF);
mHist.get(0, 0, mBuff);
for(int h=0; h<mHistSizeNum; h++) {
mP1.x = mP2.x = offset + (c * (mHistSizeNum + 10) + h) * thikness;
mP1.y = mSizeRgba.height-1;
mP2.y = mP1.y – 2 – (int)mBuff[h];
Core.line(mRgba, mP1, mP2, mColorsRGB[c], thikness);
}
}

// RGB를 HSV [색상(H), 채도(S), 명도(V)] 로 변경하고 명도값을 추출하여 히스토그램으로 표현한다.
Imgproc.cvtColor(mRgba, mIntermediateMat, Imgproc.COLOR_RGB2HSV_FULL);
// Value
Imgproc.calcHist(Arrays.asList(mIntermediateMat), mChannels[2], mMat0, mHist, mHistSize, mRanges);
Core.normalize(mHist, mHist, mSizeRgba.height/2, 0, Core.NORM_INF);
mHist.get(0, 0, mBuff);
for(int h=0; h<mHistSizeNum; h++)
{
mP1.x = mP2.x = offset + (3 * (mHistSizeNum + 10) + h) * thikness;
mP1.y = mSizeRgba.height-1;
mP2.y = mP1.y – 2 – (int)mBuff[h];
Core.line(mRgba, mP1, mP2, mWhilte, thikness);
}

// RGB를 HSV [색상(H), 채도(S), 명도(V)] 로 변경하고 색상 값을 추출하여 표현한다.
Imgproc.calcHist(Arrays.asList(mIntermediateMat), mChannels[0], mMat0, mHist, mHistSize, mRanges);
Core.normalize(mHist, mHist, mSizeRgba.height/2, 0, Core.NORM_INF);
mHist.get(0, 0, mBuff);
for(int h=0; h<mHistSizeNum; h++)
{
mP1.x = mP2.x = offset + (4 * (mHistSizeNum + 10) + h) * thikness;
mP1.y = mSizeRgba.height-1;
mP2.y = mP1.y – 2 – (int)mBuff[h];
Core.line(mRgba, mP1, mP2, mColorsHue[h], thikness);
}

Android Basic

1.. Android Application 상태 유지 기법

아래는 Activity 의 life Cycle 이다. Android 는 Process 의 관리를 Android Frame Work이 수행하기 때문에 개별Application 에서는 메모리 부족 등에 의한 급작스러운 시스템의 종료를 대비할 필요가 있다.

Activity 의 생성을 위한 자원의 Loading 및 Setting 을onCreate()에서 App 이 종료시에 필요한process 처리를 onPause() 에서 한다는 것은 틀린 이야기는 아니지만 onCreate와 onPause 에 코드가 집주되는 것을 막고 확실한 Application의 상태유지를 위해서는 아래의 두 가지 상태를 이용할 필요가 있다.

onsaveInstanceState : Activity가 종료되는 시점에 불려진다. 순서로는 onPause() 다음에 실행

onRestoreInstanceState : Activity 가 다시 화면으로 올라오는 경우 불려진다. onCreate 다음 실행

위의 두 상태에서는 Instance 의 저장을 위해 Parcelable 을 상속받는 Bundle 객체를 이용하며

이에 대한 설명은 뒤쪽에서 하도록 한다.

  1. Fragment

Android 3.0 이하에서는 화면은 즉 Activity 이고 모든 logic 처리를 Activity 안에서 수행을 하였다면 Android 3.0 이상의 버전에서는 Activity 안에 복수개의 별도의 생명 주기를 갖는Fragment 를

포함하여 개발하도록 UI 개발 사상이 바뀌었다. 기본적인 사용방법은 아래와 같다.

– Fragment를 상속받는 클래스를 생성한다.

– 생성한 Fragment 를 layout 혹은 java 코드를 통해 Activity 에 등록한다.

(1) Activity 에 Fragment 등록하기

  1. A) Fragment Class 정의

Fragment 는 Activity 와 마찬가지로 일반 Fragment , ListFragment 등 다양한 종류의 Fragment 가 존재하며, 기본적인 Fragment 의 경우 아래와 같은 callback Class 들을 갖는다.

@Override

public void onAttach(Activity activity) {

super.onAttach(activity); }

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState); }

@Override

public void onSaveInstanceState(Bundle outState) {

super.onSaveInstanceState(outState);

}

@Override

public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)

{

return tv;

}

@Override

public void onActivityCreated(Bundle savedInstanceState) {

super.onActivityCreated(savedInstanceState);

}

@Override

public void onStart() {

super.onStart();

}

@Override

public void onResume() {

super.onResume();

}

@Override

public void onPause() {

super.onPause();

}

@Override

public void onStop() {

super.onStop();

}

@Override

public void onDestroyView() {

super.onDestroyView();

}

@Override

public void onDestroy() {

super.onDestroy();

}

@Override

public void onDetach() {

super.onDetach();

}

  1. B) layout XML 에 등록하여 사용하는 방법

<fragment class=”edu.jaen.android.fragment.layout.FragmentLayout$TitlesFragment”

android:id=”@+id/titles”

android:layout_width=”match_parent”

android:layout_height=”match_parent” />

  1. B) Java 에서 동적으로 포함시키는 방법

DetailsFragment details = new DetailsFragment();

details.setArguments(getIntent().getExtras());

getFragmentManager().beginTransaction().add(android.R.id.content,

details).addToBackStack(null).commit();

@Sample@ : 1. Fragment 폴더 참조

  1. Action Bar

API11 부터 기존의 title bar에 메뉴, tab 등의 기능을 추가하여 강력한 기능을 포함한 Action Bar Class 가 제공된다 .기본적인 사용방법은 아래와 같다.

– menu 형태를 layout 혹은 java 코드로 생성

– activity 의 onCreateOptionsMenu, onOptionsItemSelected 에서 생성한 메뉴 혹은 TAB을 Activity 에 추가한다.

(1) action bar 에 메뉴 등록

  1. A) xml 에 메뉴를 정의

Menu -> item -> menu(sub) -> item(sub)과 같은 형식으로 xml 에 정의할 수 있다.

<menu xmlns:android=“http://schemas.android.com/apk/res/android”

android:actionViewClass=“android.widget.HorizontalScrollView”>

<item android:id=“@+id/action_sort”

android:icon=“@android:drawable/ic_menu_sort_by_size”

android:title=“@string/action_bar_sort”

android:showAsAction=“always”>

<menu>

<item android:id=“@+id/action_sort_size”

android:icon=“@android:drawable/ic_menu_sort_by_size”

android:title=“@string/action_bar_sort_size”

android:onClick=“onSort”/>

<item android:id=“@+id/action_sort_alpha”

android:icon=“@android:drawable/ic_menu_sort_alphabetically”

android:title=“@string/action_bar_sort_alpha”

android:onClick=“onSort”/>

</menu>

</item>

</menu>

  1. b) java 에서 동적으로 추가

menu.add(“Normal item1”);

menu.add(“Normal item2”);

menu.add(“Normal item3”);

MenuItem actionItem = menu.add(“Action Button”);

actionItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);

actionItem.setIcon(android.R.drawable.ic_menu_share);

 

(2) Activity 에서의 처리

  1. A) Menu Event 처리

onCreateoptionMenu 와 onOptionsItemSelected Event API11 이전 버전과 동일하지만

actionItem.setShowAsAction메서드를 실행함으로써 ActionBar 로 메뉴를 올려 보낼 수 있다.

@Override

public boolean onCreateOptionsMenu(Menu menu) {

// java에서 동적으로 등록

menu.add(“Normal item3”);

MenuItem actionItem = menu.add(“Action Button”);

actionItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);

actionItem.setIcon(android.R.drawable.ic_menu_share);

// xml layout inflating

MenuInflater inflater = getMenuInflater();

inflater.inflate(R.menu.actions, menu);

return true;

}

@Override

public booleanonOptionsItemSelected(MenuItem item) {

 

// 선택된 메뉴에 대한 기능 처리

return true;

}

 

  1. B) Tab 추가

ActionBar 의 addTab 메서드를 이용하여 동적으로 tab을 추가 할 수 있으며 Fragment와의 연동을 통해 API 11 이전 TabActivity 기능을 대체 할 수 있다.

final ActionBar bar = getActionBar();

final int tabCount = bar.getTabCount();

final String text = “Tab ” + tabCount;

bar.addTab(bar.newTab().setText(text).setTabListener(new TabListener(new TabContentFragment(text))));

@Sample@ : ActionBar 폴더 참조

  1. Loader

읽는 즉시즉시 출력가능하도록 간단한 메서드들을 지원한다. Thread 와 유사한 개념으로 안드로이드에서 지원하는 Loding을 위한 클래스

(1) LoadManager 등을 Implement

– implements OnQueryTextListener, LoaderManager.LoaderCallbacks

(2) init method 호출

– getLoaderManager().initLoader(id, Bundle arg, callback);

(3) call back method 정의

A)onCreateLoader

public Loader<Cursor> onCreateLoader(int id, Bundle args) {

Uri baseUri;

if (mCurFilter != null) {

baseUri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI,

Uri.encode(mCurFilter));

} else {

baseUri = Contacts.CONTENT_URI;

}

String select = “((” + Contacts.DISPLAY_NAME + ” NOTNULL) AND (”

+ Contacts.HAS_PHONE_NUMBER + “=1) AND (”

+ Contacts.DISPLAY_NAME + ” != ” ))”;

return newCursorLoader(getActivity(), baseUri,

CONTACTS_SUMMARY_PROJECTION, select, null,

Contacts.DISPLAY_NAME + ” COLLATE LOCALIZED ASC”);

}

B)onLoadFinished

public void onLoadFinished(Loader<Cursor> loader, Cursor data) {

 

mAdapter.swapCursor(data);

 

if (isResumed()) {

setListShown(true);

} else {

setListShownNoAnimation(true);

}

}

C)onLoadReset

public voidonLoaderReset(Loader<Cursor> loader) {

mAdapter.swapCursor(null);

}

@Sample@ : 8.LoaderCursor

  1. Intent

Intent 는 Android Framework 과 통신하기 위한 통신객체로 Android 에서 Intent로 다른 Activity를 호출하는 과정은 아래와 같이 일어난다.

(Activity -> Intent 호출 ->Android Frame Work -> Target Activity)

Android 가 Target Action을 호출하는 방법은 명시적 호출방법과 암묵적 호출방식이 있다.

명시적 호출방법은 package 명을 직접 지정하여 호출하는 방식이고, 암묵적 호출방식은 category, action, data 의 조건을 가지고 broad casting 방식으로 호출하는 것이다.

(1) 명시적 호출방식

ComponentName n=new ComponentName(“edu.diana.audio”,”edu.diana.audio.AudioAct”);

i.setComponent(n);

startActivity(i);-

(2) 암묵적 호출방식

i.addCategory(Intent.CATEGORY_DEFAULT);

i.setAction(Intent.ACTION_VIEW);

i.setData(Uri.parse(“poscocctvmobapp:”));

startActivity(i);

(3) Android-manifest 설정

<intent-filter>

<action android:name=“android.intent.action.VIEW”/>

<category android:name=“android.intent.category.DEFAULT”/>

<category android:name=“android.intent.category.BROWSABLE”/>

<data android:scheme=“poscocctvmobapp” />

</intent-filter>

(4) Intent 호출시 Flag 를 통한 TASK 관리

Task 는 android process 들의 실행 순서를 관리하는 것을 말한다. 쉬운 예로 H/W back 버튼을 누를 경우 이전에 사용했던 App 들을 화면상단으로 호출하는 것과 같은 현상을 볼 수 있다.

이러한 task 는 Android ActivityManager 에서 수행하고 있으며, Task 는 Intent 호출 시 Flag 값과

Android-Manifest 에서LuchMode 를 정의함으로써 컨트롤 할 수 있다 .

  1. A) flag

flag 를 통해서 task 관리 가능, bit연산으로 복수의 flag 세팅 가능

-intent.FLAG_ACTIVITY_RECORDER_TO_FRONT : 같은 놈은 위로 올린다.

-intent.FLAG_ACTIVITY_CLEART_TOP : 호출 대상 위에 있는 task 삭제 (호출 대상까지 삭제하고

대상을 다시 만든다)

– intent.FLAG_ACTIVITY_CLEART_TOP|intent.FLAG_ACTIVBITY_SINGLE_TOP : (호출 대상을 삭제하지

않고 위를 전체 삭제)

-intent.FLAG_ACTIVITY_NEW_TASK : 새로운 테스크 생성, service 및broadcast_receiver 에서

Activity를 실행하는 경우 사용

  1. B) LunchMode      

-standard : 동일한 프로세스가 중복하여 쌓일수 있다.

– singleTop : 동일한 프로세스를 연속으로 두번 누르는 경우 동일한 것은 스택에 쌓지 않음

– singleTask : 호출된 Activity 를 시작점으로 새로운 task생성

– singleinstance : 독립적으로 하나의 activity 만 존재함 (ex : 런쳐)

Cf) lunchMode – task명 : 테스크 명을 지정하지 않으면(Activity-Task afifinity) 기본적으로 Package 명을 따라간다. task 명이 같은 경우

  1. 자원공유

(1) 파일 자체를 공유하는 방법

– 기본적으로 DB, FILE 등은 Linux 권한 정책에 따라 다른 어플리케이션에서 읽을 수 없다 .    

– 기본적으로 Cache, File, DB 는 자신의 Context 영역에 정의된다.

– 다른 Context 의 자료를 가지고 싶다면. createPackageContext를 사용해서 다른 컨택스트를

생성해서 데이터를 접근할 수 있다 (단, 권한은 있어야 한다. )

– 단, 파일만들기 단계에서(createPackageContext) 권한을 주면 다른 어플리케이션에서 직접

Access 가 가능하다.

– 특정한 프로제트를 지정하여 서로 접근가능하도록 하고 싶다…-> userID 를 공유해야 한다.

android.os.Process.myUid(), Android_manifiest : shared user id 를 공유하도록 하면 됨.

(2) jar 를 통한 외부 라이브러리 공유

– 안드로이드는 프레임웍이기 때문에 정해진 폴더만 빌드시에 묶는다.

– 확인 방법은 폴더에 A 모양이 있는지를 확인한다.

– 보통의 경우 libs 아래 jar 파일을 포함시키고 path 를 걸어준다.

(3) apk 파일 공유

– 라이브러리 세팅 : 프로젝트 선택 – propoerties – android – isLib 체크

– 라이브러리 사용 : 프로젝트 선택 – propoerties – android – add

(4) DB 공유 – Content-Provider 사용

DB자체를 공유하는 것이 아닌 contentProvider를 사용하여 데이터를 공유할 수 있다.

Android에서 제공하는 주소록과 같은 것들이 이러한 형태로 사용자에게 데이터를 제공하고

있다. Content Provider 는 아래와 같은 구조로 동작한다.

Activity ( contentResolver사용)

->URI(target지정) ,update(),delete(),query(),insert() 메서드 사용

-> ContentProvider 는 해당 메서드에 대한 처리

.

– Content-Provider의 이름은 고유해야 한다.

-SQLLiteOpenHelper의 경우 Android Frame work 에서 관리하지 않는 클래스이다.

– 그렇기 때문에content-provider 를 상속받아 구현을 하면 Frame 을 통해 접근이 가능하다.

-content-provider 의 미구현 메서드는 insert, update, delete-query

-content-provider를 호출하기 위한 클래스는 contentResolver 이다.

-> context.getContentResolver 를 통해서 구한다.

-> insert(URI, ), update(URI, ), delete, quert 메서드 지원…

  1. android 에서 기본적으로 제공하는 URI 는 android.provider 에서 찾는다.

– 타겟 Content-Provider 는 Android-Manifest 등록 시 authority 를 등록해야 한다.

-> URI : content://<정의한authority>/path(table명)

<provider android:name=“MyContentProvider” android:authorities=“com.ict”

android:exported=“true”></provider>

-Content-Provider 생성후 manifiest 의 export 속성을 true 로 정의해 주어야 한다.

-Provider 는 각 Method 에서 path 명을 이용하여 서비스를 분기처리 할 수 있다.

@SAMPLE@ : Content-Provider 폴더 참조

  1. Broadcast Receiver

BroadcastReceiver는 베터리 상태, 충전, wifi접속, 문자 등 각종 Broadcast Event 에 대응하기

위하여 사용한다. Broadcast Receiver를 구성하는 방법은 아래와 같다.

  1.   A) Receiver 생성

– Receiver 측의 Android-Manifest 에 등록하거나 Java 상에서 등록한다.

– BroadcastReceiver 를 상속받아 onReceive(Context context, Intent intent)

메서드를 오버라이딩 한다.

  1.   B) Broadcast 호출

– Android-Manifest 에 Braodcast Messgage 전송 퍼미션을 추가한다 .

<uses-permission android:name=“android.permission.BROADCAST_STICKY”>

– context method 인 sendOrderedBroadcast,sendStickyBroadcast등을 사용하여 간단히

호출 가능하다.

(1) Broadcast Receiver생성 방법

  1. A) android-manifest.xml 에 등록

아래와 같이Android-Manifest에 등록하는 경우 Android Framework에서 발생하는 모든

메시지에 대해서 반응한다.

<receiver

android:name=“edu.jaen.android.receiver.OneShotAlarm1”

android:process=“:remote”>

<intent-filter android:priority=“1”>

<action android:name=“com.jaen.REGISTER” />

</intent-filter>

</receiver>

  1. B) Activity 에서 Regist

Java 에서 내부적으로 등록하는 경우 Android Framework이 알고 있지 못하기 때문에 아래와

같이 BraodcastReceiver 를 등록하기 전에는 동작하지 않는다. (로컬하게 사용하고 싶을 경우)

Context c=getApplicationContext();

IntentFilter f=new IntentFilter(“com.jaen.REGISTER”); //action

f.setPriority(500); // 우선순위 부여

c.registerReceiver(a2, f); //receiver 등록

  1. C) BroadCastting 요청 방법

사용자가 Braodcast 메시지를 호출하는 경우 크게 3가지 방법으로 호출이 가능하다.

– sendBroadCast() : 동일한 action 을 갖고 있는 Broadcast 가 여러 개 있을 경우 Random

– sendOrderedBroadcast(): 여러 개가 있을 경우 우선순위에 의해 순차적으로 실행

– sendStickyBroadcast() : 호출 시점에 Receiver가 없어도 신규 등록을 기다리고 있다가 실행

  1. D) Intent Flag 를 이용한 Broadcast 제어

intent 에서 호출 시 flag 를 사용하여 제어를 할 수 있다.

-FLAG_RECEIVER_REGISTED_ONLY : Android_Manifiest 에 정의되어 있는 receiver는 무시한다.

-FLAG_RECEIVER_REPLACE_PENDING : 동일한 intent 가 연속적으로 전달될 경우 처음과

마지막 것만 인식함

-FLAG_INCLUDE_STOPPED_PACKAGE : (Package가 Stopped)정지되어 있는 PROCESS 는

실행되지 않는 경우가 있다. 이런 경우 사용한다.

 

@SAMPLE@ : BroadCastReceiver 폴더 참조

  1. Widget – Service

Widget은 기본적으로 HomeApplication 과의 통신을 통해서 동작한다. Android 에서는 이러한 복잡한 통신 과정을 간단하게 처리할 수 있도록appWidgetProvider 를 제공한다.,

아래는 기본적인 Widget 의 동작 과정이다.

Service -> RemoteView -> AppWidgetProvider-> Home Program

(1) Android-Manuifest.xml 정의

아래와 같은 Manifest 에 정의를 하게 되면 Android Home 에서 Widget 설치 메뉴에 등록이 됨

Meta-data 에 보면 Home에서 Widget 의 UI 를 정의하는 xml 이 정의 되는 것을 볼 수 있다.

<receiver

android:enabled=“true”

android:label=스마일! 이벤트

android:name=“edu.jaen.android.wiget.event.WidgetReceiver”>

<intent-filter >

<action android:name=“android.appwidget.action.APPWIDGET_UPDATE”/>

</intent-filter>

<meta-data

android:name=“android.appwidget.provider”

android:resource=“@xml/smileinfo”/>

</receiver>

(2) [resource].xml 정의

Widget 의 크기Resizable 여부를 정의하고 Widget에서 사용할layout 등을 정의할 수 있다.

<?xml version=“1.0”encoding=“utf-8”?>

<appwidget-provider xmlns:android=“http://schemas.android.com/apk/res/android”

android:minWidth=“40dip”

android:minHeight=“110dip”

android:resizeMode=“vertical|horizontal”

android:updatePeriodMillis=“0”

android:initialLayout=“@layout/smile”>

</appwidget-provider>

(3) layout 정의

Layout 은 기존에Activity 나 Fragment 의 Layout 을 정의하는 것과 크게 다르지 않다.

<?xml version=“1.0”encoding=“utf-8”?>

<RelativeLayout xmlns:android=“http://schemas.android.com/apk/res/android”

android:id=“@+id/mainlayout”

android:layout_width=“wrap_content”

android:layout_height=“fill_parent”

android:orientation=“vertical”>

<ImageView

android:id=“@+id/smileImage”

android:layout_width=“wrap_content”

android:layout_height=“wrap_content”

android:src=“@drawable/smile”/>

<TextView

android:id=“@+id/smileText”

android:layout_width=“fill_parent”

android:layout_height=“wrap_content”

android:layout_alignRight=“@+id/smileImage”

android:layout_below=“@id/smileImage”

android:gravity=“center”

      android:text=“Smile”

android:textColor=“#ffff00”

android:textSize=“15sp”/>

</RelativeLayout>

(4)AppWidgetProvider 상속 클래스생성

3번 까지의 과정을 통해서 Widget을 Home 화면에 출력하였다면 이제 유동적으로 이벤트 처리나 데이터 갱신을 위하여 AppWidgetProvider 와 Service 를 이용하여야 한다.

AppWidgetProvider 는Home 과 Service 사이의 통신을 도와주며 통신을 위해서는 RemoteView객체를 생성하여 교환한다.

public class WidgetReceiver extends AppWidgetProvider {

public void onUpdate(Context context, AppWidgetManager appWidgetManager,

int[] appWidgetIds)

{

}

static void appWidgetUpdate(Context context, int appWidgetId, int imgId,

CharSequence text) {

}

@Override

public void onEnabled(Context context) {

super.onEnabled(context);

}

@Override

public void onDisabled(Context context) {

super.onDisabled(context);

}

@Override

public void onDeleted(Context context, int[] appWidgetIds) {

super.onDeleted(context, appWidgetIds);

}

}

(5)RemoteView 생성

  1. A) RemoteView를 생성

RemoteViews views = new RemoteViews(context.getPackageName(),R.layout.smile);

views.setImageViewResource(R.id.smileImage, imgId);

views.setTextViewText(R.id.smileText, text);

  1. B) AppWidgetManger 생성

AppWidgetManager wm = AppWidgetManager.getInstance(context);

C)Service 실행할 Intent 생성

Intent intentImage = new Intent(context, ImageService.class);

intentImage.putExtra(“wId”, appWidgetId);

D)다른 프로그램이Intent를 실행할 수 있도록 PendinIntent 생성

PendingIntent pendingImage = PendingIntent.getService(context,appWidgetId, intentImage, 0);

E)RemoteView onClickPendingIntent Listener 추가

views.setOnClickPendingIntent(R.id.smileImage, pendingImage);

F)AppWidgetManager의 updateAppWidget() 메서드를 통해 HOST로 View Update

wm.updateAppWidget(appWidgetId, views);

@Sample@ : 6. AppWigetEvent 폴더를 참조한다.

  1. 상태유지 기법과 Parcelable

상태 유지 기법으로는 Preference ,Data Base, File , network 를 사용하는 방법과 Android 의 System Memory 를 사용하는 기법이 있다.

또, Activity 에서 상태를 유지하기 위해 onSaveInstanceState, onRestoreInstanceState 상태를 이용할 수 있다.

여기서는 Android의System Memory를 이용하여 데이터를 복구하는 방법에 대해서 이야기 하고자 한다. 기본적으로 Activity와 Android FrameWork은 기본적으로 통신을 기반으로 하고 있기 때문에 Seralized 된 객체만이 전송가능하며 특별히 Android 에서는 Parcelable 이라는 개념을 사용하고 있다.

(1) Parcelable 이란?

– 기본적으로 안드로이드는 Activity 간에 Intent 통신을 사용한다.

– 통신에서 객체를 전송하기 위해서는 Serialized 가 되어 있어야 한다.

– Serialized의 단점은 속도가 느리다는 것인데 이것의 단점을 보완한 것이 Parcelable 이다.

-Android 에서는 이러한 Parcelabel 의 개념을 사용하여 Bundle 이라는 객체를 사용하고 있다

(2) onCreate, onSaveInstance 에서의 Bundle 타입 파라메터

  1. A) save call back 에서 Bundle 에 Parcelable 객체를 저장할 수 있다.

  저장된 객체는 Android FrameWork 의 System Memory 공간에 저장된다.

@Override

protected void onSaveInstanceState(Bundle outState) {

// TODO Auto-generated method stub

super.onSaveInstanceState(outState);

bundle.putParcelableArrayList(“list”, pList);

}.

  1. B) Bundle 객체에서 Parcelable 객체를 꺼내어 데이터를 복구한다.

  저장된 객체는 Android FrameWork 의 System Memory 공간에 저장된다.

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

pList = bundle.getParcelableArrayList(“list”);

}

(2) 기존에 Android 에 정의된 Pacelable 객체를 이용

– Bundle 은 기본적으로 Parcelable 객체이기 때문에 그냥 사용하면 된다…

ArrayList<HashMap<String, String>> selectedChildList = null;

ArrayList<Bundle> currentList = null;

Bundle bundle = null;

HashMap<String, String> item = null;

Object[] keyArray = null;

if(mChildList != null && mChildList.size() > 0)

{

selectedChildList = mChildList.get(groupPosition); if(selectedChildList != null && selectedChildList.size() > 0)

{

currentList = new ArrayList<Bundle>();

for(int i = 0; i < selectedChildList.size(); i++) {

item = selectedChildList.get(i);

bundle = new Bundle();

keyArray = (Object [])item.keySet().toArray();

for(int j = 0; j < keyArray.length; j++)

{

bundle.putString(String.valueOf(keyArray[j]), item.get(keyArray[j]));

}

currentList.add(bundle);

}

}

(3) Parcelable 객체를 생성하여 사용하기

– 기본적으로 Parcelable 을 Implements 받아 생성하며 몇 가지 필수적인 Method 를 Overide 하여 구현하여야 한다.

– writeToParcel: 통신시 Android FrameWork에서 호출되는 메서드로 Seraliazable 하도록 직접 사용자가 데이터를 set 해주어야 한다. (이때 순서가 매우 중요, CREATE 와 일치해야 함)

– CREATEOR : 리턴하고자 하는 객체 타입으로 복원하는 메서드 또한 Overide 하여 구현 필요

public class Point implements Parcelable{

float x;

float y;

boolean isDraw;

public Point(float f, float g, boolean isDraw) {

this.x = f;

this.y = g;

this.isDraw = isDraw;

}

@Override

public int describeContents() {

// TODO Auto-generated method stub

return 0;

}

@Override

public void writeToParcel(Parcel dest, int flags) {

// TODO Auto-generated method stub

dest.writeFloat(x);

dest.writeFloat(y);

dest.writeBooleanArray(new boolean[]{isDraw});

}

public static Creator<Point> CREATOR = newCreator<Point>() {

@Override

public Point createFromParcel(Parcel source) {

// TODO Auto-generated method stub

float x = source.readFloat();

float y = source.readFloat();

boolean[] ba = new boolean[1];

source.readBooleanArray(ba);

return new Point(x,y,ba[0]);

}

@Override

public Point[] newArray(int size) {

// TODO Auto-generated method stub

return new Point[size];

}

};

}

@Sample@ : CustomView 폴더 참조

  1. binding 과 Service 를 Custom Provider

– 이미 ServiceBind 기능을 이용하여 Service 와 Activity 간의 Interactive 한 통신이 가능하다.

샘플코드는 아래와 같은 구조로 동작한다. .

Activity -> Resolver-> (Bind) -> Service (onCreate() -> onBind()-> onUnBind()) ->onDestory());

Service 쪽에서 Bind() 가 되면 Resolver 측에는 onServiceConnected() Callback 이 호출되며 Bind

변수를 리턴한다. 이 Bind 변수를 Interface로 Castinf하여 Service 측과 메서드 기반의 통신이 가능하다. 이때, 주고 받을 수 있는 객체는 당연히 통신 기반이기 때문에 Parcelable 객체만 가능

(1) Activity ->Resolver

샘플코드 에서 Activity 에 구현되는 내용은 별 것 없다. Resolver 에 구현된 몇 가지 메서드들을 호출할 뿐이다 .

myResolver = new MyResolver(this);

Button btn01 = (Button)this.findViewById(R.id.btn_01);

btn01.setOnClickListener(newOnClickListener() {

@Override

public void onClick(View v) {

myResolver.insert();

}

});

(1) Resolver ->Service

샘플코드에서 Resolver 는 어떤 인터페이스도 클래스도 상속 받지 않는다. Resolver에서 하는 역할은 3가지로 요약된다. Service Binding, ServiceConnection 객체를 통한Binding 객체 생성, Binding 객체를 이용한Service method 호출 3가지로 요약된다.

  1. A) Service 바인딩

Intent i = new Intent();

ComponentName cn = new ComponentName(“com.example.a10.bindtestmyservice”,”com.example.a10.bindtestmyservice.MainService”);

i.setComponent(cn);

//바인딩

context.bindService(i, conn, Context.BIND_AUTO_CREATE);

  1. B) AIDL 생성

다른 패키지 간에 Method 방식으로 Direct 호출은 굉장히 복잡한 일이다. 그래서 Android Frame Work 에서는 AIDL 을 지원한다 .

– AIDL 확장자의 파일을src/package 아래 생성한다.

– gen 폴더 아래 java 파일이 자동 생성되는 것을 볼 수 있다 .

– Service 를 제공받고자 하는 쪽에서도 동일하게 AIDL 파일을 생성해야 한다.

– 단, Service 를 제공하는 쪽과 동일한 Package 명을 사용해야 한다는 점은 유의

– 아래는 AIDL 파일의 예제이다.

package com.example.a10.bindtestmyservice;

interface AidlProvider

{

void insert();

void update();

void delete();

void query();

}

  1. C) ServiceConnection생성

ServiceConnection 클래스는 두 개의 Overiding method 를 지원하는데 onServerConnected()

에서는 Bind 클래스를 return 받을 수 있다.

우리가 정의한 update, query, delete, insert 4개의 method 를 활용하기 위해서 (B)에서 생성한 AIDL 클래스를 사용한다.

AidlProvider provider = AidlProvider.Stub.asInterface(Binder bind)

이렇게 생성된 provider 는 bind.insert();bind.update();bind.delete();bind.query();

메서드를 사용할 수 있다 .

private ServiceConnection conn = new ServiceConnection() {

@Override

public void onServiceDisconnected(ComponentName name) {

Toast.makeText(context, “-ServiceDisconncted”, 10).show();

}

@Override

public void onServiceConnected(ComponentName name, IBinder service) {

Toast.makeText(context, “-ServiceConneted”, 10).show();

bind = AidlProvider.Stub.asInterface(service);

}

};

@Sample@ : AIDL 폴더 참조

  1. USER-PERMISSION

(1) 자신이 생성한 Applcation 에 Permission 지정

<permission

android:description=”@string/permdesc_required”

android:label=”권한이 요구됩니다.”

android:name=”edu.jaen.permission”

android:protectionLevel=”signature”

/>

(2) Permission 획득

<uses-permission android:name=”edu.jaen.permission”/>

@Sample@ : B2.PermissionClient, B2.PermissionProject

  1. 기타

(1) 하위 버전 OS 환경에서 상위버전 기능 사용하기

– android-support_v4 : 하위 버전에서 상위 OS 기능을 사용할 수 있도록 External 형태로 라이브러리가 제공된다. 해당 Lib 는APK 에 포함되어 하위 OS 에서도 동작 할 수 있도록 한다.

(2) ApplicationManager

(3) SQLLite