NDK를 이용한 기본 예제이다. 간단한 프로그래밍은 기본예제의 변형으로 가능할 것이다. 더 깊은 내용은 나중에 포스팅 하도록 하겠다.


NDK 설치 완료후 제대로 설치가 되었는지 이 예제를 통해서 확인해보길 바란다. 먼저 프로젝트를 하나 생성한다. 프로젝트명은 HelloJNI로 하였다.


프로젝트 생성후 jni라는 이름의 폴더를 하나 생성한다. 이 폴더안에 2개의 파일을 생성할 예정이다.

2개의 파일 이름은 Android.mkhello-jni.c 이다.


jni폴더 생성후 [마우스 오른쪽 클릭] -> [New] -> [File] 을 눌러 파일을 생성한다.




위의 그림의 방식처럼 hello-jni.c 와 Android.mk 파일을 만들었다면 두 파일에 내용을 넣는다. 먼저 hello-jni.c 파일부터 내용을 넣겟다.


hello-jni.c

#include <string.h>
#include <jni.h>

jstring Java_tjssm_hellojni_MainActivity_stringFromJNI( JNIEnv* env, jobject thiz )
{

    return (*env)->NewStringUTF(env, "Hello from JNI !");
}

NDK 설치를 확인하기 위한 간단한 예제이기 때문에 자세한 설명은 생략하도록 하겠다. 

여기서 주의할 점은 jstring Java_tjssm_hellojni_MainActivity_stringFromJNI()이다.

jstring은 return 타입이고 그다음은 Java_패키지명1_패키지명2_class명_class에서만든메소드명() 이다.


ex) return타입이 jstring 이고 패키지명이 tjssm.hellojni이고 class명이 MainActivity이고, class에 만들어 놓은 메소드명이 stringFromJNI 이기때문에jstring Java_tjssm_hellojni_MainActivity_stringFromJNI() 이라고 쓴다.


여기서 주의할 점은 패키지명이나 class명에 '_'기호가 들어갈 경우 에러가 난다는 것이다. ndk를 이용한 프로그래밍에서는 '_'기호를 넣지 않도록 한다.


다음은 Android.mk 파일에 내용을 넣겠다.


Android.mk

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE    := hello-jni
LOCAL_SRC_FILES := hello-jni.c

include $(BUILD_SHARED_LIBRARY)

LOCAL_MODULE 은 c파일의 이름

LOCAL_SRC_FILES 에는 c파일의 이름에 .c를 붙여주면 된다.


다음은 JAVA소스이다. jni를 호출하는 MainActivity의 소스이다.


MainActivity.java

public class MainActivity extends Activity {
	
	private TextView tv;
	
	static {
		System.loadLibrary("hello-jni");
	}
	
	public native String stringFromJNI();

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		
		tv = (TextView) findViewById(R.id.tv_result);
		tv.setText(stringFromJNI());
	}
}

System.loadLibrary에 이전에 만들었던 c파일의 이름인 hello-jni를 넣어준다. 

public native String stringFromJNI() 라는 메소드가 jni와 연결된다.

return 타입이 String 이므로 이전에 작성했던 hello-jni로부터 String을 return 받아 tv라는 TextView로 값이 전달된다.


위와 같이 소스를 작성하였다면 ndk-build를 실행한다. cygwin 폴더안의 android-ndk폴더를 환경변수로 등록을 하였다면 cmd 창을 실행하여 현재 작성한 프로젝트 파일의 경로로 이동한다. 그후에 ndk-build라는 명령어를 입력하면 현재 프로젝트의 libs->armeabi 라는 폴더가 생기며 폴더안에 파일이 생성되어 있을것이다.


이제 이 프로젝트를 실행시키면 다음과 같은 결과를 얻을 수 있다.



매번 cmd창을 이용하여 ndk build를 할 수는 없으니 다음에는 이클립스에서 ndk build하는 방법을 알아보도록 하겠다.



2014/01/27 - [Programming/안드로이드] - [안드로이드] Eclipse에서 NDK-build 하기



안드로이드 프로그래밍에서 C나 C++ 언어를 사용하기 위해서는 NDK를 설치하여야 한다. NDK 설치 방법에 대해 알아보도록 하자.


Cygwin 설치

NDK를 설치하기 위해서는 Cygwin을 먼저 설치하여야 한다.


다운받기


각자 컴퓨터 사양에 맞는 파일을 다운받는다.



다운이 완료된 설치파일을 실행한다.



인터넷에서 파일을 받는 항목 선택



경로는 C:\cygwin 으로 설정한다.



패키지 파일을 다운로드할 폴더를 지정한다. 어느 경로를 지정하던지 상관없다.



인터넷 연결 선택



다운로드 사이트를 선택한다. 전세계적으로 사이트가 있는데 한국사이트는 없는듯 하다 ㅠㅠ 가까운 일본 사이트를 선택하도록 하자



다음을 누르면 아래와 같은 화면이 뜨는데 항목중에 Devel 항목이 Default로 표시되어 있을것이다. 클릭하여 Install로 바꿔주고 다음을 누른다.



다음을 누르면 엄청난 시간이 걸린다.. 잠시 쉬도록 하자



완료가 되면 다음과 같은 창이 뜬다.



이렇게 Cygwin 설치가 완료되었다.


환경변수 등록

환경변수를 등록하자

[내컴퓨터] -> [속성] -> [고급] -> [환경변수] 에서 시스템 변수Path 값을 편집한다.

C:\cygwin\bin;

C:\cygwin\usr\include;

두개의 환경변수를 등록한다.



환경변수 등록후 Cygwin을 실행하면 다음과 같은 화면이 나올 것이다.

이렇게 Cygwin설치를 완료한다.



NDK 설치

이제 NDK를 다운받아 설치하도록 하자


다운받기


각자 컴퓨터에 맞는 사양의 파일을 다운받는다.



다운로드 받은 파일을 압축 해제후 폴더안의 android-ndk-r9c(android-ndk-버전) 폴더를 C:\cygwin\home\Administrator 폴더로 이동시킵니다. (C:\cygwin\home\사용자계정)



이제 같은 경로에 있는 .bashrc파일을 수정한다. .bashrc파일을 이클립스에 드래그해서 열고 맨 아래에 다음 코드를 추가한다.

export ANDROID_NDK_ROOT=/home/사용자계정/ndk버전

ex) export ANDROID_NDK_ROOT=/home/Administrator/android-ndk-r9c



NDK를 이용한 프로그램을 작성한뒤 ndk build를 하기위해 android ndk의 폴더의 경로를 환경변수로 설정한다.

C:\cygwin\home\Administrator\android-ndk-r9c; (C:\cygwin\home\사용자계정\android-ndk-r9c)


이렇게 안드로이드 NDK 개발환경 구축이 완료되었다.


2014/01/27 - [Programming/안드로이드] - [안드로이드] NDK 기본 예제


2014/01/27 - [Programming/안드로이드] - [안드로이드] Eclipse에서 NDK-build 하기


 안드로이드에서 음성인식 기능을 구현하기 위해서는 구글의 Speech-To-Text(이하 STT)기능을 사용하면 됩니다. SST기능을 사용하는 방법은 2가지가 있습니다. 구글에서 지원하는 UI를 사용하거나, 나만의 커스텀 UI를 만드는 방법이 있습니다. 이 두가지 방법을 사용하는 예제는 인터넷에서 충분히 구할 수 있으나 이 두가지 방법은 제 맘에 드는 방법이 아니었습니다.

 저는 현재 음성녹음 시작과 함께 음성인식(STT)이 가능한 앱을 개발해야 했는데, 저 두가지 방법은 액티비티 전환이 필요하기 때문에 액티비티 전환 없이 음성인식을 하도록 만들어 보았습니다. 음성녹음의 경우 어렵지 않게 예제를 보고 구현할 수 있기 때문에 음성녹음 시작시 액티비티 전환 없이 음성인식을 하는 기능만 구현하면 되겠거니 생각해서 만들어 보았습니다.


액티비티(Activity)전환 없이 음성인식(구글 STT) 사용하기

 일단 프로젝트를 하나 생성한다. 그리고 가장 처음에 퍼미션부터 등록하도록 하겠다. 이 부분은 자칫하면 깜빡하고 넘어가기 쉽기 때문에(글쓴이 같은 경우..) 가장 먼저 등록을 해놓고 시작하겠다.

AndroidManifest.xml

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

 소리를 입력받기 위해 RECORD_AUDIO 권한이 필요하고, 음성인식을 하기위해 인터넷에 접속해야 하기 떄문에 INTERNET 권한이 필요하다.

 음성 인식 시작을 위한 버튼하나정도는 필요할 것이다. 버튼 하나와 결과를 출력할 텍스트뷰를 만들어준다.

 그리고 액티비티가 최초 생성될 때 onCreate시 음성인식을 위한 준비를 한다.

 MainActivity.java

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		
		i = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
		i.putExtra(RecognizerIntent.EXTRA_CALLING_PACKAGE, getPackageName());
		i.putExtra(RecognizerIntent.EXTRA_LANGUAGE, "ko-KR");
	}

i는 전역변수로 설정해주었다. (Intent i)
마지막 줄인 EXTRA_LANGUAGE는 인식할 언어를 설정해주는 코드이다. 글쓴이는 한글을 인식하였다. 영어를 인식하기 위해서는 "ko-KR" 대신 "en-US"를 써주면 된다.

("ko-KR"로 설정해도 abc라고 발음했을 경우 "에이비씨" 보다 "abc"로 나오는 경우가 많은것 같다.)

다음은 버튼 클릭시 작동하는 코드이다.

MainActivity.java

			mRecognizer = SpeechRecognizer.createSpeechRecognizer(this);
			mRecognizer.setRecognitionListener(listener);
			mRecognizer.startListening(i);

mRecognizer역시 전역변수로 설정 해 주었다. (SpeechRecognizer mRecognizer)
위의 두줄은 onCreate에 넣어줘도 상관은 없을것 같다. 마지막 줄은 음성인식 리스너를 불러오기 때문에 버튼 클릭시 실행하도록 한다.

다음은 리스너를 작성하자. 몇줄만 넣으면 자동완성으로 리스너 안의 메소드가 작성된다.

MainActivity.java

private RecognitionListener listener = new RecognitionListener() {
		
		@Override
		public void onRmsChanged(float rmsdB) {
			// TODO Auto-generated method stub
			
		}
		
		@Override
		public void onResults(Bundle results) {
			// TODO Auto-generated method stub
			
		}
		
		@Override
		public void onReadyForSpeech(Bundle params) {
			// TODO Auto-generated method stub
			
		}
		
		@Override
		public void onPartialResults(Bundle partialResults) {
			// TODO Auto-generated method stub
			
		}
		
		@Override
		public void onEvent(int eventType, Bundle params) {
			// TODO Auto-generated method stub
			
		}
		
		@Override
		public void onError(int error) {
			// TODO Auto-generated method stub
			
		}
		
		@Override
		public void onEndOfSpeech() {
			// TODO Auto-generated method stub
			
		}
		
		@Override
		public void onBufferReceived(byte[] buffer) {
			// TODO Auto-generated method stub
			
		}
		
		@Override
		public void onBeginningOfSpeech() {
			// TODO Auto-generated method stub
			
		}
	};

각 메소드의 이름만 보면 언제 동작할 것인지 이해할것이라 생각하고 음성인식 결과를 텍스트로 출력하는 부분만 작성하겠다. 

참고로 onRmsChanged 메소드는 입력받는 소리의 크기를 나타내주는데, 소리 크기값인 rmsDb는 디폴트 값이 -2 또는 -2.12 인거 같다. 한번 음성입력을 받고 일정 시간동안 입력이 없으면(rmsDb값이 -2 또는 -2.12일 때) 자동으로 종료되는듯 하다.

음성인식 결과는 onResult 메소드에서 얻을 수 있다.

MainActivity.java

@Override
public void onResults(Bundle results) {
	String key = "";
	key = SpeechRecognizer.RESULTS_RECOGNITION;
	ArrayList<String> mResult = results.getStringArrayList(key);
	String[] rs = new String[mResult.size()];
	mResult.toArray(rs);
	tv.setText(""+rs[0]);		
}

tv는 텍스트뷰이다. tv역시 전역변수로 설정하였다.(TextView tv)
results라는 결과값을 mResult라는 ArrayList에 저장한다. 
rs라는 String배열을 만들어 mResult의 크기만큼 배열을 초기화 하고 그 rs라는 배열에 mResult값을 넣는다.
for루프를 돌려서 인식한 결과값을 모두 볼 수도 있고, rs[0]으로 첫번째 나온 값만 받을수 있다.

액티비티 전환없이 음성인식을해서 결과를 받아왔다. 음성인식 시작코드만 음성녹음 시작시에 실행하도록 하면 음성녹음과 동시에 음성인식을 할 수 있을것 같다. 추가적으로 입맛에 맞게 코드 수정도 자유롭게 할 수 있을것 같다.



제가 설명이 부족한 부분이 있을텐데 댓글로 질문해주시면 감사하겠습니다.


 요즘 많은 어플들이 뒤로가기 버튼을 두번 눌러 앱을 종료시킨다. 
 종료하시겠습니까? 라는 확인창이 뜨고 확인을 눌러야 되는 번거로움이 없고, 잘못 종료버튼을 눌렀을 경우에도 토스트 알림창만 뜰뿐 별다른 방해요소가 없어서 참 좋은것 같다. 요즘 대부분의 앱이 이러한 종료 방식을 선택하고 있기때문에 한번 구현을 해보자.



 구현방법은 간단하다 뒤로가기 버튼 클릭시 현재시간을 저장하며 토스트 알림창을 띄워주고 한번더 눌렀을때 일정시간(예를들면 2초)가 지났는지 확인하고 일정시간이 지나지 않았을 경우 종료, 지났을 경우 알림창을 다시 띄워주면 된다.

0.    시간을 저장하는 변수(t) = 0;
1.    뒤로가기 버튼 (처음)클릭시 시간을 저장하는 변수(t) + 2000(2초)가 현재 시간보다 작다.
2-1. 알림창을 띄운다.('뒤로'버튼을 한번 더 누르시면 종료됩니다.)
2-2. 시간을 저장하는 변수(t)에 현재 시간을 저장한다.
3.    뒤로가기 버튼을 한번더 클릭
4-1. 현재 시간이 변수t + 2000보다 작으면 앱 종료
4-2. 현재 시간이 변수t + 2000보다 크면 t에 현재시간을 저장하고 알림창을 띄운다.


글로 보면 어렵더라도 소스를 보면 아마 바로 이해가 갈 것이다.

먼저 뒤로가기 버튼의 이벤트를 담당하는 클래스를 하나 만들었다.

BackPressCloseHandler.java

import android.app.Activity;
import android.widget.Toast;

public class BackPressCloseHandler {

	private long backKeyPressedTime = 0;
	private Toast toast;

	private Activity activity;

	public BackPressCloseHandler(Activity context) {
		this.activity = context;
	}

	public void onBackPressed() {
		if (System.currentTimeMillis() > backKeyPressedTime + 2000) {
			backKeyPressedTime = System.currentTimeMillis();
			showGuide();
			return;
		}
		if (System.currentTimeMillis() <= backKeyPressedTime + 2000) {
			activity.finish();
			toast.cancel();
		}
	}

	public void showGuide() {
		toast = Toast.makeText(activity,
				"\'뒤로\'버튼을 한번 더 누르시면 종료됩니다.", Toast.LENGTH_SHORT);
		toast.show();
	}
}


다음은 이 기능을 사용하려는 액티비티에서 넣어줘야 되는 소스이다. 사용하려는 액티비티에 onBackPressed()메소드를 생성하고 BackPressCloseHandler 클래스의 onBackPressed()메소드를 불러와주면 된다.

MainActivity.java

public class MainActivity extends Activity {

	private BackPressCloseHandler backPressCloseHandler;
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		
		backPressCloseHandler = new BackPressCloseHandler(this);
	}

	@Override
	public void onBackPressed() {
		//super.onBackPressed();
		backPressCloseHandler.onBackPressed();
	}
}

 안드로이드 블루투스통신 예제는 인터넷에 많이 있을 것이다. 예를들면 블루투스통신 채팅 같은 예제.. 그러나 예제를 수정하여 블루투스 통신을 구현하려고 할 때 연결이 잘 안될수도 있다. 블루투스 프로토콜 종류가 많이 있기 때문에 프로토콜이 맞지 않아서 생기는 원인같다. 아래 리스트에서 사용하는 블루투스 통신의 성격에 맞는 프로토콜을 찾아서 사용하도록 하자.

 블루투스 통신을 찾다보면 BluetoothChat이라는 예제 프로젝트를 볼 수 있는데 이 예제는 스마트폰끼리 채팅하는 예제이기 때문에 다른 블루투스 기기와 연결이 안될것이다. BluetoothChatService.java에 들어가서 UUID를 바꿔주면 아마 될 것이다. 

private static final UUID MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");

MY_UUID부분을 아래 UUID 리스트에서 찾아서 프로토콜에 맞게 변경해주자!

블루투스 프로토콜 UUID 리스트

BASE UUID
SDP_PROTOCOL_UUID
UDP_PROTOCOL_UUID
RFCOMM_PROTOCOL_UUID
TCP_PROTOCOL_UUID
TCSBIN_PROTOCOL_UUID
TCSAT_PROTOCOL_UUID
OBEX_PROTOCOL_UUID
IP_PROTOCOL_UUID
FTP_PROTOCOL_UUID
HTTP_PROTOCOL_UUID
WSP_PROTOCOL_UUID
BNEP_PROTOCOL_UUID
UPNP_PROTOCOL_UUID
HID_PROTOCOL_UUID
HCCC_PROTOCOL_UUID
HCDC_PROTOCOL_UUID
HN_PROTOCOL_UUID
AVCTP_PROTOCOL_UUID
AVDTP_PROTOCOL_UUID
CMPT_PROTOCOL_UUID
UDI_C_PLANE_PROTOCOL_UUID
L2CAP_PROTOCOL_UUID

= '{00000000-0000-1000-8000-00805F9B34FB}';
= '{00000001-0000-1000-8000-00805F9B34FB}';
= '{00000002-0000-1000-8000-00805F9B34FB}';
= '{00000003-0000-1000-8000-00805F9B34FB}';
= '{00000004-0000-1000-8000-00805F9B34FB}';
= '{00000005-0000-1000-8000-00805F9B34FB}';
= '{00000006-0000-1000-8000-00805F9B34FB}';
= '{00000008-0000-1000-8000-00805F9B34FB}';
= '{00000009-0000-1000-8000-00805F9B34FB}';
= '{0000000A-0000-1000-8000-00805F9B34FB}';
= '{0000000C-0000-1000-8000-00805F9B34FB}';
= '{0000000E-0000-1000-8000-00805F9B34FB}';
= '{0000000F-0000-1000-8000-00805F9B34FB}';
= '{00000010-0000-1000-8000-00805F9B34FB}';
= '{00000011-0000-1000-8000-00805F9B34FB}';
= '{00000012-0000-1000-8000-00805F9B34FB}';
= '{00000014-0000-1000-8000-00805F9B34FB}';
= '{00000016-0000-1000-8000-00805F9B34FB}';
= '{00000017-0000-1000-8000-00805F9B34FB}';
= '{00000019-0000-1000-8000-00805F9B34FB}';
= '{0000001B-0000-1000-8000-00805F9B34FB}';
= '{0000001D-0000-1000-8000-00805F9B34FB}';
= '{00000100-0000-1000-8000-00805F9B34FB}'; 

ServiceDiscoveryServerServiceClassID_UUID
BrowseGroupDescriptorServiceClassID_UUID
PublicBrowseGroupServiceClass_UUID
SerialPortServiceClass_UUID
LANAccessUsingPPPServiceClass_UUID
DialupNetworkingServiceClass_UUID
IrMCSyncServiceClass_UUID
OBEXObjectPushServiceClass_UUID
OBEXFileTransferServiceClass_UUID
IrMCSyncCommandServiceClass_UUID
HeadsetServiceClass_UUID
CordlessTelephonyServiceClass_UUID
AudioSourceServiceClass_UUID
AudioSinkServiceClass_UUID
AVRemoteControlTargetServiceClass_UUID
AdvancedAudioDistributionServiceClass_UUID
AVRemoteControlServiceClass_UUID
VideoConferencingServiceClass_UUID
IntercomServiceClass_UUID
FaxServiceClass_UUID
HeadsetAudioGatewayServiceClass_UUID
WAPServiceClass_UUID
WAPClientServiceClass_UUID
PANUServiceClass_UUID
NAPServiceClass_UUID
GNServiceClass_UUID
DirectPrintingServiceClass_UUID
ReferencePrintingServiceClass_UUID
ImagingServiceClass_UUID
ImagingResponderServiceClass_UUID
ImagingAutomaticArchiveServiceClass_UUID
ImagingReferenceObjectsServiceClass_UUID
HandsfreeServiceClass_UUID
HandsfreeAudioGatewayServiceClass_UUID

= '{00001000-0000-1000-8000-00805F9B34FB}';
= '{00001001-0000-1000-8000-00805F9B34FB}';
= '{00001002-0000-1000-8000-00805F9B34FB}';
= '{00001101-0000-1000-8000-00805F9B34FB}';
= '{00001102-0000-1000-8000-00805F9B34FB}';
= '{00001103-0000-1000-8000-00805F9B34FB}';
= '{00001104-0000-1000-8000-00805F9B34FB}';
= '{00001105-0000-1000-8000-00805F9B34FB}';
= '{00001106-0000-1000-8000-00805F9B34FB}';
= '{00001107-0000-1000-8000-00805F9B34FB}';
= '{00001108-0000-1000-8000-00805F9B34FB}';
= '{00001109-0000-1000-8000-00805F9B34FB}';
= '{0000110A-0000-1000-8000-00805F9B34FB}';
= '{0000110B-0000-1000-8000-00805F9B34FB}';
= '{0000110C-0000-1000-8000-00805F9B34FB}';
= '{0000110D-0000-1000-8000-00805F9B34FB}';
= '{0000110E-0000-1000-8000-00805F9B34FB}';
= '{0000110F-0000-1000-8000-00805F9B34FB}';
= '{00001110-0000-1000-8000-00805F9B34FB}';
= '{00001111-0000-1000-8000-00805F9B34FB}';
= '{00001112-0000-1000-8000-00805F9B34FB}';
= '{00001113-0000-1000-8000-00805F9B34FB}';
= '{00001114-0000-1000-8000-00805F9B34FB}';
= '{00001115-0000-1000-8000-00805F9B34FB}';
= '{00001116-0000-1000-8000-00805F9B34FB}';
= '{00001117-0000-1000-8000-00805F9B34FB}';
= '{00001118-0000-1000-8000-00805F9B34FB}';
= '{00001119-0000-1000-8000-00805F9B34FB}';
= '{0000111A-0000-1000-8000-00805F9B34FB}';
= '{0000111B-0000-1000-8000-00805F9B34FB}';
= '{0000111C-0000-1000-8000-00805F9B34FB}';
= '{0000111D-0000-1000-8000-00805F9B34FB}';
= '{0000111E-0000-1000-8000-00805F9B34FB}';
= '{0000111F-0000-1000-8000-00805F9B34FB}';

DirectPrintingReferenceObjectsServiceClass_UUID
ReflectedUIServiceClass_UUID
BasicPringingServiceClass_UUID
PrintingStatusServiceClass_UUID
HumanInterfaceDeviceServiceClass_UUID
HardcopyCableReplacementServiceClass_UUID
HCRPrintServiceClass_UUID
HCRScanServiceClass_UUID
CommonISDNAccessServiceClass_UUID
VideoConferencingGWServiceClass_UUID
UDIMTServiceClass_UUID
UDITAServiceClass_UUID
AudioVideoServiceClass_UUID
PnPInformationServiceClass_UUID
GenericNetworkingServiceClass_UUID
GenericFileTransferServiceClass_UUID
GenericAudioServiceClass_UUID
GenericAudioServiceClass_UUID
GenericTelephonyServiceClass_UUID
UPnPServiceClass_UUID
UPnPIpServiceClass_UUID
ESdpUPnPIpPanServiceClass_UUID
ESdpUPnPIpLapServiceClass_UUID
EdpUPnpIpL2CAPServiceClass_UUID

= '{00001120-0000-1000-8000-00805F9B34FB}';
= '{00001121-0000-1000-8000-00805F9B34FB}';
= '{00001122-0000-1000-8000-00805F9B34FB}';
= '{00001123-0000-1000-8000-00805F9B34FB}';
= '{00001124-0000-1000-8000-00805F9B34FB}';
= '{00001125-0000-1000-8000-00805F9B34FB}';
= '{00001126-0000-1000-8000-00805F9B34FB}';
= '{00001127-0000-1000-8000-00805F9B34FB}';
= '{00001128-0000-1000-8000-00805F9B34FB}';
= '{00001129-0000-1000-8000-00805F9B34FB}';
= '{0000112A-0000-1000-8000-00805F9B34FB}';
= '{0000112B-0000-1000-8000-00805F9B34FB}';
= '{0000112C-0000-1000-8000-00805F9B34FB}';
= '{00001200-0000-1000-8000-00805F9B34FB}';
= '{00001201-0000-1000-8000-00805F9B34FB}';
= '{00001202-0000-1000-8000-00805F9B34FB}';
= '{00001203-0000-1000-8000-00805F9B34FB}';
= '{00001203-0000-1000-8000-00805F9B34FB}';
= '{00001204-0000-1000-8000-00805F9B34FB}';
= '{00001205-0000-1000-8000-00805F9B34FB}';
= '{00001206-0000-1000-8000-00805F9B34FB}';
= '{00001300-0000-1000-8000-00805F9B34FB}';
= '{00001301-0000-1000-8000-00805F9B34FB}';
= '{00001302-0000-1000-8000-00805F9B34FB}'; 



블루투스(Bluetooth)통신 - 시작, 블루투스 활성화


위의 링크에 다시 작성 하였습니다.

클릭하면 크게 보실 수 있습니다.


 안드로이드 앱을 만들기 전에 가장 기본적으로 이해하고 넘어가야 되는 것이 액티비티의 생명주기이다. 생명주기를 이해하지 못하면 좋은 앱을 만들수 없다. 각 기능이 언제 실행될지 적당한 위치에 코드를 삽입할 수 없기 때문에 앱이 이상하게 작동되는 경우가 생기기 때문이다. 그렇기 때문에 액티비티 생명주기에 대해서 자세히 알아보도록 하겠다.


Activity의 4가지 주요 상태

Activity에는 크게 4가지 주요 상태가 있다.

1. Active/Running 상태

 MainActivity가 화면의 가장 앞(foreground)에 있어서 사용자가 직접 볼 수 있고, focus를 가지고 있는 상태다.
 MainActivity에서 입/출력이 가능한 상태


2. Pause 상태

 활동중인 MainActivity가 화면의 foreground를 새로 점유한 SubActivity에게 포커스를 잃었지만 아직은 MainActivity가 보이는 상태이다.
 SubActivirt가 화면 전체를 사용하지 않거나, 반투명하게 구현 되어 있을 때


3. Stop 상태

 활동중인 MainActivity가 화면 전체를 채우는 SubActivity에게 foreground를 점유당한 상태


4. Killed (Dead) 상태

 MainActivity가 생성되지 않았거나, 생성 후 소멸된 상태


상태 변화에 대한 핸들러 메소드








+ Recent posts