검색결과 리스트
안드로이드/애플리케이션 제작에 해당되는 글 30건
- 2015.08.24 Handler와 Message를 활용하여 콜백함수 구현하기
- 2015.02.08 안드로이드 기기 간에 Wifi Socket 통신하기 14
- 2015.02.07 USB를 연결한 후 Logcat이 바로 보이지 않을 때 해결방법
- 2015.02.05 xml graphical layout가 정상적으로 동작하지 않을 때
- 2015.02.03 XML의 Graphical Layout이 보이지 않는 경우 해결법
- 2014.12.07 Extract contour area using OpenCV in Android(OpcnCV에서 검출된 영역의 넓이 구하기)
- 2014.12.06 Color detection using Android openCV(안드로이드 OpenCV로 특정 색깔 인식) 3
- 2014.12.01 Use front camera with OpenCV 2.4.9 for android(안드로이드 OpenCV에서 전면카메라 적용 방법) 2
- 2014.11.20 블루투스를 통해 이미지를 바이트로 전송하기 38
- 2014.11.16 [NDK] openCV jni 소스 헤더파일이 include 되지 않을 때 해결방법
- 2014.10.06 <Project name> does not specify a android.test.InstrumentationTestRunner instrumentation or does not declare uses-library android.test.runner in its AndroidManifest.xml
- 2014.10.03 MediaPlayer, VideoView 재생이 끝났을 때 이벤트 처리하기 (setOnCompletionListener)
글
Handler와 Message를 활용하여 콜백함수 구현하기
안드로이드 프레임워크를 분석하던 도중 흥미로운 부분을 발견하게 되어 이를 소개하고자 합니다. 물론 이는 안드로이드의 Application 단계에서도 쉽게 구현될 수 있는 기능이기에 안드로이드 애프리케이션 제작에 어느 정도 경험이 있으신 분들이라면 쉽게 이해하실 수 있으시리라 생각합니다.
이번에 다루고자 하는 핵심적인 개념은 바로 Callback 입니다. 그럼 여기서 Callback 이란 무엇인지 간단하게 설명하도록 하겠습니다.
Callback이란?
일반적으로 우리들이 프로그래밍을 설계할 때 Method와 같은 함수를 구현합니다. 특히 API와 같이 원하는 기능이 미리 구현되어 있어 해당 함수를 호출하는 것으로 원하는 기능을 실행하기도 하지요. Callback 또한 일반적인 함수들과 비슷하게 구성되어 있습니다. Android의 경우 프로그래머가 구현하고자 하는 기능을 Listener Interface를 통해 Callback 기능을 등록해줍니다.
Callback 함수가 일반 함수와 가장 큰 차이점으로 호출되는 시점에 있습니다. 일반적인 함수의 경우 프로세스가 해당 함수를 호출하면 호출되는 즉시 해당 기능을 수행하게 됩니다. 반면 Callback 함수의 경우 프로세서가 호출을 요청할 경우 일반 함수처럼 즉시 호출될 수도 있지만 프로세스의 동작과는 독립적으로 동작하는 것이 가능하여 해당 프로세스가 수행을 종료한 후에 Callback 함수를 실행시킬 수 있습니다.
안드로이드 Framework에서 Runnable Interface를 통해 Callback 기능을 구현한 방법이 있어 해당 기능을 분석해 보았습니다. 특이하게도 안드로이드에서 지원하는 Looper와 Message를 활용해서 구현하였다는 점인데요 쉽게 설명을 드리자면 실행하고자 하는 함수를 Runnable Interface를 통해 구현한 후 이를 Mssage를 통해 해당 함수를 예약해 두었다가 이후 프로세스가 작업을 종료하게 되었을 때 해당 함수를 호출하는 방식입니다.
자세한 구현 내용을 실제 소스코드를 통해 확인해보도록 합시다.
/framework/base/core/java/android/view/Choreographer.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 | public final class Choreographer { .... // Choreographer를 초기와 합니다. 인자로 Choreographer의 Looper를 넘겨줍니다. // Thread local storage for the choreographer. private static final ThreadLocal<Choreographer> sThreadInstance = new ThreadLocal<Choreographer>() { @Override protected Choreographer initialValue() { Looper looper = Looper.myLooper(); if (looper == null) { throw new IllegalStateException("The current thread must have a looper!"); } return new Choreographer(looper); } }; .... private final Looper mLooper; private final FrameHandler mHandler; // The display event receiver can only be accessed by the looper thread to which // it is attached. We take care to ensure that we post message to the looper // if appropriate when interacting with the display event receiver. private final FrameDisplayEventReceiver mDisplayEventReceiver; .... private Choreographer(Looper looper) { //Constructor를 통해 Looper를 받는다. mLooper = looper; //Constructor를 통하여 얻게 된 Looper를 FrameHadler에 등록한다. mHandler = new FrameHandler(looper); mDisplayEventReceiver = USE_VSYNC ? new FrameDisplayEventReceiver(looper) : null; .... } } .... } //Callback 기능을 수행할 Hndler입니다. //Callback 기능 구현시 handlerMessage(Message msg) 함수는 실행되지 않습니다. private final class FrameHandler extends Handler { public FrameHandler(Looper looper) { super(looper); } @Override public void handleMessage(Message msg) { switch (msg.what) { case MSG_DO_FRAME: doFrame(System.nanoTime(), 0); break; case MSG_DO_SCHEDULE_VSYNC: doScheduleVsync(); break; case MSG_DO_SCHEDULE_CALLBACK: doScheduleCallback(msg.arg1); break; } } } //Callback 기능을 구현하고자 하는 부분입니다. //Runnable Interface로 구현하고자 하는 Callback 함수를 run() 함수로 구성합니다. private final class FrameDisplayEventReceiver extends DisplayEventReceiver implements Runnable { private boolean mHavePendingVsync; private long mTimestampNanos; private int mFrame; public FrameDisplayEventReceiver(Looper looper) { super(looper); } @Override public void onVsync(long timestampNanos, int builtInDisplayId, int frame) { .... mTimestampNanos = timestampNanos; mFrame = frame; //Message를 통해 Callback 기능 구현 //Callback 함수를 Message에 등록합니다. //mHandler : Message를 받을 Looper를 갖고 있는 Handler //this : 등록하고자 하는 함수. 해당 기능은 Runnable Interface를 통하여 run() 함수로 구성됨 Message msg = Message.obtain(mHandler, this); msg.setAsynchronous(true); //Message를 Handler에 전송합니다. Handler는 Message를 받은 후 현재 프로세스가 작업을 // 종료하면 이후 해당 Callback 기능을 실행합니다. mHandler.sendMessageAtTime(msg, timestampNanos / NANOS_PER_MS); } //실행하고자 하는 Callback 함수 @Override public void run() { mHavePendingVsync = false; doFrame(mTimestampNanos, mFrame); } } | cs |
위에서 구현된 함수를 이미지로 나타내면 다음과 같습니다.
'안드로이드 > 애플리케이션 제작' 카테고리의 다른 글
저장된 사진및 파일이 보이지 않을 때 미디어스캐닝(Media Scanning) 방법 [Kitkat 이후의 버전에서 적용방법] (0) | 2015.10.04 |
---|---|
byte[] 바이트 배열을 socket을 통해 쉽게 전송하는 방법 (0) | 2015.10.03 |
안드로이드 기기 간에 Wifi Socket 통신하기 (14) | 2015.02.08 |
USB를 연결한 후 Logcat이 바로 보이지 않을 때 해결방법 (0) | 2015.02.07 |
xml graphical layout가 정상적으로 동작하지 않을 때 (0) | 2015.02.05 |
설정
트랙백
댓글
글
안드로이드 기기 간에 Wifi Socket 통신하기
※해당 포스팅의 내용은 Java로 작성되어 있습니다. 본 내용을 Kotlin으로 다시 설계하여 보다 향상된 버전의 내용을 확인하고 싶으신 분들은 아래의 주소로 이동해주세요.
최근 사물인터넷이 주목을 받게 되면서 휴대전화 이외의 기기에 안드로이드 OS가 적용되는 사례가 증가하고 있습니다. 이로 인해 기존 휴대기기에서 사용되지 않던 안드로이드 Server라는 개념이 등장하기도 합니다. 이번 포스팅에서는 Wifi를 활용한 간단한 Wifi 통신에 대해 다루어볼까 합니다. 아래의 예제를 통해서 안드로이드 기기에서 Wifi socket 통신을 즐겨보는 기회를 가져보도록 하겠습니다.
먼저 AndroidMenifest.xml에 통신 관련 권한을 추가해 줍니다.
AndroidMenifest.xml
1 2 3 4 5 6 7 | <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="19" /> <uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> <uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/> | cs |
string.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | <?xml version="1.0" encoding="utf-8"?> <resources> <string name="app_name">FW</string> <string name="hello_world">Hello world!</string> <string name="action_settings">Settings</string> <string name="ip">IP</string> <string name="port">PORT</string> <string name="name">NAME</string> <string name="button1">Connect!</string> <string name="button2">Disconnect!</string> <string name="button3">Set Server!</string> <string name="button4">close Server!</string> <string name="button5">View info!</string> <string name="button6">Msg</string> </resources> | cs |
activity_main.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 | <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_alignParentTop="true" android:layout_centerHorizontal="true" android:orientation="vertical" > <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" > <TextView android:id="@+id/textView1" android:layout_width="60dp" android:layout_height="wrap_content" android:text="@string/ip" /> <EditText android:id="@+id/editText1" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:hint="" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" > <TextView android:id="@+id/textView2" android:layout_width="60dp" android:layout_height="wrap_content" android:text="@string/port" /> <EditText android:id="@+id/editText2" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:hint="" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" > <TextView android:id="@+id/textView3" android:layout_width="60dp" android:layout_height="wrap_content" android:text="@string/name" /> <EditText android:id="@+id/editText3" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:hint="" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" > <Button android:id="@+id/button1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="OnClick" android:text="@string/button1" /> <Button android:id="@+id/button2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="OnClick" android:text="@string/button2" /> <Button android:id="@+id/button6" android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="OnClick" android:text="@string/button6" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" > <Button android:id="@+id/button3" android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="OnClick" android:text="@string/button3" /> <Button android:id="@+id/button4" android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="OnClick" android:text="@string/button4" /> <Button android:id="@+id/button5" android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="OnClick" android:text="@string/button5" /> </LinearLayout> <TextView android:id="@+id/textView4" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="TextView" /> </LinearLayout> | cs |
MainActivity.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 | package com.example.fw; import android.app.Activity; import android.content.Context; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; import android.os.Bundle; import android.os.Handler; import android.text.format.Formatter; import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; import java.io.DataInputStream; import java.io.DataOutputStream; import java.net.ServerSocket; import java.net.Socket; public class MainActivity extends Activity { private EditText et1, et2, et3; private TextView tv4; private Socket socket; private DataOutputStream writeSocket; private DataInputStream readSocket; private Handler mHandler = new Handler(); private ConnectivityManager cManager; private NetworkInfo wifi; private ServerSocket serverSocket; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); et1 = (EditText) findViewById(R.id.editText1); et2 = (EditText) findViewById(R.id.editText2); et3 = (EditText) findViewById(R.id.editText3); tv4 = (TextView) findViewById(R.id.textView4); cManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); } @SuppressWarnings("deprecation") public void OnClick(View v) throws Exception { switch (v.getId()) { case R.id.button1: (new Connect()).start(); break; case R.id.button2: (new Disconnect()).start(); break; case R.id.button3: (new SetServer()).start(); break; case R.id.button4: (new CloseServer()).start(); break; case R.id.button5: wifi = cManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI); if (wifi.isConnected()) { WifiManager wManager = (WifiManager) getSystemService(Context.WIFI_SERVICE); WifiInfo info = wManager.getConnectionInfo(); tv4.setText("IP Address : " + Formatter.formatIpAddress(info.getIpAddress())); } else { tv4.setText("Disconnected"); } break; case R.id.button6: (new sendMessage()).start(); } } class Connect extends Thread { public void run() { Log.d("Connect", "Run Connect"); String ip = null; int port = 0; try { ip = et1.getText().toString(); port = Integer.parseInt(et2.getText().toString()); } catch (Exception e) { final String recvInput = "정확히 입력하세요!"; mHandler.post(new Runnable() { @Override public void run() { // TODO Auto-generated method stub setToast(recvInput); } }); } try { socket = new Socket(ip, port); writeSocket = new DataOutputStream(socket.getOutputStream()); readSocket = new DataInputStream(socket.getInputStream()); mHandler.post(new Runnable() { @Override public void run() { // TODO Auto-generated method stub setToast("연결에 성공하였습니다."); } }); (new recvSocket()).start(); } catch (Exception e) { final String recvInput = "연결에 실패하였습니다."; Log.d("Connect", e.getMessage()); mHandler.post(new Runnable() { @Override public void run() { // TODO Auto-generated method stub setToast(recvInput); } }); } } } class Disconnect extends Thread { public void run() { try { if (socket != null) { socket.close(); mHandler.post(new Runnable() { @Override public void run() { // TODO Auto-generated method stub setToast("연결이 종료되었습니다."); } }); } } catch (Exception e) { final String recvInput = "연결에 실패하였습니다."; Log.d("Connect", e.getMessage()); mHandler.post(new Runnable() { @Override public void run() { // TODO Auto-generated method stub setToast(recvInput); } }); } } } class SetServer extends Thread { public void run() { try { int port = Integer.parseInt(et2.getText().toString()); serverSocket = new ServerSocket(port); final String result = "서버 포트 " + port + " 가 준비되었습니다."; mHandler.post(new Runnable() { @Override public void run() { // TODO Auto-generated method stub setToast(result); } }); socket = serverSocket.accept(); writeSocket = new DataOutputStream(socket.getOutputStream()); readSocket = new DataInputStream(socket.getInputStream()); while (true) { byte[] b = new byte[100]; int ac = readSocket.read(b, 0, b.length); String input = new String(b, 0, b.length); final String recvInput = input.trim(); if(ac==-1) break; mHandler.post(new Runnable() { @Override public void run() { // TODO Auto-generated method stub setToast(recvInput); } }); } mHandler.post(new Runnable(){ @Override public void run() { // TODO Auto-generated method stub setToast("연결이 종료되었습니다."); } }); serverSocket.close(); socket.close(); } catch (Exception e) { final String recvInput = "서버 준비에 실패하였습니다."; Log.d("SetServer", e.getMessage()); mHandler.post(new Runnable() { @Override public void run() { // TODO Auto-generated method stub setToast(recvInput); } }); } } } class recvSocket extends Thread { public void run() { try { readSocket = new DataInputStream(socket.getInputStream()); while (true) { byte[] b = new byte[100]; int ac = readSocket.read(b, 0, b.length); String input = new String(b, 0, b.length); final String recvInput = input.trim(); if(ac==-1) break; mHandler.post(new Runnable() { @Override public void run() { // TODO Auto-generated method stub setToast(recvInput); } }); } mHandler.post(new Runnable(){ @Override public void run() { // TODO Auto-generated method stub setToast("연결이 종료되었습니다."); } }); } catch (Exception e) { final String recvInput = "연결에 문제가 발생하여 종료되었습니다.."; Log.d("SetServer", e.getMessage()); mHandler.post(new Runnable() { @Override public void run() { // TODO Auto-generated method stub setToast(recvInput); } }); } } } class CloseServer extends Thread { public void run() { try { if (serverSocket != null) { serverSocket.close(); socket.close(); mHandler.post(new Runnable() { @Override public void run() { // TODO Auto-generated method stub setToast("서버가 종료되었습니다.."); } }); } } catch (Exception e) { final String recvInput = "서버 준비에 실패하였습니다."; Log.d("SetServer", e.getMessage()); mHandler.post(new Runnable() { @Override public void run() { // TODO Auto-generated method stub setToast(recvInput); } }); } } } class sendMessage extends Thread { public void run() { try { byte[] b = new byte[100]; b = "Hello, World!".getBytes(); writeSocket.write(b); } catch (Exception e) { final String recvInput = "메시지 전송에 실패하였습니다."; Log.d("SetServer", e.getMessage()); mHandler.post(new Runnable() { @Override public void run() { // TODO Auto-generated method stub setToast(recvInput); } }); } } } void setToast(String msg) { Toast.makeText(this, msg, Toast.LENGTH_SHORT).show(); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); if (id == R.id.action_settings) { return true; } return super.onOptionsItemSelected(item); } } | cs |
※자신의 안드로이드기기를 Server로 설정하고 싶을떼
1.PORT에 자신이 설정하고자 하는 PORT 번호를 입력한다.
2.'Set Server!' 버튼을 누르면 해당 안드로이드 기기가 Server의 역할을 맡게 된다.
3.'View info!' 버튼을 눌러 해당 안드로이드 기기의 IP 주소를 확인한다.
※자신의 안드로이드 기기를 Client로 설정하고 싶을때
1.위에서 확인한 Server로 설정한 안드로이드 기기의 IP주소를 확인한 후 IP 칸에 해당 주소를 입력한다.
2.Server에서 설정한 Port 번호를 입력한다.
3.'Connect!'버튼을 눌러 접속을 시도한다.
'안드로이드 > 애플리케이션 제작' 카테고리의 다른 글
byte[] 바이트 배열을 socket을 통해 쉽게 전송하는 방법 (0) | 2015.10.03 |
---|---|
Handler와 Message를 활용하여 콜백함수 구현하기 (0) | 2015.08.24 |
USB를 연결한 후 Logcat이 바로 보이지 않을 때 해결방법 (0) | 2015.02.07 |
xml graphical layout가 정상적으로 동작하지 않을 때 (0) | 2015.02.05 |
XML의 Graphical Layout이 보이지 않는 경우 해결법 (0) | 2015.02.03 |
설정
트랙백
댓글
글
USB를 연결한 후 Logcat이 바로 보이지 않을 때 해결방법
간혹가다 안드로이드 기기를 USB에서 분리하였다가 연결한 후 Logcat을 보려 하였을 때 Logcat이 보이지 않는 경우가 종종 있습니다. 이 경우 DDMS를 키신 후 자신의 Device를 선택하는 메뉴에서 클릭을 하시면 손쉽게 해결하실 수 있습니다.
eclipse 오른쪽 윗 부분의 아이콘을 보시면 Open Perspective라는 메시지가 보이는 아이콘이 있습니다. 해당 아이콘을 클릭하신 후
여기서 DDMS를 선택하신 후 확인 버튼을 누르시면 DDMS 선택메뉴가 추가된 것을 확인하실 수 있습니다. DDMS를 선택하시면 현재 컴퓨터에 연결된 기기의 리스트를 보실 수 있습니다. 만약 이 때 자신의 기기가 보이지 않을 경우 아래와 같이 view Menu를 클릭하신 후 'Reset adb'를 선택하시면 접속된 안드로이드 기기 리스트가 갱신되는 것을 확인하실 수 있습니다.
이후 자신이 Logcat을 보고자 하는 기기를 선택하시면 Logcat이 정상적으로 동작하고 있는 모습을 확인하실 수 있습니다.
'안드로이드 > 애플리케이션 제작' 카테고리의 다른 글
Handler와 Message를 활용하여 콜백함수 구현하기 (0) | 2015.08.24 |
---|---|
안드로이드 기기 간에 Wifi Socket 통신하기 (14) | 2015.02.08 |
xml graphical layout가 정상적으로 동작하지 않을 때 (0) | 2015.02.05 |
XML의 Graphical Layout이 보이지 않는 경우 해결법 (0) | 2015.02.03 |
Extract contour area using OpenCV in Android(OpcnCV에서 검출된 영역의 넓이 구하기) (0) | 2014.12.07 |
설정
트랙백
댓글
글
xml graphical layout가 정상적으로 동작하지 않을 때
안드로이드 애플리케이션을 개발하던 도중 XML을 편집하고 graphicl layout을 확인한 순간 다음과 같은 메시지를 보게 되었습니다.
Exception raised during rendering:java.util.Locale.toLanguageTag()Ljava/lang/String;
Exception details are logged in Window > Show View > Error Log
이러한 경우 대개 2가지 경우로 보실 수 있습니다.
1.자신이 Target으로 한 버전의 SDK가 설치되어 있지 않아 Graphical Layout가 지원되지 않는 경우
2.다른 무언가에 의해 충돌이 될 경우
거의 대부분의 경우가 1번의 경우가 많은 것으로 보입니다. 이를 해결하는 방법은 상당히 간단합니다. SDK Manager를 실행하여 자신의 프로젝트에 해당되는 프로젝트를 다운로드하여 설치하신 뒤 Eclipse를 다시 실행하시면 Graphical Layout가 정상적으로 동작하는 것을 확인해 보실 수 있습니다.
'안드로이드 > 애플리케이션 제작' 카테고리의 다른 글
안드로이드 기기 간에 Wifi Socket 통신하기 (14) | 2015.02.08 |
---|---|
USB를 연결한 후 Logcat이 바로 보이지 않을 때 해결방법 (0) | 2015.02.07 |
XML의 Graphical Layout이 보이지 않는 경우 해결법 (0) | 2015.02.03 |
Extract contour area using OpenCV in Android(OpcnCV에서 검출된 영역의 넓이 구하기) (0) | 2014.12.07 |
Color detection using Android openCV(안드로이드 OpenCV로 특정 색깔 인식) (3) | 2014.12.06 |
설정
트랙백
댓글
글
XML의 Graphical Layout이 보이지 않는 경우 해결법
오랜만에 Linux에서 안드로이드 작업을 하려고 새로운 프로젝트를 생성한 후 작업을 하려 했더니 아래와 같은 에러가 발생하면서 아무런 화면도 뜨지 않는 현상이 발생하였습니다.
The rendering target (Android 5.0.1) is still loading.
The layout will refresh automatically once the process is finished.
처음에는 다소 당황했었으나 차분히 원인을 분석해 본 결과 안드로이드 버전을 낮은 버전으로 설정하는 바람에 Graphical Layout가 해당 버전과 맞지 않아 위와 같은 에러가 발생하였더군요 해결 방법은 간단합니다.
1. 먼저 에러가 발생한 xml 파일을 끈 후 다시 엽니다.
2. Graphical Layout을 클릭한 후 xml 창의 왼쪽 위 부분을 자세히 보면 아래쪽 화살표 모양의 버튼이 보입니다 해당 버튼을 클릭하면 현재 설정된 버전의 번호가 보입니다 해당 버전의 번호를 클릭하면 설정할 수 있는 버전 명단이 뜨는데 그 중 자신의 프로젝트에 해당하는 버튼을 클릭합니다.
위의 과정을 거치만 아래와 같이 Grahpical Layout가 정상적으로 출력 되는 것을 확인하실 수 있습니다.
'안드로이드 > 애플리케이션 제작' 카테고리의 다른 글
USB를 연결한 후 Logcat이 바로 보이지 않을 때 해결방법 (0) | 2015.02.07 |
---|---|
xml graphical layout가 정상적으로 동작하지 않을 때 (0) | 2015.02.05 |
Extract contour area using OpenCV in Android(OpcnCV에서 검출된 영역의 넓이 구하기) (0) | 2014.12.07 |
Color detection using Android openCV(안드로이드 OpenCV로 특정 색깔 인식) (3) | 2014.12.06 |
Use front camera with OpenCV 2.4.9 for android(안드로이드 OpenCV에서 전면카메라 적용 방법) (2) | 2014.12.01 |
설정
트랙백
댓글
글
Extract contour area using OpenCV in Android(OpcnCV에서 검출된 영역의 넓이 구하기)
※이 프로그램은 OpenCV의 예제파일인 OpenCV Sample - color-blob-detection을 수정한 자료임을 알립니다.
OpenCV의 색상 검출 프로그램을 돌려보면 원하는 영역이 아래와 같이 붉은 테두리로 나타나는 것을 보실 수 있을 것입니다.
위 그림에서 보시는 이 빨간 테두리를 '등고선(Contour)'라 부릅니다. Android OpenCV에서는 이 빨간 테두리가 쳐진 부분의 넓이를 추출하는 기능을 가지고 있습니다. 이를 적용하는 방법은 아래외 같이 하시면 되겠습니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | public class ColorBlobDetectionActivity extends Activity implements OnTouchListener, CvCameraViewListener2 { private static final String TAG = "OCVSample::Activity"; private boolean mIsColorSelected = false; private Mat mRgba; private Scalar mBlobColorRgba; private Scalar mBlobColorHsv; private ColorBlobDetector mDetector; private Mat mSpectrum; private Size SPECTRUM_SIZE; private Scalar CONTOUR_COLOR; private CameraBridgeViewBase mOpenCvCameraView; List<MatOfPoint> contours; } |
위의 코드에서 contour 변수는 원래 onCameraFrame() 함수 내에 있는 변수입니다. 이를 다른 곳에서 사용하기 위해서는 위의 코드에서 보시는 것 처럼 전역변수로 선언하는 것이 사용하기에 편합니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | public Mat onCameraFrame(CvCameraViewFrame inputFrame) { mRgba = inputFrame.rgba(); if (mIsColorSelected) { mDetector.process(mRgba); contours = mDetector.getContours(); Log.e(TAG, "Contours count: " + contours.size()); Imgproc.drawContours(mRgba, contours, -1, CONTOUR_COLOR); Mat colorLabel = mRgba.submat(4, 68, 4, 68); colorLabel.setTo(mBlobColorRgba); Mat spectrumLabel = mRgba.submat(4, 4 + mSpectrum.rows(), 70, 70 + mSpectrum.cols()); mSpectrum.copyTo(spectrumLabel); } return mRgba; } |
onCameraFrame() 함수 내에 있던 contours 변수를 외부에 전역으로 선언하였으므로 이 함수 안에서는 그냥 변수에 값을 넣는 개념으로 이해하시면 되겠습니다.
1 2 3 4 5 6 7 8 | if(contours != null){ double d; d=0; for(int i=0; i<contours.size();i++){ d += Imgproc.contourArea(contours.get(i)); } } |
프로그램을 처음 구동할 때 contours의 값이 null일 경우가 있으므로 if문을 통해 null일 경우 예외처리를 해줍니다.
그 다음으로 contours 내의 모든 등고선의 값을 d에 저장을 하시면 화면에 표시되는 등고선(Contour)의 면적값들을 구하실 수 있습니다.
위에서 보시는 바와 같이 contours는 List 변수로 내부에는 화면에 표시된 등고선의 수 만큼의 Mat 값들이 있는 것을 확인하실 수 있습니다. 이러한 contours를 반복문을 통해서 각 하나의 contour값을 확인하는 과정을 거칩니다.
Imageproc.contourArea() 함수는 해당 Contour의 값을 구하는 기능을 가지고 있습니다. 이를 통하여 해당 contour의 넓이를 구해 모든 값을 더하게 되면 화면에 표시된 붉은 영역의 총 면적을 구할 수 있게 됩니다.
'안드로이드 > 애플리케이션 제작' 카테고리의 다른 글
xml graphical layout가 정상적으로 동작하지 않을 때 (0) | 2015.02.05 |
---|---|
XML의 Graphical Layout이 보이지 않는 경우 해결법 (0) | 2015.02.03 |
Color detection using Android openCV(안드로이드 OpenCV로 특정 색깔 인식) (3) | 2014.12.06 |
Use front camera with OpenCV 2.4.9 for android(안드로이드 OpenCV에서 전면카메라 적용 방법) (2) | 2014.12.01 |
블루투스를 통해 이미지를 바이트로 전송하기 (38) | 2014.11.20 |
설정
트랙백
댓글
글
Color detection using Android openCV(안드로이드 OpenCV로 특정 색깔 인식)
※이 프로그램은 OpenCV의 예제파일인 OpenCV Sample - color-blob-detection을 수정한 자료임을 알립니다.
1.먼저 자신이 찾고자 하는 색깔의 Hsv를 알아내야 합니다. 만약 자신이 찾는 색깔의 Hsv를 모르는 경우 해당 색깔의 RGB를 Hsv로 변환하는 사이트를 이용합니다.
http://www.rapidtables.com/convert/color/rgb-to-hsv.htm
위의 RGB 색상 변환으로 나오는 HSV의 값을 아래와 같이 입력하시면 되겠습니다.
new Scalar(235, 75.2, 45.9, 0.0);
위에서 처리한 값을 이제 아래의 onCameraViewStarted() 함수에 입력해주시면 프로그램이 실행하자마자 해당 색상을 검출하는 것을 확인하실 수 있습니다.
ColorBlobDetectionActivity.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | public void onCameraViewStarted(int width, int height) { mRgba = new Mat(height, width, CvType.CV_8UC4); mDetector = new ColorBlobDetector(); mSpectrum = new Mat(); mBlobColorRgba = new Scalar(255); SPECTRUM_SIZE = new Size(200, 64); CONTOUR_COLOR = new Scalar(255,0,0,255); mBlobColorHsv = new Scalar(235, 75.2, 45.9, 0.0); mDetector.setHsvColor(mBlobColorHsv); mIsColorSelected = true; } |
'안드로이드 > 애플리케이션 제작' 카테고리의 다른 글
XML의 Graphical Layout이 보이지 않는 경우 해결법 (0) | 2015.02.03 |
---|---|
Extract contour area using OpenCV in Android(OpcnCV에서 검출된 영역의 넓이 구하기) (0) | 2014.12.07 |
Use front camera with OpenCV 2.4.9 for android(안드로이드 OpenCV에서 전면카메라 적용 방법) (2) | 2014.12.01 |
블루투스를 통해 이미지를 바이트로 전송하기 (38) | 2014.11.20 |
[NDK] openCV jni 소스 헤더파일이 include 되지 않을 때 해결방법 (0) | 2014.11.16 |
설정
트랙백
댓글
글
Use front camera with OpenCV 2.4.9 for android(안드로이드 OpenCV에서 전면카메라 적용 방법)
굳게 마음을 먹고 OpenCV를 사용하여 프로그래밍을 해보려고 하는데 SurfaceView를 통해 전면 카메라를 사용하는 방법과 다른 방법을 쓰는 것 같아 찾아보니 쉽지가 않더군요.
그래서 직접 OpenCV 라이브러리를 찾아보면서 적용방법을 찾아본 결과 다음과 같은 결과를 얻을 수 있었습니다.
안드로이드용 OpenCV에서 아래의 클래스가 카메라를 담당하는 것으로 보였습니다.
private CameraBridgeViewBase mOpenCvCameraView;
위 클래스를 이것 저것 적용하다보니 사용법을 찾아낼 수 있었습니다.
아래의 코드와 같이 onCreate()에서 굵게 표시한 부분을 코드에 삽입하면 OpenCV가 전면카메라를 사용하는 것을 확인하실 수 있습니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 | public void onCreate(Bundle savedInstanceState) { Log.i(TAG, "called onCreate"); super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); setContentView(R.layout.color_blob_detection_surface_view); mOpenCvCameraView = (CameraBridgeViewBase) findViewById(R.id.color_blob_detection_activity_surface_view); mOpenCvCameraView.disableView(); mOpenCvCameraView.setCameraIndex(CameraBridgeViewBase.CAMERA_ID_FRONT); mOpenCvCameraView.setCvCameraViewListener(this); } |
'안드로이드 > 애플리케이션 제작' 카테고리의 다른 글
설정
트랙백
댓글
글
블루투스를 통해 이미지를 바이트로 전송하기
대부분의 안드로이드 폰에는 블루투스가 기본적으로 내장되어 있습니다. 블루투스 기능을 활용하면 굳이 인터넷이나 기지국을 거치지 않고도 안드로이드 기기간에 파일 전송이 가능하지요.
이번 포스팅에서는 간단하게 다른 안드로이드 폰으로 사진을 전송하는 방법에 대해 알아보겠습니다.
시작하기에 앞서 아래에 있는 블루투스 채팅 프로그램 프로젝트를 다운로드하여 Import 합니다.
위의 예제는 안드로이드 폰 상호간에 간단한 문자 채팅을 할 수 있는 프로그램입니다. 이 프로젝트에 이미지를 전송할 수 있는 기능을 넣어보도록 하겠습니다.
먼저 AndroidManifest.xml 파일에 다음과 같은 퍼미션을 추가 해줍니다.
1 2 | <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> <uses-permission android:name="android.permission.BLUETOOTH" /> |
다음으로 메인 레이아웃인 main.xml에 그림을 띄울 ImageView와 그림을 전송하기 위한 Button을 다음과 같이 추가합니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" > <ListView android:id="@+id/in" android:layout_width="match_parent" android:layout_height="0dp" android:stackFromBottom="true" android:transcriptMode="alwaysScroll" android:layout_weight="1" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" > <ImageView android:id="@+id/getimage" android:layout_width="match_parent" android:layout_height="150dp" android:src="@drawable/app_icon" android:scaleType="centerInside" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" > <EditText android:id="@+id/edit_text_out" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="bottom" android:layout_weight="1" > <requestFocus /> </EditText> <Button android:id="@+id/button_send" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/send" /> <Button android:id="@+id/button_image" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/send_image" /> </LinearLayout> </LinearLayout> </LinearLayout> |
다음으로 BluetoothChat.java를 수정해 보도록 하겠습니다.
1 2 | private Button mSendImage; private ImageView iv; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | private void setupChat() { ............ iv = (ImageView)findViewById(R.id.getimage); mSendImage = (Button) findViewById(R.id.button_image); mSendImage.setOnClickListener(new OnClickListener(){ @Override public void onClick(View v) { Intent intent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI); startActivityForResult(intent,10); } }); } |
위에서 보는 것과 같이 이미지 갤러리를 Intent를 통해 불러오는 것을 볼 수 있습니다.
Intent를 통해 선택된 사진은 onActivityResult() 함수를 통해 얻을 수 있습니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | public void onActivityResult(int requestCode, int resultCode, Intent data) { ............ switch (requestCode) { ............ case 10: if(resultCode==RESULT_OK && data != null){ try { Uri selectedImage = data.getData(); Bitmap bp = Images.Media.getBitmap(this.getContentResolver(), selectedImage); ByteArrayOutputStream baos = new ByteArrayOutputStream(); bp.compress(CompressFormat.JPEG, 80, baos); byte[] imageByte = baos.toByteArray(); iv.setImageBitmap(BitmapFactory.decodeByteArray(imageByte, 0, imageByte.length)); if(mChatService.getState() == BluetoothChatService.STATE_CONNECTED){ int len; final int size = 512; byte[] sendByte = new byte[size]; ByteArrayInputStream bais = new ByteArrayInputStream(imageByte); mConversationArrayAdapter.add("이미지 전송을 시작합니다."); sendByte[0] = 6; sendByte[1] = 26; sendByte[2] = 18; mChatService.write(sendByte); while( (len=bais.read(sendByte)) != -1){ if(len<512){ byte[] EOF = new byte[len]; for(int eof=0 ; eof<EOF.length; eof++){ EOF[eof] = sendByte[eof]; } mChatService.write(EOF); }else{ mChatService.write(sendByte); } } sendByte[0] = 26; sendByte[1] = 6; sendByte[2] = 18; mChatService.write(sendByte); mConversationArrayAdapter.add("이미지 전송이 완료되었습니다!"); mConversationArrayAdapter.add("Image Size : " + imageByte.length); } } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } break; } } |
마지막으로 Handler를 통해 전송된 사진의 값을 수정하는 부분을 다음과 같이 수정해 줍니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 | .... boolean imageTransfer = false; boolean imageTransferW = false; ByteArrayOutputStream ReceiveImage; // The Handler that gets information back from the BluetoothChatService private final Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case MESSAGE_STATE_CHANGE: if(D) Log.i(TAG, "MESSAGE_STATE_CHANGE: " + msg.arg1); switch (msg.arg1) { case BluetoothChatService.STATE_CONNECTED: mTitle.setText(R.string.title_connected_to); mTitle.append(mConnectedDeviceName); mConversationArrayAdapter.clear(); break; case BluetoothChatService.STATE_CONNECTING: mTitle.setText(R.string.title_connecting); break; case BluetoothChatService.STATE_LISTEN: case BluetoothChatService.STATE_NONE: mTitle.setText(R.string.title_not_connected); break; } break; case MESSAGE_WRITE: byte[] writeBuf = (byte[]) msg.obj; String writeMessage = new String(writeBuf); mConversationArrayAdapter.add(writeBuf.length+" "+(int)writeBuf[0] +" "+(int)writeBuf[1]); mConversationArrayAdapter.add("나 : " + writeMessage); break; case MESSAGE_READ: byte[] readBuf = (byte[]) msg.obj; // construct a string from the valid bytes in the buffer if(msg.arg1 > 2 && readBuf[0]==6 && readBuf[1]==26 && readBuf[2] == 18){ imageTransfer = true; ReceiveImage = new ByteArrayOutputStream(); mConversationArrayAdapter.add("Image Transfer Start!"); break; } if(msg.arg1 > 2 && readBuf[0]==26 && readBuf[1]==6 && readBuf[2] == 18){ imageTransfer = false; mConversationArrayAdapter.add("Image Transfer End!"); mConversationArrayAdapter.add("Image Size : " + ReceiveImage.size()); byte[] getImage = ReceiveImage.toByteArray(); iv.setImageBitmap(BitmapFactory.decodeByteArray(getImage, 0, getImage.length)); break; } if(imageTransfer){ try { ReceiveImage.write(readBuf); if(readBuf.length==512) mConversationArrayAdapter.add("Size : " + readBuf.length +", " +(short)readBuf[0]+", " + (short)readBuf[511]); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } }else{ String readMessage = new String(readBuf, 0, msg.arg1); mConversationArrayAdapter.add(mConnectedDeviceName+": " + readMessage); } break; case MESSAGE_DEVICE_NAME: // save the connected device's name mConnectedDeviceName = msg.getData().getString(DEVICE_NAME); Toast.makeText(getApplicationContext(), "Connected to " + mConnectedDeviceName, Toast.LENGTH_SHORT).show(); break; case MESSAGE_TOAST: Toast.makeText(getApplicationContext(), msg.getData().getString(TOAST), Toast.LENGTH_SHORT).show(); break; case 6: //Toast.makeText(getApplicationContext(), "WTF", Toast.LENGTH_SHORT).show(); break; } } }; .... | cs |
'안드로이드 > 애플리케이션 제작' 카테고리의 다른 글
설정
트랙백
댓글
글
[NDK] openCV jni 소스 헤더파일이 include 되지 않을 때 해결방법
안드로이드로 openCV를 해보기 위해 NDK를 설치한 후 직접 소스를 수정해보기 위해 소스파일을 연 순간 다음과 같은 장면이 펼쳐졌습니다.
분명 직접 빌드까지 하였던 프로젝트임에도 이렇게 헤더파일이 잡히지 않아 당황하였습니다. 혹시 프로젝트를 빌드에 성공하지 못하셨던 분이라면 아래의 블로그를 참조해 주시길 바랍니다.
http://adppark.tistory.com/303
그럼 프로젝트의 헤더파일이 연결될 수 있도록 해보겠습니다.
1. 자신이 원하는 jni 프로젝트 폴더를 오른쪽 클릭 -> Properties -> C/C++ General -> Paths and Symbols를 선택합니다.
2. 다음과 같은 화면이 나오면 Includes 탭 내의 Languages 내에서 C/C++ 둘중 Include directories가 있는 경우 모두 추가해줍니다.
오른쪽의 Add를 선택합니다.
3. File System...를 선택하신 후
4. "자신의 안드로이드 openCV 버전/sdk/native/jni/include"를 선택하신 후 확인 버튼을 누른 후
5. OK버튼을 눌러 Include directories에 추가합니다.
6. 추가한 Include 디렉토리를 상단 두번째에 위치시킵니다. 오른쪽의 Move Up를 클릭하여 이동이 가능합니다.
8. jni 폴더 내에 있는 Android.mk 파일을 연 후 include 부분에 자신의 OpenCV의 절대 경로로 수정합니다.
9. 시작버튼을 눌러 '고급 시스템 설정'을 검색하여 나오는 항목을 클릭합니다.
10. 다음과 같이 시스템 설정 메뉴가 나오는 것을 보실 수 있습니다. 아래 환경변수(N)을 클릭합니다.
11. 새로 만들기(W)를 선택하신 후
12. 자신의 Android NDK의 환경변수를 설정합니다.
변수 이름은 'NDKROOT'로 설정하시고
변수값에는 자신의 NDK가 있는 위치를 입력하신 후 확인버튼을 누릅니다.
위와 같은 과정을 거치시면 다음과 같이 헤더파일이 정상적으로 동작하는 것을 확인하실 수 있습니다.
'안드로이드 > 애플리케이션 제작' 카테고리의 다른 글
설정
트랙백
댓글
글
<Project name> does not specify a android.test.InstrumentationTestRunner instrumentation or does not declare uses-library android.test.runner in its AndroidManifest.xml
블로그에 올라와 있는 안드로이드 프로젝트 파일을 받은 후 이를 실행하기 위해 실행을 하려 했더니 다음과 같은 에러가 뜨면서 프로그램이 실행되지 않는 상황을 맟게 되었습니다.
"<Project name> does not specify a android.test.InstrumentationTestRunner instrumentation or does not declare uses-library android.test.runner in its AndroidManifest.xml"
이렇게 나오는 경우 다음과 같이 진행해 주시면 되겠습니다.
해당 프로젝트 폴더 위에 마우스 우클릭 -> Run As(또는 Debug As) -> 1 Android Application
다음과 같이 프로그램을 실행하면 정상적으로 동작되는 것을 확인하실 수 있습니다.
만약 위와 같은 방법으로 실행이 되지 않으신 분들은
Run As -> Run Configurations... 를 선택하신 후
동작 시킬 프로그램을 선택하신 후 수동으로 프로그램을 실행할 타겟을 선택합니다.
'안드로이드 > 애플리케이션 제작' 카테고리의 다른 글
블루투스를 통해 이미지를 바이트로 전송하기 (38) | 2014.11.20 |
---|---|
[NDK] openCV jni 소스 헤더파일이 include 되지 않을 때 해결방법 (0) | 2014.11.16 |
MediaPlayer, VideoView 재생이 끝났을 때 이벤트 처리하기 (setOnCompletionListener) (0) | 2014.10.03 |
안드로이드 SDK 업데이트 후 이클립스에서 실행이 안될 때(Android ADT 재설치) (0) | 2014.09.27 |
숨겨진 Activity 혹은 Fragment의 Thread를 종료시키는 방법 (1) | 2014.09.11 |
설정
트랙백
댓글
글
MediaPlayer, VideoView 재생이 끝났을 때 이벤트 처리하기 (setOnCompletionListener)
public void setOnCompletionListener (MediaPlayer.OnCompletionListener listener)
안드로이드를 통해 동영상이나 mp3 파일 등을 재생한 후 해당 미디어를 모두 재생이 되었을 때 설정하는 이벤트입니다. 사운드를 재생하는 MediaPlayer라던가 동영상을 재생하는 VideoView에서 사용할 수 있습니다.
함수의 인자로 OnCompletionListener()가 사용됩니다. 이 함수는 인터페이스로 new 로 함수를 새로 선언함으로서 적용할 수 있습니다.
아래는 MediaPlayer에 setOnCompletionListener 함수를 적용한 예제입니다. 음악이 모두 재생된 후 이벤트가 정상적으로 발생되는 것을 확인하실 수 있습니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | MediaPlayer mp; mp = MediaPlayer.create(this, R.raw.melody); mp.start(); mp.setOnCompletionListener(new OnCompletionListener(){ @Override public void onCompletion(MediaPlayer mp) { // TODO Auto-generated method stub l1.setBackgroundColor(Color.TRANSPARENT); l2.setBackgroundColor(Color.TRANSPARENT); l3.setBackgroundColor(Color.TRANSPARENT); pb1.setVisibility(View.INVISIBLE); pb2.setVisibility(View.INVISIBLE); pb3.setVisibility(View.INVISIBLE); tv4.setText(""); tag = 0; } }); |