http://java.elex.pe.kr/2014/01/blog-post.html

안녕하세요 오랜만에 포스팅을 하네요

개인적인 사정(면접, 과제)로 정신없이 지내다 보니 조금은 소홀해졌네요 ^^..

댓글로 질문하신 분도 꽤 있으신데 제가 관련 내용을 업데이트 못 해서 죄송합니다 ^^.. 빠른 시일 내에 하도록 하겠습니다!



Genymotion 설치 방법


안드로이드 프로그래밍을 하다 보면 스마트폰에 예제 어플들이 수도 없이 깔려서 거슬린 적이 많을 것이다. 하지만 느린 에뮬레이터를 쓸 바에는 불편함을 감수하고 스마트폰을 사용하는 분들이 많을 것이라고 생각된다. 하지만 이 에뮬레이터는 빠르다.

Genymotion 설치법에 대해서 알아보자!


1. 회원가입 및 다운로드

http://www.genymotion.com 에 들어가서 회원가입을 한다. GET GENYMOTION 클릭!



유료 버전이 기능이 더 많지만 일단은 Free 버전을 써보도록 하자! DOWNLOAD 클릭!



DOWNLOAD를 클릭하면 로그인 하라는 창이 뜬다. 아직 회원가입을 안했다면 회원가입을 한다. 계정이 있다면 로그인!



Enterprise size나 Usage type은 적당히 선택하도록 한다.


가입을 완료하면 방금 적었던 이메일 주소로 인증메일이 온다. 인증메일에서 확인을 하면 바로 실행프로그램을 다운받을수 있는 창이 뜬다. (https://cloud.genymotion.com/page/launchpad/download)



자신의 컴퓨터 사양에 맞는 버전을 다운받는다.



2. 설치

다운받은 설치 프로그램을 실행하여 설치를 하도록 하자




설치를 마치고 지니모션을 실행시킨다.  

VirtualBox도 설치가 될텐데 따로 설정할 부분은 없다.

(VirtualBox는 가상운영체제로 여기서 지니모션이 실행된다.)


3. 설정

사용할 에뮬레이터의 환경설정을 한다. 지니모션 첫 실행시 다음과 같은 화면이 뜬다.

새로운 디바이스를 만들도록하자.



Yes를 누르면 로그인을 하라는 화면이 뜰 것이고 로그인을 하면 다음과 같은 화면이 뜬다.

원하는 디바이스 환경을 찾아서 Next를 누르면 설치가 진행이 된다.



설치완료후 안드로이드 에뮬레이터로 사용하기 위해 세팅을 해준다.

Settings 메뉴에서 ADB메뉴에서 Android SDK 폴더의 경로를 지정해준다.




세팅완료후 Play버튼을 눌러 실행을 한다.



4. 에러해결

실행 했을때 다음과 같은 화면이 뜨는 경우가 있을것이다. 

MS 오피스가 설치된 PC에서 대부분 발생하는 문제라고 한다.

이 문제는 키보드 입력기를 "Microsoft 입력기"로 설정하면 된다.







위 그림과 같이 설정을 변경해주면 'Microsoft 입력기'키보드가 추가된다.

선택메뉴에서 'Microsoft 입력기'로 꼭 선택해주자

확인을 누르고 다시 지니모션을 실행해보자.


이제 정상적으로 실행이 된다! 다른 문제가 있다면 현재(2014.05.22)날짜 기준으로 VirtualBox를 최신버전으로 업데이트 하지 않았을 경우 또 다른 에러가 발생한다. 


설치나 설정을 모두다 완료했는데 안된다면 재부팅을 추천한다.







지금까지 블루투스를 활성화 하고 기기 검색을 하는 단계까지 진행하였다.


이전 글 : 블루투스 활성화 글 보기블루투스 기기 검색하기 글 보기


저번 프로젝트에 이어 블루투스 연결하는 단계를 포스팅 하겠다.


검색한 기기에 연결하기 위해서는 ConnectThread와 ConnectedThread에 대해서 알고 있어야 한다.

BluetoothService.java 파일에 ConnectThread와 ConnectedThread 클래스를 내부 클래스로 삽입해준다.


1. ConnectThread


BluetoothService.java

public class BluetoothService {
	... // 이전 부분 생략

	// RFCOMM Protocol
	private static final UUID MY_UUID = 
		UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
	
	private BluetoothAdapter btAdapter;
	
	private ConnectThread mConnectThread;
	private ConnectedThread mConnectedThread;

	... // 이전 부분 생략
		
	private class ConnectThread extends Thread {
		private final BluetoothSocket mmSocket;
		private final BluetoothDevice mmDevice;

		public ConnectThread(BluetoothDevice device) {
			mmDevice = device;
			BluetoothSocket tmp = null;
			
			// 디바이스 정보를 얻어서 BluetoothSocket 생성
			try {
                tmp = device.createRfcommSocketToServiceRecord(MY_UUID);
            } catch (IOException e) {
                Log.e(TAG, "create() failed", e);
            }
			mmSocket = tmp;
		}

		public void run() {
			Log.i(TAG, "BEGIN mConnectThread");
			setName("ConnectThread");
			
			// 연결을 시도하기 전에는 항상 기기 검색을 중지한다.
			// 기기 검색이 계속되면 연결속도가 느려지기 때문이다.
			btAdapter.cancelDiscovery();

			// BluetoothSocket 연결 시도
			try {
				// BluetoothSocket 연결 시도에 대한 return 값은 succes 또는 exception이다.
				mmSocket.connect();
				Log.d(TAG, "Connect Success");
				
			} catch (IOException e) {
				connectionFailed();		// 연결 실패시 불러오는 메소드
				Log.d(TAG, "Connect Fail");
				
				// socket을 닫는다.
				try {
					mmSocket.close();
				} catch (IOException e2) {
					Log.e(TAG,
							"unable to close() socket during connection failure",
							e2);
				}
				// 연결중? 혹은 연결 대기상태인 메소드를 호출한다.
				BluetoothService.this.start();
				return;
			}

			// ConnectThread 클래스를 reset한다.
			synchronized (BluetoothService.this) {
				mConnectThread = null;
			}

			// ConnectThread를 시작한다.
			connected(mmSocket, mmDevice);
		}

		public void cancel() {
			try {
				mmSocket.close();
			} catch (IOException e) {
				Log.e(TAG, "close() of connect socket failed", e);
			}
		}
	}
}


여기서 UUID라는 변수가 있는데 이것은 Bluetooth 통신 프로토콜이다. 블루투스 통신을 할 때 그에 맞는 프로토콜로 통신을 해 주어야 한다. 간단한 예로 블루투스 기능이 지원되는 이어폰과의 통신을 원한다면 그에 맞는 프로토콜을 사용하여야 하고, 스마트폰 끼리의 블루투스 통신은 또 그에 맞는 프로토콜을 사용해야 한다. 

지금 위에서 사용한 프로토콜은 아마 스마트폰끼리의 블루투스 통신을 하는데 사용하는 프로토콜일 것이다.


블루투스 프로토콜 종류 보기 - [안드로이드] 블루투스 프로토콜 UUID 리스트


2. ConnectedThread


위에서(ConnectThread) 다음단계가 ConnectedThread이다. 위 단계에서는 연결을 하는 중간단계 까지라고 생각하고, 이번 단계는 연결을 완료하는 단계라고 생각하면 될 것 같다. 위와 동일하게 BluetoothService 클래스에 내부 클래스로 정의한다.


BluetoothService.java

public class BluetoothService {
	... // 이 전 부분 생략
	
	private BluetoothAdapter btAdapter;
	
	private Activity mActivity;
	private Handler mHandler;

	private ConnectThread mConnectThread; // 변수명 다시
	private ConnectedThread mConnectedThread; // 변수명 다시
	
	... // 이 전 부분 생략
	
    private class ConnectedThread extends Thread {
        private final BluetoothSocket mmSocket;
        private final InputStream mmInStream;
        private final OutputStream mmOutStream;

        public ConnectedThread(BluetoothSocket socket) {
            Log.d(TAG, "create ConnectedThread");
            mmSocket = socket;
            InputStream tmpIn = null;
            OutputStream tmpOut = null;

            // BluetoothSocket의 inputstream 과 outputstream을 얻는다.
            try {
                tmpIn = socket.getInputStream();
                tmpOut = socket.getOutputStream();
            } catch (IOException e) {
                Log.e(TAG, "temp sockets not created", e);
            }

            mmInStream = tmpIn;
            mmOutStream = tmpOut;
        }

        public void run() {
            Log.i(TAG, "BEGIN mConnectedThread");
            byte[] buffer = new byte[1024];
            int bytes;

            // Keep listening to the InputStream while connected
            while (true) {
                try {
                    // InputStream으로부터 값을 받는 읽는 부분(값을 받는다)
                    bytes = mmInStream.read(buffer);

                } catch (IOException e) {
                    Log.e(TAG, "disconnected", e);
                    connectionLost();
                    break;
                }
            }
        }

        /**
         * Write to the connected OutStream.
         * @param buffer  The bytes to write
         */
        public void write(byte[] buffer) {
            try {
            	// 값을 쓰는 부분(값을 보낸다)
                mmOutStream.write(buffer);

            } catch (IOException e) {
                Log.e(TAG, "Exception during write", e);
            }
        }

        public void cancel() {
            try {
                mmSocket.close();
            } catch (IOException e) {
                Log.e(TAG, "close() of connect socket failed", e);
            }
        }
    }
}



3. 마무리 작업


지금까지 잘 따라했다면 몇 가지 빨간줄이 있을 것이다. 이 빨간줄을 지워보자

기본 베이스는 처음에 말했듯이 안드로이드 기본 예제인 BluetoothChat이다.

BluetoothChat에서 다음과 같은 메소드를 모두 복사해서 BluetoothService.java에 붙여넣어 빨간줄을 없애보자


BluetoothService.java

public class BluetoothService {
	... // 이 전과 동일
	private int mState;

	// 상태를 나타내는 상태 변수
	private static final int STATE_NONE = 0; // we're doing nothing
	private static final int STATE_LISTEN = 1; // now listening for incoming connections
	private static final int STATE_CONNECTING = 2; // now initiating an outgoing connection
	private static final int STATE_CONNECTED = 3; // now connected to a remote device

	... // 이 전과 동일

	// Bluetooth 상태 set
	private synchronized void setState(int state) {
		Log.d(TAG, "setState() " + mState + " -> " + state);
		mState = state;
	}

	// Bluetooth 상태 get
	public synchronized int getState() {
		return mState;
	}

	public synchronized void start() {
		Log.d(TAG, "start");

		// Cancel any thread attempting to make a connection
		if (mConnectThread == null) {

		} else {
			mConnectThread.cancel();
			mConnectThread = null;
		}

		// Cancel any thread currently running a connection
		if (mConnectedThread == null) {

		} else {
			mConnectedThread.cancel();
			mConnectedThread = null;
		}
	}

	// ConnectThread 초기화 device의 모든 연결 제거
	public synchronized void connect(BluetoothDevice device) {
		Log.d(TAG, "connect to: " + device);

		// Cancel any thread attempting to make a connection
		if (mState == STATE_CONNECTING) {
			if (mConnectThread == null) {

			} else {
				mConnectThread.cancel();
				mConnectThread = null;
			}
		}

		// Cancel any thread currently running a connection
		if (mConnectedThread == null) {

		} else {
			mConnectedThread.cancel();
			mConnectedThread = null;
		}

		// Start the thread to connect with the given device
		mConnectThread = new ConnectThread(device);

		mConnectThread.start();
		setState(STATE_CONNECTING);
	}

	// ConnectedThread 초기화
	public synchronized void connected(BluetoothSocket socket,
			BluetoothDevice device) {
		Log.d(TAG, "connected");

		// Cancel the thread that completed the connection
		if (mConnectThread == null) {

		} else {
			mConnectThread.cancel();
			mConnectThread = null;
		}

		// Cancel any thread currently running a connection
		if (mConnectedThread == null) {

		} else {
			mConnectedThread.cancel();
			mConnectedThread = null;
		}

		// Start the thread to manage the connection and perform transmissions
		mConnectedThread = new ConnectedThread(socket);
		mConnectedThread.start();

		setState(STATE_CONNECTED);
	}

	// 모든 thread stop
	public synchronized void stop() {
		Log.d(TAG, "stop");

		if (mConnectThread != null) {
			mConnectThread.cancel();
			mConnectThread = null;
		}

		if (mConnectedThread != null) {
			mConnectedThread.cancel();
			mConnectedThread = null;
		}

		setState(STATE_NONE);
	}

	// 값을 쓰는 부분(보내는 부분)
	public void write(byte[] out) { // Create temporary object
		ConnectedThread r; // Synchronize a copy of the ConnectedThread
		synchronized (this) {
			if (mState != STATE_CONNECTED)
				return;
			r = mConnectedThread;
		} // Perform the write unsynchronized r.write(out); }
	}

	// 연결 실패했을때
	private void connectionFailed() {
		setState(STATE_LISTEN);
	}

	// 연결을 잃었을 때 
	private void connectionLost() {
		setState(STATE_LISTEN);

	}

	private class ConnectThread extends Thread {
		... 
	}

	private class ConnectedThread extends Thread {
		...
	}
}


EX_Bluetooth.zip



마지막에 설명을 쫌 대강대강 하고 넘어간 부분이 많은데, 일단은 현재까지의 프로젝트를 압축파일로 올리겠다.

이후 시간이 된다면 스마트폰 끼리의 블루투스 예제를 주석을 달아서 올리도록 하겠다. 

또한, 글쓴이는 임베디드 보드(동글)과 통신을 하였는데 이 부분에 대해서 궁금하신 분이 많다면 서둘러 예제 프로젝트를 올리도록 하겠다.

  1. 이전 댓글 더보기
  2. 함동균 2014.08.27 17:32 신고

    정말 감사합니다. 기존의 블루투스 채팅 앱에서 채팅 기능 을 빼고 블루투스 기능만 제 앱에 탑재 할려 고 하는데 블루투스에 대한 이해가 낮아서 고심하던 찰나에 이런 포스팅을 해주셔서 감사합니다. ㅋ 저는 한국해양대학교 조선과 학생입니다. 자주 방문하도록 하겠습니다.

  3. 이태경 2014.09.23 12:14 신고

    포스팅 잘 보았습니다.
    다름이 아니고, 이번에 블루투스 관련해서 프로젝트를 하는데,
    폰과 스피커를 블루투스 연결해서 전화가 왔을 때, 그 소리를 스피커로 전달하려고 하거든요
    그래서 말씀하신대로 UUID를 HSP UUID로 바꿔서 연결해봤더니, 일단 연결되었다는 의미로
    스피커에서 뚜.뚜 하는 소리는 나는데 실제로 전화가 왔을 때, 그게 스피커로 전달은 안 되더군요
    문제가 뭘까요?

    • 영상털이범 2014.09.23 13:17 신고

      스피커를 연결했을때 들리는 소리는
      미디어 사운드가 들리고
      전화가 왔을때는 다른 채널?의 사운드기 때문에 안들리는게 아닐까요?
      핸드폰의 소리 옵션에도 미디어 사운드, 통화음, 시스템사운드 등등으로 나눠져 있어서
      그 문제가 아닐까 싶습니다.. 아니면 연결이 잘 안되었거나?
      자세한건 저도 다시 알아보고 답변 달겠습니다.

  4. 이태경 2014.09.24 10:48 신고

    먼저 답변 감사합니다~!
    현재 저희 상황 다시 한번 상세히 설명 좀 드릴게요^^
    먼저 폰의 기본 블루투스 연결(환경설정에서의~)로 스피커를 연결하면, 물론 음악과 전화음 모두 스피커로 전달이 됩니다.
    헌데 올려주신 앱 통해서 UUID를 HFP, HSP로 바꾼 후 블루투스 연결을 해 보면, 스피커에서 뚜,,뚜 소리와 함께
    연결되었을 때의 소리는 나거든요(이건 HSP UUID로 설정했을 경우입니다.). 연결이 되었으니 당연히 핸드폰으로 전화가 왔을 경우, 스피커에서 소리가 나올 줄 알았는데 그게 아니더군요...아니면 HSP, HFP가 동시에 2개 다 연결이 되야하는 걸까요? 아니면 말씀해 주신대로, 소리 Source 옵션을 바꿔줘야 하는 걸까요? 가능성이 여러가지라서 어떤 방식으로 풀어야 할지...ㅎㅎ

    • 영상털이범 2014.10.01 15:46 신고

      저도 직접 해본게 아니라서 뭐라고 말씀을 드리지는 못하겠네요 ^^...
      여러가지 가능성을 열어두고
      귀찬겠지만 일일이 테스트해보시는게 제일 도움이 될 듯 싶습니다.

  5. 천태평 2014.10.20 09:00 신고

    블루투스 사용에 도움이 되었네요 ~~ UUID만 바꾸면 블루투스 스피커와 연결이 가능할까요?

  6. 2014.10.22 10:23

    비밀댓글입니다

  7. 김현우 2014.11.27 17:19 신고

    안드로이드 블루투스 통신 공부중인데요 이해가 잘 되게 정리가 되있네요!
    좋은 자료 감사합니다.
    한가지 궁금한 것이 있는데요, 현재 구현된 코드로 보면 MainActivity 내부에 BluetoothService 객체가 정의되어있잖아요? 그렇게되면 여기 MainActivity를 통해 인텐트를 통해 다른 액티비티를 불러냈을 때 더이상 블루투스 통신을 할 수 없는 것인가요?
    만약 그렇다면 서비스를 구현을 해야하는 것인지 개념이 안잡혀서 이렇게 물어봅니다!

  8. 박상균 2014.12.09 10:46 신고

    좋은글 잘 봤습니다. 설명을 정말 잘해놓으셨는데 임베디드 동글보드 연동예제도 볼수 있을까요??저도 구현중인데
    소스를 보고 하면 더 이해가 빠를꺼같아서요 ㅎㅎ

  9. futurejo2 2015.03.29 16:31 신고

    감사합니다. 많은 도움이 됫습니다.

  10. jsj 2015.04.11 00:49 신고

    안드로이드간 블루투스 통신을 하려고 하는데 포스팅한 것을 보고 그대로 했는데도
    어플이 맨처음 main.xml에 뜨는 연결 버튼을 누르면 프로그램이 죽어버립니다...
    BluetoothService.java에 enableBluetooth() 메소드 else문에서 인텐트 객체 생성하는데까지만 동작하는것같은데
    다음은 왜 안되는걸까요 ㅠㅠ

  11. magi 2015.04.20 17:18 신고

    정상적으로 실행되는 예제에다 친절한 주석까지! 깔끔하게 정리된 포스팅에 눈 호강하고 갑니다! 건승하세요 ^^

  12. yha 2015.04.23 17:22 신고

    블루투스에 대해 처음 공부중인데 많은 도움이 되었습니다. 감사합니다!

  13. hoha 2015.05.23 10:34 신고

    정말 많은 도움 받고 있습니다!!
    그런데 블루투스가 켜지는 것까지는 됬는데 블루투스가 켜진 후에는 앱이 중지된다고 하면서 종료됩니다.
    무슨 문제인지 조언해주시면 정말 감사하겠습니다ㅠㅠ

    • 거북이 2015.11.23 21:59 신고

      저도 그런상황이군요.
      현재 안드로이드 스튜디오 사용중이고
      안드 버전은 4.4로 맞춰서 사용중인데... ㄷㄷ

    • 2015.11.29 07:38 신고

      매니페스트에 블루투스 선언하셔야대용ㅋㅋ

    • bhy 2016.10.24 19:37 신고

      저도 같은 상황에서 문제가 발생햇는데 혹시 해결하셧나요

  14. hoha 2015.05.23 11:05 신고

    그리고 제가 지금 만들려고 하는 것이 pc와 앱을 블루투스로 연결하여 앱을 이용해 pc를 제어하도록 하는 것을 하는데요, 위에 포스팅하신 내용이 서버쪽도 완성이 되어있어야 블투루스 검색 리스트가 실행될 수 있는 것인지,
    제 작업에 대한 조언 부탁드려요ㅠㅠ

  15. Thanks for you 2015.05.30 19:37 신고

    안녕하세요. 블루투스 왕초보입니다.
    글 써주신 것을 완성하였을때는, 어떤 결과화면을 볼 수 있는건가요?

  16. youngman 2015.12.10 21:24 신고

    임베디드 보드와의 통신예제 혹시 올려주실수 있나요?ㅜ

  17. 양재의 2016.02.17 08:45 신고

    안녕하십니까^^ 지인의 추천으로 이 곳을 알게 된 안드로이드 초보자입니다만, 블루투스에 대해서 학습 중이던 차에 큰 도움을 받게 되어서
    감사드립니다. 아주 이해하기 쉽게 글을 써놓으셔서 다른 강좌도 공부를 할 예정입니다. 그리고 앞의 글을 보니 임베디드 보드와의 통신에 대해서 예제 프로젝트를 올리겠다고 하셨던데 보이지가 않더군요^^ 강좌를 게시한 시기가 많이 지난 것 같은데 지금이라도 혹시 게시가 가능할까요?
    간곡히 부탁 좀 드리겠습니다.^^; 수고하십시오.

  18. bhy 2016.10.24 20:02 신고

    안녕하세요~ 너무 잘봤습니다. 한가지 궁금한점이 있어서 글을 올립니다~블루투스 활성화 까지는 되지만검색하려고할때 앱이 중지되는데 문제점을 모르겟습니다 ㅠㅠ 가르쳐주세요 ㅠㅠ

  19. ㅁㄴㅇ 2016.11.10 22:45 신고

    @Override
    public void onClick(View v) {
    if(btService.getDeviceState()) {
    // 블루투스가 지원 가능한 기기일 때
    btService.enableBluetooth();
    } else {
    finish();
    }
    }

    에서 @override가 에러나는데 어떻게 해야 고쳐질까요??ㅠㅜ

  20. 상산조자룡 2018.08.01 12:26 신고

    좋은 자료 감사합니다.
    글 작성일이 한참 되서 반영이 안된 내용이 있는데

    마시멜로 버전 올라오면서부터 블루투스 스캔 사용하려면

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

    이 두개 권한이 더 필요하게 됬습니다 블루투스 쓰는데 로케이션권한이 왜 필요한건지.. 암튼 매니페스토 추가하면 되겠습니다..
    여기서 하나더. DeviceListActivity 사용시 이상하게 location 권한 요청을 안합니다..
    그래서 onCreate에서

    int MY_PERMISSIONS_REQUEST_ACCESS_COARSE_LOCATION = 1;

    ActivityCompat.requestPermissions(this,

    new String[]{Manifest.permission.ACCESS_COARSE_LOCATION},

    MY_PERMISSIONS_REQUEST_ACCESS_COARSE_LOCATION);

    강제 권한 요청 해주시면 스캔 잘 돌아갑니다.
    이거때매 2일동안 머리털 많이 빠졌습니당.. 저같은 고생 안하시길 바라며 글 남깁니다.

    영상털이범님 항상 감사합니다.

  21. 안드드드드 2018.11.13 14:07 신고

    블루투스 리스트가 나오고 클릭했을때 페어링을합니다 그런데 페어링하고난 뒤에 연결이 안되는데.. 왜그런건가요????ㅠㅠ 답글부탁드립니다

저번 포스팅에서는 블루투스를 활성화 하는 단계까지 진행하였다. 


이전 글 : 블루투스 활성화 글 보기 


이번에는 저번 프로젝트에 이어 기기 검색하는 부분부터 시작하겠다.


1. 기기 검색하기 - 프로젝트 파일 복사하기


기기 검색하기에 앞서 기기 검색하기 기능 실행시 보여줄 화면을 위해 안드로이드 블루투스 채팅 예제프로젝트에서 몇가지 파일을 가져오도록 하겠다. 번거로울수 있어서 아래 포스팅을 하였다. 접힌 내용을 펼쳐서 보길 바란다.

java 파일인 DeviceListActivity.java

레이아웃 xml 파일인 device_list.xml, device_name.xml

을 복사해서 붙여넣고 

[res]->[values]->[string.xml] 에 string 들을 추가해준다.(복사해서 붙여넣는다.)


.. 추가중


Manifest에 액티비티 추가(DeviceListActivity)를 해주는것도 잊지말자!


AndroidManifest.xml

        <activity android:name="ssm.bluetooth.MainActivity" 
                android:label="@string/app_name">
                    <intent-filter>
                        <action android:name="android.intent.action.MAIN">

                        <category android:name="android.intent.category.LAUNCHER">
                    </category>
                </action>
        </intent-filter>
        </activity>
        <!-- 여기서부터 추가 -->
        <activity android:name="ssm.bluetooth.DeviceListActivity" 
                android:theme="@android:style/Theme.DeviceDefault.Dialog">
        <!-- 여기까지 추가 -->


2. 기기 검색하기 - 코드 작성하기


기기 검색시 띄워줄 액티비티가 완성되었으니 이제 액티비티를 띄워줄 코드를 작성해보자

BluetoothService.java 파일에 scanDevice()라는 메소드를 생성하였다.


BluetoothService.java

public void scanDevice() {
		Log.d(TAG, "Scan Device");
		
		Intent serverIntent = new Intent(mActivity, DeviceListActivity.class);
		mActivity.startActivityForResult(serverIntent, REQUEST_CONNECT_DEVICE);
	}

startActivityForResult가 또 등장하였다!

저번 포스팅에서 봤던 녀석이 아닌가!

새로운 액티비티를 띄워서 처리된 결과값이 mActivity로 반환이 되는 코드이다.(mActivity는 MainActivity)


scanDevice() 메소드에서는 디바이스를 선택하는 액티비티를 띄워주고 선택하였을 경우 그 결과값을 MainActivity로 반환하고 있다. 


그렇다면 scanDevice()라는 기기를 검색을 요청하는 메소드는 어디에 추가를해야 될까?

기기의 블루투스 상태가 On 상태이고, 블루투스 연결 버튼을 눌렀을 경우,

또는 기기의 블루투스 상태가 Off상태 이었을때, 연결 버튼을 눌러 블루투스를 활성화 하였을 경우.

이 두가지 경우에 scanDevice()메소드를 호출하면 될 것이다. 

간단히 정리하자면 블루투스가 활성화 되어있는 상태에서 scanDevice()메소드를 호출하면 된다.




그럼 scanDevice()메소드를 호출하고, 기기를 선택하였을 경우 결과값을 반환 받았을때, MainActivity에서 처리해주는 소스를 작성해 보자.


MainActivity.java

public void onActivityResult(int requestCode, int resultCode, Intent data) {
        Log.d(TAG, "onActivityResult " + resultCode);
        
        switch (requestCode) {
        
        /** 추가된 부분 시작 **/
        case REQUEST_CONNECT_DEVICE:
            // When DeviceListActivity returns with a device to connect
            if (resultCode == Activity.RESULT_OK) {
            	btService.getDeviceInfo(data);
            }
            break;
        /** 추가된 부분 끝 **/
        case REQUEST_ENABLE_BT:
            // When the request to enable Bluetooth returns
            if (resultCode == Activity.RESULT_OK) {
            	// Next Step
            	btService.scanDevice();
            } else {

                Log.d(TAG, "Bluetooth is not enabled");
            }
            break;
        }
	}

requestCode가 REQUEST_CONNECT_DEVICE인 경우 getDeviceInfo()메소드를 호출하도록 하였다.

getDeviceInfo()메소드는 아직 구현하지 않았다. 

이 메소드는 기기선택 액티비티에서 선택한 기기의 정보를 받아 getDeviceInfo()라는 메소드로 전달을 해주고 getDeviceInfo()메소드는 그 정보를 이용하여 블루투스연결을 시도할 예정이다.


3. 검색된 기기에 접속하기 - 1


검색된 기기에 접속하기 위해서 getDeviceInfo()메소드를 작성해보자.


BluetoothService.java

	public void getDeviceInfo(Intent data) {
		// Get the device MAC address
		String address = data.getExtras().getString(DeviceListActivity.EXTRA_DEVICE_ADDRESS);
		// Get the BluetoothDevice object
		//BluetoothDevice device = btAdapter.getRemoteDevice(address);
		BluetoothDevice device = btAdapter.getRemoteDevice(address);
		
		Log.d(TAG, "Get Device Info \n" + "address : " + address);

		connect(device);
	}

address라는 String에는 선택한 기기의 주소가 담겨져 있고, 그 주소를 BluetoothDevice로 전달하여 connect()메소드로 전달하면 접속을 할 수 있다. connect()메소드는 아직 구현을 하지 않았다. 이제 connect()메소드만 구현하면 기기의 블루투스 연결은 가능할 것 이다.


4. 검색된 기기에 접속하기 - 2


이제부터는 많은 양의 복사 붙여넣기를 시도할 예정이다.

안드로이드 블루투스 채팅 예제의 BluetoothChatService의 connect()메소드를 붙여넣고, 이와 관련된 모든 소스를 붙여넣는다.

다음 포스팅을 보면서 진행하도록 하자.


다음 글 : 블루투스통신 연결하기 글 보기




  1. 2014.04.05 01:06

    비밀댓글입니다

    • 영상털이범 2014.04.05 03:58 신고

      지금까지는 잘 따라하셨나요? ㅋㅋ
      죄송합니다.. 사실 더 포스팅을 했어야 하는데
      그 뒤로 시간도 안나고 귀차니즘도 있어서 ..
      뒷 부분은 제가 오늘부터 포스팅 할 생각이니까 잘 봐주세요 ㅎㅎ

  2. 2014.04.05 11:36

    비밀댓글입니다

  3. 이정민 2014.05.19 15:22 신고

    android:theme="@android:style/Theme.DeviceDefault.Dialog">
    이 소스가 어떤 의미인가요??

    소스를 복사해서 붙엿는데 이 부분이 빨간줄로 나오더라구요...-_ -;;

    • 영상털이범 2014.06.26 14:04 신고

      새로 추가한 DeviceListActivity의 테마를 변경해 주는 소스입니다.
      그 부분을 제거하였을 경우 디바이스를 선택하는 화면이 전체화면으로 나타나게 됩니다.
      하지만 저 부분을 넣어주면 다이얼로그액티비티로 나타나게 됩니다.
      저 부분에서 에러가 나신다면 액티비티를 메니페스트에서 다이얼로그액티비티로 띄우는 부분을 찾아서 수정하시면 될 듯 합니다!

  4. gyun 2014.05.25 18:22 신고

    안녕하세요. 친절한 포스팅 덕분에 많이 배우고 있습니다~
    근데 블루투스 채팅 예제프로젝트는 어딨는건가요?

    • 영상털이범 2014.06.26 14:05 신고

      채팅예제 프로젝트는 이전 글에보시면
      안드로이드 예제 프로젝트를 생성하는 포스팅이 있습니다(접혀 있으니 펼쳐 보셔야 됩니다.)
      잘 못찾으시겠다면 인터넷 검색으로도 쉽게 구할 수 있습니다.
      아마 BluetoochChat 이라는 프로젝트 이름일 것입니다.

  5. 감사해용 2015.04.30 21:37 신고

    혹시 기기간 블루투스 통신 인가요?????

  6. 감사함당 2015.05.19 17:30 신고

    Manifest에 액티비티 추가(DeviceListActivity) 부분에서

    <activity android:name="ssm.bluetooth.DeviceListActivity" 부분이 빨간색으로 오류가 뜨는데
    이 소스는 무슨 의미인가요 ???

  7. 이동우 2016.03.01 00:12 신고

    기기 검색하기에 앞서 기기 검색하기 기능 실행시 보여줄 화면을 위해 안드로이드 블루투스 채팅 예제프로젝트에서 몇가지 파일을 가져오도록 하겠다. 번거로울수 있어서 아래 포스팅을 하였다. 접힌 내용을 펼쳐서 보길 바란다.
    java 파일인 DeviceListActivity.java
    레이아웃 xml 파일인 device_list.xml, device_name.xml
    을 복사해서 붙여넣고
    [res]->[values]->[string.xml] 에 string 들을 추가해준다.(복사해서 붙여넣는다.)

    이부분에서 접힌 내용을 펼쳐서 보길 바란다라고 되어있는데 접힌 내용이없고 추가중....이라는 말밖에없습니다 ㅠㅠ 어떤것을 복사붙여넣기 하라는 것인지 string들을 추가해준다도 어떤 것을 복사해서 붙여넣으라는 것인지 모르겠습니다

    • cchead 2017.02.19 13:28 신고

      DeviceListActivity.java 는
      예제소스로 공개 되어 구글링 하시면 금방나옵니다.
      bluetoothChat 예제에 다 들어있는듯

  8. String?? 2016.11.23 07:01 신고

    [res]->[values]->[string.xml] 에 string 들을 추가해준다.(복사해서 붙여넣는다.)

    이부분에서 string들을 찾을 수가 없네요... string.xml 파일은 어디서 구할 수 있을까요?

  9. 이레 2017.04.12 14:33 신고

    connect() 에서 막혀서 요녀석이어딨지? 하면서 엄청고민했었는데

    마지막을안읽었었네요 ㅋㅋ

    재밌게 따라하고있습니다 감사합니다

  10. 안드드드드 2018.11.12 16:12 신고

    블루투스 기기 검색시뜨는창을 제가직접 만들고싶은데 어떻게해야하는지좀 알려주세요ㅠㅠ

안드로이드의 블루투스 통신 예제입니다.

안드로이드의 블루투스 레퍼런스를 참고하고 싶으시다면 다음 링크로 들어가시면 됩니다.


레퍼런스 참고 -> 블루투스 API


1. 블루투스 통신 예제


> 예제 사용법 보기(클릭)


이 예제를 활용하여 수정한다면 블루투스 통신을 자유자재로 사용할 수 있다.

이제부터 이 예제를 활용하여 블루투스 통신을 하는 예제를 만들어 보겠다.


2. 새 프로젝트 생성


액티비티에 버튼을 생성하여, 버튼을 눌렀을 경우 블루투스 연결을 할 수 있도록 만들어볼 예정이다.


메인화면 레이아웃은 다음과 같이 버튼과 현재 상황을 알려주는 TextView로 만들었다.

main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >

    <Button
        android:id="@+id/btn_connect"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:text="연결" />


    <TextView
        android:id="@+id/txt_result"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/btn_connect"
        android:text="" />

</RelativeLayout>



기본 세팅이 끝났으니 이제부터 블루투스 통신에 관련된 코드를 작성해보겠다.


3. 권한 등록


제대로된 코딩을 시작하기 전에 권한등록(permission 등록)을 먼저 하도록 하자

블루투스 기능을 사용하기 위해서는 'BLUETOOTH'와 'BLUETOOTH_ADMIN'의 권한을 등록해줘야 한다.


BLUETOOTH : 커넥션 요구, 커넥션 수락, 데이터 전송 등의 블루투스 통신을 하기 위해 필요한 권한

BLUETOOTH_ADMIN : 디바이스 검색 시작, 블루투스 설정을 조작하기 위해 필요

(BLUETOOTH_ADMIN 권한을 사용하려면 BLUETOOTH 권한도 꼭 있어야 한다.)


Manifest 파일에 블루투스 권한 등록


AndroidManifest.xml

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


4. 새 Class 파일 생성


MainActivity에는 Button과 TextView만 배치해놓고 BluetoothService라는 Class를 만들도록 한다.

BluetoothService라는 Class에서 블루투스와 관련된 모든 작업을 처리할 예정이다. 

작업이 처리되는 과정은 핸들러를 통해서 MainActivity에 전달되어 상태값을 전달받아 TextView에 보여주거나 버튼의 상태를 변경해 주도록 할 것이다.


BluetoothService 생성자는 메인이 되는 MainActivity로 부터 Activity와 Handler 값을 받는다.


BluetoothService.java

public class BluetoothService {
	// Debugging
	private static final String TAG = "BluetoothService";
	
	private BluetoothAdapter btAdapter;
	
	private Activity mActivity;
	private Handler mHandler;
	
	// Constructors
	public BluetoothService(Activity ac, Handler h) {
		mActivity = ac;
		mHandler = h;
		
		// BluetoothAdapter 얻기
		btAdapter = BluetoothAdapter.getDefaultAdapter();
	}

MainActivity.java

private BluetoothService btService = null;

private final Handler mHandler = new Handler() {

		@Override
		public void handleMessage(Message msg) {
			super.handleMessage(msg);
		}
		
	};

@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		
		setContentView(R.layout.main);
		
		// BluetoothService 클래스 생성
		if(btService == null) {
			btService = new BluetoothService(this, mHandler);
		}
	}


5. 블루투스 활성화


블루투스를 활성화 하기 위해 BluetoothAdapter클래스를 사용해서 다음 두 단계의 작업을 순서대로 진행한다.


① 블루투스 지원 확인

② 블루투스 활성화


① 블루투스 지원 확인

블루투스 통신을 사용하기 전에 디바이스가 블루투스를 지원하는지 확인할 필요가 있다. 디바이스가 블루투스를 지원하는지 확인해보도록 하자


BluetoothService.java

public boolean getDeviceState() {
		Log.d(TAG, "Check the Bluetooth support");
		
		if(btAdapter == null) {
			Log.d(TAG, "Bluetooth is not available");
			
			return false;
			
		} else {
			Log.d(TAG, "Bluetooth is available");
			
			return true;
		}
	}

getDeviceState() 라는 메소드를 만들어서 기기의 블루투스 지원여부를 확인 한다.

BluetoothAdapter가 null일 경우 블루투스 통신을 지원하지 않는 기기이다. (하지만 이러한 기기는 요즘 없을듯..?)


② 블루투스 활성화

getDeviceState()가 true를 반환할 경우 블루투스 활성화를 요청하도록 해보자.

블루투스 활성화 요청을 위해서 enableBluetooth()라는 메소드를 만들었다. 


BluetoothService.java

public void enableBluetooth() {
		Log.i(TAG, "Check the enabled Bluetooth");
		
		
		if(btAdapter.isEnabled()) {		
			// 기기의 블루투스 상태가 On인 경우
			Log.d(TAG, "Bluetooth Enable Now");
			
			// Next Step
		} else {		
			// 기기의 블루투스 상태가 Off인 경우
			Log.d(TAG, "Bluetooth Enable Request");
			
			Intent i = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
			mActivity.startActivityForResult(i, REQUEST_ENABLE_BT);
		}
	}

기기의 블루투스 상태가 On일 경우 다음 단계를 실행하면 되고, 

기기의 블루투스 상태가 Off일 경우 블루투스 활성화를 요청하는 알림창을 띄운다.


알림창에서 확인/취소를 선택할 경우 결과는 MainActivityonActivityResult()메소드로 들어온다. 

그 전에 startActivityForResult의 개념에 대해서 알고 있어야 이해하기 편한데, 이 것은 구글링을 통해서 알아보는것을 추천한다.


알림창의 확인/취소 결과는 MainActivity에 onActivityResult()메소드로 전달되는데 소스를 보면 다음과 같다.


MainActivity.java

public void onActivityResult(int requestCode, int resultCode, Intent data) {
        
        switch (requestCode) {          
        case REQUEST_ENABLE_BT:
            // When the request to enable Bluetooth returns
            if (resultCode == Activity.RESULT_OK) {
                // 확인 눌렀을 때
                //Next Step
            } else {
                // 취소 눌렀을 때
                Log.d(TAG, "Bluetooth is not enabled");
            }
            break;
        }
}


이제 MainActivity에서 버튼을 클릭했을 때 블루투스 활성화를 위한 이벤트 처리만 해주면 된다.


MainActivity.java

@Override
	public void onClick(View v) {
		if(btService.getDeviceState()) {
			// 블루투스가 지원 가능한 기기일 때
			btService.enableBluetooth();
		} else {
			finish();
		}
	}

여기까지 블루투스를 활성화 하는 방법에 대해서 알아보았다.

블루투스가 활성화 되었을 때(resultCode가 Activity.RESULT_OK일때) 기기 검색을 통해 페어링을 시켜주면 되는데, 이 부분은 다음장에 포스팅 하도록 하겠다.


전체 소스는 다음과 같고, 프로젝트를 첨부파일로 올린다.


EX_Bluetooth(1).zip



MainActivity.java

public class MainActivity extends Activity implements OnClickListener {
	// Debugging
	private static final String TAG = "Main";
	
	// Intent request code
	private static final int REQUEST_CONNECT_DEVICE = 1;
	private static final int REQUEST_ENABLE_BT = 2;
	
	// Layout
	private Button btn_Connect;
	private TextView txt_Result;
	
	private BluetoothService btService = null;
	
	
	private final Handler mHandler = new Handler() {

		@Override
		public void handleMessage(Message msg) {
			super.handleMessage(msg);
		}
		
	};

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		Log.e(TAG, "onCreate");
		
		setContentView(R.layout.main);
		
		/** Main Layout **/
		btn_Connect = (Button) findViewById(R.id.btn_connect);
		txt_Result = (TextView) findViewById(R.id.txt_result);
		
		btn_Connect.setOnClickListener(this);
		
		// BluetoothService 클래스 생성
		if(btService == null) {
			btService = new BluetoothService(this, mHandler);
		}
	}

	@Override
	public void onClick(View v) {
		if(btService.getDeviceState()) {
			// 블루투스가 지원 가능한 기기일 때
			btService.enableBluetooth();
		} else {
			finish();
		}
	}
	
	public void onActivityResult(int requestCode, int resultCode, Intent data) {
        Log.d(TAG, "onActivityResult " + resultCode);
        
        switch (requestCode) {

        case REQUEST_ENABLE_BT:
            // When the request to enable Bluetooth returns
            if (resultCode == Activity.RESULT_OK) {
            	
            } else {

                Log.d(TAG, "Bluetooth is not enabled");
            }
            break;
        }
	}

}


BluetoothService.java

public class BluetoothService {
	// Debugging
	private static final String TAG = "BluetoothService";
	
	// Intent request code
	private static final int REQUEST_CONNECT_DEVICE = 1;
	private static final int REQUEST_ENABLE_BT = 2;
	
	private BluetoothAdapter btAdapter;
	
	private Activity mActivity;
	private Handler mHandler;
	
	// Constructors
	public BluetoothService(Activity ac, Handler h) {
		mActivity = ac;
		mHandler = h;
		
		// BluetoothAdapter 얻기
		btAdapter = BluetoothAdapter.getDefaultAdapter();
	}
	
	/**
	 * Check the Bluetooth support
	 * @return boolean
	 */
	public boolean getDeviceState() {
		Log.i(TAG, "Check the Bluetooth support");
		
		if(btAdapter == null) {
			Log.d(TAG, "Bluetooth is not available");
			
			return false;
			
		} else {
			Log.d(TAG, "Bluetooth is available");
			
			return true;
		}
	}
	
	/**
	 * Check the enabled Bluetooth
	 */
	public void enableBluetooth() {
		Log.i(TAG, "Check the enabled Bluetooth");
		
		
		if(btAdapter.isEnabled()) {		
			// 기기의 블루투스 상태가 On인 경우
			Log.d(TAG, "Bluetooth Enable Now");
			
			// Next Step
		} else {		
			// 기기의 블루투스 상태가 Off인 경우
			Log.d(TAG, "Bluetooth Enable Request");
			
			Intent i = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
			mActivity.startActivityForResult(i, REQUEST_ENABLE_BT);
		}
	}
	
}


다음 글 : 블루투스 기기 검색하기 글 보기



  1. 이전 댓글 더보기
  2. 오류 2014.07.11 15:45 신고

    btn_Connect = (Button) findViewById(R.id.btn_connect);
    txt_Result = (TextView) findViewById(R.id.txt_result);
    여기가 이렇게오류는데 왜 그럴까요 ㅠ,ㅠbtn.connect랑txt_result쪽이 오류가많이나네요
    임포트종류도 많이나와서 어떤걸할지 ㅠ,???

  3. 오류 2014.07.11 15:45 신고

    btn_Connect = (Button) findViewById(R.id.btn_connect);
    txt_Result = (TextView) findViewById(R.id.txt_result);
    여기가 이렇게오류는데 왜 그럴까요 ㅠ,ㅠbtn.connect랑txt_result쪽이 오류가많이나네요
    임포트종류도 많이나와서 어떤걸할지 ㅠ,???

  4. 오류 2014.07.11 15:54 신고

    create field 만들라 그러고 그러는데 어떻게하죵

    • 영상털이범 2014.07.14 08:54 신고

      .. 그 부분은 xml파일이랑 id값을 맞춰주어야 하는 부분인데
      이건 너무 기본적인 부분이라서 제가 직접 설명을 해드리기보다
      책을펴고 기본부터 공부를 하시고 프로젝트를 진행하시는게 맞다고 생각이 듭니다.

  5. 오류 2014.07.14 13:57 신고

    답변 감사드려요 이번에 공부좀 많이 하고 싶어서 그런데 책 추천좀 해주실수 있을까요???

    • 영상털이범 2014.07.14 14:47 신고

      시중에 안드로이드 책이 많이 있기때문에 서점에가서 한번씩 보시고 쉽게 재밌게 나온 책으로 공부하시는 것도 추천하고
      가장 기본적인 책으로는 '안드로이드 프로그래밍 1,2' 를 보시는 것을 추천해 드립니다. 두껍고 총 2권으로 되어있는데 왠만한 내용은 다 들어있기때문에 처음부터 책을 본다는 생각말고 중간에 필요한 내용을 찾아보는 사전처럼 사용하시면 좋을것 같습니다.

  6. 2014.07.31 20:27

    비밀댓글입니다

    • 영상털이범 2014.08.03 19:12 신고

      메일주소는
      dsnight@nate.com 입니다.
      제가 업무상 여유가 될 때 확인하고 도움드리도록 하겠습니다.

  7. 꿈나무 2014.08.01 15:45 신고

    블루투스 플젝을 처음하는데 포스팅이 완전탄탄해서 많은 도움이됐습니다!!

    다름이아니라 블루투스 on/off시에 enableBluetooth()메소드에서 처리를하는데

    이메소드에서 블루투스를 on을했을때 다른기기가 검색할수있는 방법을 찾고있습니다

    현재 BluetoothChat플젝에있는 ensureDiscoverable() 메소드를 참조하고있는데

    블루투스 on/off를 선택하는창 뒤에 미리 떠있더라구요 on/off선택후 기기검색허용 창이 뜨게하고싶은데

    방법이없을까요? 답변부탁드립니다!

    언제나 감사합니다^^

    • 영상털이범 2014.08.03 19:13 신고

      onActivityResult 메소드를 알아보시면
      블루투스 on/off 에서 확인을 클릭했을 경우
      받아오는 이벤트가 있습니다.
      그 부분을 찾아서 on(확인)을 클릭했을 경우
      그 다음동작에 기기검색 메소드를 실행하면 될 것 같습니다.

  8. 꿈나무 2014.08.06 16:53 신고

    지난번 답변 감사했습니다!

    이번엔 Fragment를 이용해서 블루투스를 만드려고하는데

    FragmentActivity에서 다른 Fragment로 이동후 그화면에서

    Fragment-enableBluetooth()메소드를 이용해서 기기활성화는 되는데

    scanDevice()메소드에서 Intent가 말썽입니다.

    Intent() 안에 Activity만 들어가지는지 빨간줄이 없어지질 않아서

    DeviceListActivity를 Fragment클래스로 부르는법 질문드립니다..ㅠ

    여름인데 건강 조심하세요! 감사합니다.

    • 영상털이범 2014.08.06 21:12 신고

      Activity를 상속받은 클래스에서 Intent가 가능할 것 입니다.
      Fragment 클래스로 Context를 넘겨주던지
      핸들러를 사용하여 처리하면 될 것? 같습니다. 지금 떠오르는 생각으로는..
      저 방법이 안되고 정 안되신다면 다시한번 댓글 주시면 적극적으로 해결해 드리겠습니다!

  9. 꿈나무 2014.08.08 10:27 신고

    잘해결했습니다ㅋ바보같이
    <activity
    android:name=".DeviceListActivity"
    android:theme="@android:style/Theme.DeviceDefault.Dialog"/>
    이구문을 빼놓고 구동시키니까 오류가 났었네요..

    다이어로그창이 따로 안뜨고 Activity안에서 검색레이아웃이 뜨게 만드는법 헤딩해보려고 합니다ㅎㅎ

    답글 감사합니다!^^

    • 영상털이범 2014.08.08 16:30 신고

      그 부분은
      android:theme="@android:style/Theme.DeviceDefault.Dialog"
      부분만 지워주시면 다이어로그창이 따로 안뜨고
      하나의 액티비티로 뜨게 됩니다.
      그냥 DeviceListActivity를 통쨰로 옴겨오던지 수정하시면 금방 끝날거 같습니다.

  10. wonmi 2014.08.20 15:42 신고

    이클립스 샘플파일에서 BlueToothChat이 안열립니다........finish버튼이 활성화가 안되요
    (A project with that name already exists in the workspace)라고 메세지가 뜨네요
    도와주세요 ㅠㅠ

    • 영상털이범 2014.08.20 17:23 신고

      이클립스에 같은 이름의 프로젝트가 존재해서 그렇습니다.
      BlueToothChat 이라는 같은 이름의 프로젝트가 존재하기 때문에 안열리는듯 합니다.
      원래 있던 프로젝트의 이름을 변경후에 시도해주세요.

  11. 꿈나무 2014.08.28 16:23 신고

    여름 마지막 더위에 잘지내시는지 모르겠네요ㅋ
    요즘 비콘으로 연동하는법을 찾고있는데 온갖단어로 구글링을 해도 안나오네요..ㅠㅠ
    비콘연동 해보셨는지 궁금합니다!!
    항상 감사합니다!

  12. 사과는금 2014.11.09 22:47 신고

    안드로이드 BluetoothChat 예제 를 해서
    run 해봐도 블루투스 이용 가능 하지 않다고 뜨고
    님이 올려주신 걸로 실행해보아도 이용 가능 하지 않다고 뜨고
    제가 소스보고 따라해봐도 그대론데 어떻게 해야 되나요?ㅠㅠㅠ

  13. 앱을 만들기 시간한 강군 2015.02.25 19:17 신고

    안녕하세요 안드로이드 개발자 강군입니다.
    제가 안드로이드스튜디오로 앱을 개발 중입니다.

    // BluetoothService 클래스 생성
    if(btService == null) {
    btService = new BluetoothService(this, mHandler);
    }
    이부분에 btService = new BluetoothService(this, mHandler); 에러가 발행합니다.
    에러 발생 이유를 보르겠습니다. 블루투스서비스소켓에 대한 안내글이 나오는데 이해가 잘 안되네요.

    추가로 질문이 하나 더있는데
    안드로이드 4.3미만의 버전에서는 블루투스를 이용한 통신을 하려고 합니다.
    4.3이상의 버전과 API가 다르다고 제가 들은거 같은데 위에 작성된 앱은 어떤 버전에서 사용되는 것인가요?
    Bluetooth 4.0 버전, 4.0미만 버전에 대한 통신을 하나의 앱에서 하려고 합니다.
    어떻게 작성해야 할까요?

  14. 2016.04.15 14:15 신고

    포스팅 잘봤습니다~
    따라하고 있는데,
    REQUEST_ENABLE_BT가 빨간 글씨로 뜨는데
    어떻게 해결할 수 있을까요?

  15. 2017.02.13 16:14

    비밀댓글입니다

  16. 끼룩 2017.02.13 17:00 신고

    감사합니다!!!

  17. what 2017.02.23 09:54 신고

    Buetooth 안드로이드 간에 채팅 소스 혹시 올려주실수 있나요?ㅠㅠ

  18. question 2017.03.06 11:13 신고

    이거 연결이 되면 무슨 알람같은게 뜨나요??? 연결 하기 해서 장치 선택했는데 아무 알람이 안떠서.. 된건지 안된건지..

  19. 하정 2017.03.20 00:12 신고

    Error:(21, 28) No resource found that matches the given name (at 'paddingBottom' with value '@dimen/activity_vertical_margin').
    Error:(22, 26) No resource found that matches the given name (at 'paddingLeft' with value '@dimen/activity_horizontal_margin').
    Error:(23, 27) No resource found that matches the given name (at 'paddingRight' with value '@dimen/activity_horizontal_margin').
    Error:(24, 25) No resource found that matches the given name (at 'paddingTop' with value '@dimen/activity_vertical_margin').
    C:\Users\Moi13\AndroidStudioProjects\BluetoothChat2\Application\build\intermediates\res\merged\debug\menu\main.xml
    Error:(21, 28) No resource found that matches the given name (at 'paddingBottom' with value '@dimen/activity_vertical_margin').
    Error:(22, 26) No resource found that matches the given name (at 'paddingLeft' with value '@dimen/activity_horizontal_margin').
    Error:(23, 27) No resource found that matches the given name (at 'paddingRight' with value '@dimen/activity_horizontal_margin').
    Error:(24, 25) No resource found that matches the given name (at 'paddingTop' with value '@dimen/activity_vertical_margin').


    안드로이드 스튜디오의 위 에러는 대체 어떻게 해결해야 할까요 ㅠㅠㅠ

  20. 촠봌 2018.05.26 23:43 신고

    감사합니다.
    덕분에 안되는 부분 해결했어요!!!!!!!!!!!

  21. 화랑 2018.08.06 15:06 신고

    WARNING: Configuration 'compile' is obsolete and has been replaced with 'implementation' and 'api'.

    샘플 프로젝트를 임포트하는 과정에서 위와 같은 에러 일때 전부 implementation으로 바꿔 주었는데 HC-06모듈과 연결이 안되는데 따로 더 수정해야하는것이 있을까요/????

 안드로이드 프로그래밍에서 어플만의 UI를 갖는것은 필수라고 생각한다.

 앱의 기능은 구글링을 통해서 어느정도 구현을 할 수가 있는데, 똑같은 기능을 갖고 있는 앱 중에서 UI가 이쁜 앱과 UI가 평범한 앱중에는 당연히 UI가 이쁜 앱을 쓰지 않을까??

 독특한 특색을 갖는 UI를 꾸미기 위해서 이번에는 액션바를 활용해 보겠다. (커스텀하게 액션바를 만드는 내용은 다음에 시간날때 올리도록 하겠다..)


 글쓴이의 경우 앱에 액션바를 사용하였는데 액션바에 배경이미지를 넣고 사용하기 위해 커스텀하게 구현을 하였다. 버튼역시 테마에 맞게 이미지를 넣어 구현을 하였다. 


 이때 문제가 발생하였는데 이미지를 넣은 버튼을 배치했을 때 디바이스에 따라 해상도가 모두 다르기 때문에 버튼의 크기가 제 각각 이었다. 

 액션바의 크기는 모든 디바이스에서 비율이 똑같을 것이라고 생각하고 크기를 절대값으로 조절하였더니 문제가 생긴것이다. 해상도에 따라서 액션바의 크기도 제각각이었다. 그래서 액션바의 크기를 구해서 버튼크기를 조절하려고 했다. 그러나 액션바의 크기가 0으로 나와서 크기를 알 수 가 없었다.

 그렇다.. 액션바의 크기는 0이었던 것이다.. 

 하지만 액션바의 크기를 구할 수 있는 방법이 있다!!

 액티비티가 실행될 때 onCreate 안에서 액션바의 크기를 구하면 0이 나오지만, 스레드를 이용하면 크기를 구할수 있다.

 일단 Action Bar 와 Status Bar 크기를 구하는 코드부터 살펴보자


private void getStatusBarSize() {
	Rect rectgle = new Rect();
	Window window = getWindow();
	window.getDecorView().getWindowVisibleDisplayFrame(rectgle);
	int StatusBarHeight = rectgle.top;
	int contentViewTop = window.findViewById(Window.ID_ANDROID_CONTENT).getTop();
	int TitleBarHeight = contentViewTop - StatusBarHeight;
	
	Log.i("getHeight", "StatusBar Height= " + StatusBarHeight + " TitleBar Height = " + TitleBarHeight);
}

위의 메소드를 onCreate 안에서 호출하지말고 스레드를 통해서 호출한다.


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

	LinearLayout layout = new LinearLayout(this);
	layout.post(new Runnable() {
		@Override
		public void run() {
			getStatusBarSize();
		}
	});
}


스레드를 통해서 getStatusBarSize를 호출하면 크기를 구할 수 있다.


여기서 또 한가지 팁은 액션바 사이즈를 구해서 액션바 사이즈를 이용해서 액션바에 들어가는 버튼이나 이미지 크기를 조절하려면 onCreate안에서 계산하면 안된다. 스레드를 통해서 크기를 구하기 때문에 onCreate가 끝나고 크기가 구해질 수 가 있기 때문에 액션바에 들어가는 버튼의 크기를 조절하고자 한다면 스레드 안에서 getStatusBarSize()를 호출하고 난 뒤에 크기를 조절해 주도록 하자!


액션바를 커스텀하게 만드는 방법은 다음에 자세히 포스팅 하도록 하겠다.


안드로이드 앱의 폴더와 서버의 폴더 생성 시간을 비교하고 변경하여 동기화 하는 작업을 수행하는 도중 setLastModified() 메소드가 제대로 작동하지 않았다. 

폴더의 생성시간에 접근을 하는 메소드는 setLastModified()가 맞는데 몇번을 수행하여도 폴더의 시간이 변경되지 않았다.


setLastModified()의 반환형이 boolean 형임을 파악하고 Log를 계속 찍어보았다.

return 값은 계속해서 false...


실행한 디바이스는 갤럭시 탭 10.1로 안드로이드 4.0 버전이었다.


분명히 폴더시간이 바뀌어야 되는데 바뀌지 않았다. 구글링을 한 결과 setLastModified() 메소드가 일부 디바이스에서 작동하지 않는다는 답변이 있었다. 


아마도 삼성제품에 대다수 해당되는 것 같았다. 해킹이나 버그를 방지하기 위해서 접근하지 못하게 해놓았다는 답변이다. 정말 거지같다..


결국 SDcard의 폴더 생성시간은 변경할 수 없다.


폴더 생성시간을 변경을 하지는 못하고, 서버의 폴더 생성 시간과 비교를 하기 위해서는 따로 DB를 만들거나 또 다른 편법을 써야할 것 같다..


이 문제로 고민하는 분이 없길 바란다...

NDK를 사용할 시 ndk-build를 이클립스에서 편하게 할 수 있는 방법에 대해서 알아보도록 하겠다.

NDK-build를 하여 .so파일을 생성할 때 cmd창이나 cygwin 터미널을 이용하지 않고 이클립스에서 편하게 할 수 있다.


먼저 생성한 프로젝트의 [Properties] -> [Builders] -> [New] 를 선택한다.



Program 선택


이름은 NDK_Builder로 하였다. 

Location에는 Browse File System을 선택하여 ndk-build가 있는 위치를 지정해준다.

Working Directory는 현재 프로젝트의 위치를 지정해주면 되는데 Browse Workspace를 선택하여 해당 프로젝트를 선택해준다.


다음은 같은 창에서 Refresh를 선택하고 아래 그림과 같은 순서로 선택한다. 3번을 선택하면 새 창이 뜨는데 해당 프로젝트 파일의 jni 폴더를 선택해 준다.


다음은 Build Options로 넘어가겠다. 1번은 선택사항이다. 자동으로 빌드를 하는건데 컴퓨터가 느려지길 원하지 않는다면 선택을 하지 않아도 된다. 1번을 제외한 나머지 항목은 필수로 선택을 한다. 여기서는 해당 프로젝트의libs 폴더를 선택한다. 


설정이 완료 되었다. 이제 프로젝트를 빌드해보자.


콘솔창에 다음과 같이 나왔다면 빌드에 성공한것이다.


.c 혹은 .cpp파일의 내용이 변경되었을 경우는 [Project] -> [Clean] 에서 해당 프로젝트만 Clean을 해주고 다시 디버깅을 하면 된다.


이제 cmd창에 입력할 필요 없이 이클립스에서 clean -> Debug로 간단하게 ndk build를 할 수 있다.

하지만 이후에 다른 프로젝트에서 똑같은 방법으로 했을 경우 이름이 중복된다는 경고를 볼 수 있다. 그럴때는 Builder의 이름을 NDK_Builder(2) 이런식으로 바꿔주도록 하자. 왜 굳이 따로 또 만들어야 되는지는 모르겠다.. 


이 문제를 해결할 방법을 아시는분은 알려주세요~!^^



  1. 김병섭 2014.08.18 21:37 신고

    안녕하세요?
    안드로이드에서 open cv 라이브러리를 사용하기위해 ndk를 설치하고
    빌드까지 해보려고 안드로이드 프로젝트를 생성하고
    글에서 제시해 주신대로 따라가고 있었습니다.

    그런데.. 제 프로젝트에는 'jni'폴더가 따로 생성되지 않더군요..
    프로젝트를 생성할 때 다른 방법으로 생성해 주어야 하는 건가요??

  2. dpszlfk 2015.04.27 10:23 신고

    안녕하세요 글 보고 쉽게 NDK 빌드 설정했습니다. 감사합니다.

    이제 처음 시작하는 입장이라 조심스럽습니다만...

    이름 중복 문제는 NDK_Builder를 만들 때 Working Directory에 .externalToolBuilders 폴더가 생기고
    폴더 안에 '빌드이름.launch' 파일이 생기는데, 이 파일을 지우면 중복 문제는 해결이 될 것 같습니다.
    물론... 설정해논 빌드가 지워지긴 합니다...ㅎㅎ

  3. 2015.08.12 15:07

    비밀댓글입니다

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 하기



  1. 2014.09.27 11:39

    비밀댓글입니다

    • 영상털이범 2014.10.01 15:46 신고

      setContentView(R.layout.main)은 main이라는 이름의 레이아웃을 사용하겠다는 뜻이고
      main.xml안에
      id가 tv_result인 TextView를 직접 만들어주셔야 합니다.
      아주 기본적인 내용이기에 어떻게 설명해야되는지 모르겠는데..
      일단 안드로이드 책을 보시면서 처음부터 공부하시고 NDK는 나중에 접근하시는것을 추천합니다.

      또한 참고로 말씀드리자면 R.java파일은 절대로 건드리시면 안됩니다.

  2. 2014.10.09 00:36

    비밀댓글입니다

  3. kim 2014.11.14 10:46 신고

    설치부터 알려주신대로 소스 전부 입력했는데요
    MainActivity class에서 stringFromJNI()부분에서 에러가 납니다.
    해당 메소드가 없다는 뜻인거 같은데
    jni에 파일을 만들어 줫음에도 빨간줄이 뜨는 이유와 빌드를 했을때 so파일을 나타났는데
    이대로 실행이 가능한지 여부를 알고 싶습니다.

안드로이드 프로그래밍에서 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 하기


  1. 궁금이 2014.08.18 10:00 신고

    PATH 에 include 폴더를 추가하는 이유가 뭔가요?

 안드로이드에서 음성인식 기능을 구현하기 위해서는 구글의 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]으로 첫번째 나온 값만 받을수 있다.

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



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


  1. dkdk 2014.04.07 17:44 신고

    음성녹음과 동시에 작동하는거 성공하셨나요?

    • 영상털이범 2014.04.07 21:33 신고

      실제로 작품에 음성인식과 녹음을 동시에 사용하려고 하다가 포기를 했는데, 이유는 다음과 같습니다.
      1. 정확도가 높은 음성인식 결과를 받기위한 인식거리가 짧다.
      2. 쉬지않고 말을 했을경우 엄청나게 긴 음성이 입력이 되는데, 이 음성데이터의 결과값이 반환되는데 너무 많은 시간이 걸린다.
      3. 일정 Db(소리크기)이상의 음성이 입력되지 않을경우 자동으로 음성인식이 종료되고 결과가 반환된다. 음성 인식 종료시 바로 음성인식을 실행시켜 보았으나, 2~4회 반복후 음성인식이 먹히지 않는다.

      위의 3가지 이유 때문에 시도하다가 말았습니다. 3번 문제는 어떻게 해결 할 수 있을거 같은데, 1,2번 문제로 포기를 하였습니다.
      실제 사용은 간단한 단어를 인식하는데 쓰면 좋을것 같습니다.

  2. 대학생1 2014.11.22 22:30 신고

    음성인식으로 뭔가 만들어보려고 찾아다니다 왔는데 굉장히 쉽게 잘설명해주셨네요, 정말 감사합니다! 다른 글들도 잘 읽어볼게요

  3. 쩌네요. 2015.01.08 21:13 신고

    잘되네요 .. 잘 정리해주셔서 감사합ㄴ다.

  4. 대학생2 2015.02.04 06:25 신고

    혹시 이파일좀구할수있을까요?

  5. 앱만드는 대학생 2015.04.01 23:12 신고

    감사합니다. 덕분에 원하던 정보를 찾았네요.

  6. 질문 2015.04.11 16:23 신고

    안녕하세요. 음성인식 관련해서 앱 제작중인데 한가지 궁금한게 있어서 질문드려요.
    해당 코드는 버튼을 눌렀을때 음성인식을 하도록 작성하셨는데,
    Activity가 화면에 뜨자마자 음성인식을 하려면 어떻게 해야할까요??
    답변 부탁드려요...

    • 관리자 2015.04.13 09:08 신고

      MainActivity의 소스중
      9줄 짜리 소스랑 3줄 짜리 소스를
      쭉 이어서 쓰시면 됩니다.

    • 질문 2015.04.15 19:29 신고

      감사합니다!

  7. 질문자 2015.04.21 00:01 신고

    안녕하세요....안드로이드 구글 음성입력 후 한글자판으로 남게 하는 방법이나 소프트웨어가 있는지 알려주세요

    구글 음성 입력후 수정을 하려면 영문으로 자판이 바뀌어서 다시 한글로 바꾼후 사용을 해야 합니다.
    이를 막기 위한 것 입니다.

  8. 질문자 2015.04.21 00:03 신고

    메일로 답변 주시면 감사하겠습니다. asinfherr@gmail.com ^_^

  9. zelaw 2015.08.14 00:01 신고

    제가 구현하고 싶은 것은 온라인음성인식이 아닌 누란스엔젠을 기반으로 한 구글내장음성인식입니다. 혹 이와 관련된 api가 있으면 소개 해 주시면 감사하겠습니다.
    해당 블로그의 api로도 제가 구현하고자 하는 기능을 구현 할 수 있겠으나,
    궁극적인 목표는 '데이터 없이도' 음성명령을 내리도록 하고 싶습니다.
    예를 들어 베가 아이언의 내장음성명령 정도를 들 수 있습니다.
    혹시 아시는 것 있으면 부탁드립니다.

  10. 학생 2015.10.16 04:55 신고

    덕분에 액티비티 전환없이 구현했습니다.
    그런데 혹시 스타트하면 들리는 beep음을 제거하는 방법이 있을까요

  11. 질문학생 2015.11.11 23:29 신고

    좋은 정보 잘 봤습니다. :)

    혹시 인터넷이 안되도 스마트폰 자체 내장음성인식 기능을 활용할 수 있는 API나 Library? 에 대한 정보 있으면 얻을 수 있을까요?

    그리고 보통 음성인식후 텍스트로 나타나게 되면, 발음이 '말도 안되게 이상했을 경우' 그 발음과 가장 흡사한 '말이 되는 단어 or 문장'으로 텍스트를 출력해주던데,

    그렇게 말고 그냥 발음한 그대로 출력하게끔 하는 음성인식 API가 혹시 있을까요?

    도움 주시면 감사하겠습니다. 혹시몰라 메일 남기겠습니다. djfrhkd1004@naver.com

  12. 궁금한게 있는데 2016.01.15 10:27 신고

    음성인식 사용할 경우 어떤 앱에서는 비슷한 단어라며 여러개 보여주던데요

    예를들어.. 안녕하세요 라고 말하면

    언녕하세요
    안녕하세요
    안영하세요

    이렇게 리스트를 보여주고 여기서 고르게끔 하는데
    이런건 어떻게 구현하나요? api자체 기능인가요?

  13. ^^& 2016.04.04 00:41 신고

    안녕하세요 음성인식자료 잘봤습니다!!
    실행도 됐구요 질문이 있는데요 혹시 stt로 얻은 결과값과 영상과 동시에 합쳐지는 것도 가능한건가요?

  14. 4학년할모이 2016.04.21 14:11 신고

    혹시 "92 다시 일"이라고 인식 한 것을 "92-1"로 변환하여 검색 할 수있을까요? 말하기 버튼을 누르면 음성인식이 되고 그 스트링을 editText 안에 들어가게 하고 검색하는 기능을 구현하려 하는데 하이픈은 한글로만 인식이 되더라구요ㅠㅠ

  15. 2016.07.24 13:19

    비밀댓글입니다

  16. lee 2017.08.09 14:58 신고

    안녕하세요 음성인식자료 잘봤습니다
    안드로이드 공부하는데 유익한 자료가 될거같습니다.
    감사합니다

  17. 2017.08.10 17:44

    비밀댓글입니다

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



 구현방법은 간단하다 뒤로가기 버튼 클릭시 현재시간을 저장하며 토스트 알림창을 띄워주고 한번더 눌렀을때 일정시간(예를들면 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();
	}
}

  1. nhs0912 2014.07.31 16:06 신고

    근데 이거 현재시간 초가 0~2초 사이에 뒤로가기 버튼을 누르면 그냥 그대로 종료 되는거 아닌가요?

    • 영상털이범 2014.08.03 19:11 신고

      맨 처음 뒤로가기 버튼을 눌렀을 때의 시간을 저장해 놓고
      그 뒤에 뒤로가기 버튼을 눌럿을 때 시간차이를 비교해서
      시간차이가 0~2초 사이일 때 종료가 됩니다.

  2. 썽민 2015.03.03 19:41 신고

    처천재다;;

  3. 2015.05.01 17:13

    비밀댓글입니다

  4. aaa 2015.07.20 19:52 신고

    굿!! 좋은 자료 감사합니다!

  5. newkie 2015.10.19 13:56 신고

    감사합니다.

  6. 평행이론 2016.01.14 10:01 신고

    잘봤어요 저랑 같은 스팩을 가지고 계신분이네요.~

  7. 실버파파 2016.03.18 15:08 신고

    좋은 정보 공유 감사합니다. ^^

  8. 행인 2016.06.28 11:27 신고

    도움이 되는 글 감사합니다~

  9. 김호석 2016.10.10 16:10 신고

    좋은 정보 감사합니다.

  10. 2017.01.10 01:52

    비밀댓글입니다

  11. 신재호 2017.03.22 01:50 신고

    뒤로가기 두번 눌러 앱종료하기
    정말 너무 유용했습니다.. 가뭄에 단비같은 ...ㅎㅎ
    혹시. 뒤로가기 두 번 눌렀을 때 종료확인 창이 뜨게 하는 소스를 알려주실 수 있으신가요?
    예를 들어 back키 두번 눌렀을 때 "종료하시겠습니까? " O or X 누를 수 있는 창이요..ㅠㅠ
    back키 두번 누르는 소스에서 무엇을 더 추가해야되는지 알려주시면 정말 감사하겠습니다.!!
    혹시 메일로 답장 해주시는 거면
    mosi12@naver.com 입니다! 정말 부탁드립니다.!

  12. 김병희 2017.07.15 00:38 신고

    잘 쓰겠습니다.
    감사합니다.

  13. 감사합니다 2018.06.17 18:00 신고

    감사합니다 유용하게 잘 봤습니다. 한가지 BackPressCloseHandler.java 에서 Toast.cancel();을 activity.finish();보다 늦게 실행시키면 에러가 뜨는데 사용환경에 따라 다른건지 궁금하네요!

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

 블루투스 통신을 찾다보면 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