RPC(Remote Procedure Call)
: 서로다른 네트워크 또는 프로세스에 존재하는 Procedure(함수)를 호출하기 위한 기술
안드로이드에서는 AIDL(Android Interface Definition Language)로 제공 하고 있다.
IPC를 하는 Service와 Activity 간에 AIDL 이라는 인터페이스를 공유해서
Activity - Service 가 Bind Connect 된 이후에 Activity 에서 Service에서 구현 된 AIDL 인터페이스를 활용할 수 있도록 하는 기술이다.
1. AIDL 서비스 앱 생성
2. AIDL Client 앱 생성
[AIDL 서비스 앱]
1. res/raw 에 mp3 파일 준비
2. aidl 폴더, 패키지 및 aidl 파일 생성
IPlayService.aidl
// IPlayService.aidlpackage com.example.ch3_aidl; // Declare any non-default types here with import statements interface IPlayService { int currentPosition(); int getMaxDuration(); void start(); void stop(); int getMediaStatus(); }
3. Service 생성
PlayService.java
package com.example.ch3_aidl; import android.app.Service; import android.content.Intent; import android.os.IBinder; public class PlayService extends Service { public PlayService() { } @Override public IBinder onBind(Intent intent) { // TODO: Return the communication channel to the service. throw new UnsupportedOperationException("Not yet implemented"); } }
4. manifest 수정
자동 생성된 service 태그 아래
<service android:name=".PlayService"
android:enabled="true"
android:exported="true"> <intent-filter>
<action android:name="com.multi.ACTION_PLAY"/> </intent-filter> </service>
*5. 빌드 한번 하기
Build -> Make Module 'AIDL모듈명'
진행 해야 현 소스코드에서 해당 AIDL 인지 가능
6. 서비스 구현
package com.example.ch3_aidl; public class CommonProperties { public static final int MEDIA_STATUS_STOP = 0; public static final int MEDIA_STATUS_RUNNING = 1; public static final int MEDIA_STATUS_COMPLETED = 2; }
package com.example.ch3_aidl; import android.app.Service; import android.content.Intent; import android.media.MediaPlayer; import android.os.IBinder; import android.os.RemoteException; public class PlayService extends Service { MediaPlayer player; int status = 0; public PlayService() { } @Override public void onCreate() { super.onCreate(); player = new MediaPlayer(); } @Override public void onDestroy() { super.onDestroy(); player.release(); } @Override public IBinder onBind(Intent intent) { // aidl 파일을 구현한 stub 객체(실 업무 객체가 넘어가는게 아니라)를 리턴 return new IPlayService.Stub(){// Make Module xxx 작업을 해서 에러가 발생하지 않음 @Override public int currentPosition() throws RemoteException { if(player.isPlaying()){ return player.getCurrentPosition(); }else{ return 0; } } @Override public int getMaxDuration() throws RemoteException { if(player.isPlaying()){ return player.getDuration(); }else{ return 0; } } @Override public void start() throws RemoteException { if(!player.isPlaying()){ player = MediaPlayer.create(PlayService.this, R.raw.music); player.start(); player.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { @Override public void onCompletion(MediaPlayer mp) { status = CommonProperties.MEDIA_STATUS_COMPLETED; } }); } status = CommonProperties.MEDIA_STATUS_RUNNING; } @Override public void stop() throws RemoteException { if(player.isPlaying()) player.stop(); status = CommonProperties.MEDIA_STATUS_STOP; } @Override public int getMediaStatus() throws RemoteException { return status; } }; } }
[AIDL Client 앱]
1. aidl 폴더, 패키지 생성 및 aidl 파일 복사
2. 빌드 한번 하기
Build -> Make Module 'AIDL모듈명'
진행 해야 현 소스코드에서 해당 AIDL 인지 가능
3. MainActivity
package com.example.ch3_aidl_client; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.os.RemoteException; import android.os.SystemClock; import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.view.View; import android.widget.ImageButton; import android.widget.ProgressBar; import com.example.ch3_aidl.IPlayService; public class MainActivity extends AppCompatActivity implements View.OnClickListener { IPlayService pService; ImageButton start; ImageButton stop; ProgressBar mProgress; boolean isRunning = true; ProgressThread pt; Handler handler; Intent intent; //--add 1--------------- // bindService시 callback함수를 가지는 interface구현 클래스 ServiceConnection connection = new ServiceConnection() { // bindService에 의해 bind객체가 넘어온 순간 호출 // 두번째 객체가 bind 객체 stub 객체가 넘어 옴 @Override public void onServiceConnected(ComponentName name, IBinder service) { pService = IPlayService.Stub.asInterface(service); start.setEnabled(true); checkService(); } @Override public void onServiceDisconnected(ComponentName name) { pService = null; } }; //------------------------ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); start = (ImageButton) findViewById(R.id.start); stop = (ImageButton) findViewById(R.id.stop); mProgress = (ProgressBar) findViewById(R.id.pb); mProgress.setProgress(0); start.setOnClickListener(this); stop.setOnClickListener(this); start.setEnabled(false); stop.setEnabled(false); handler = new Handler() { // Activity ANR - Thread에서 sendMessage하는 순간 UI Thread에 의해 자동 호출 @Override public void handleMessage(Message msg) { switch(msg.what) { case 1: // stopped media start.setEnabled(true); stop.setEnabled(false); mProgress.setProgress(0); break; } super.handleMessage(msg); } }; //add2------------------------------------- // service 구동을 위한 intent 준비 intent = new Intent("com.multi.ACTION_PLAY"); // 이전버전에서는 그냥 intent를 실행. lollipop부터는 bindService의 경우 package명을 명시 intent.setPackage("com.example.ch3_aidl"); //-------------------------------------- } private void checkService() { if(pService != null) { try { if(pService.getMediaStatus() == CommonProperties.MEDIA_STATUS_STOP) { Log.d("kkang", "MEDIA_STATUS_STOP"); stop.setEnabled(false); } else if(pService.getMediaStatus() == CommonProperties.MEDIA_STATUS_RUNNING) { Log.d("kkang", "MEDIA_STATUS_RUNNING"); start.setEnabled(false); isRunning = true; pt = new ProgressThread(); pt.start(); } } catch (RemoteException e) { } } } //add3------------------------------- @Override protected void onResume() { super.onResume(); bindService(intent, connection, Context.BIND_AUTO_CREATE); checkService(); } @Override protected void onPause() { super.onPause(); unbindService(connection); isRunning = false; } //--------------------------------- @Override public void onClick(View v) { if(v == start) { try { pService.start(); mProgress.setMax(pService.getMaxDuration()); isRunning = true; pt = new ProgressThread(); pt.start(); start.setEnabled(false); stop.setEnabled(true); } catch (RemoteException e) { // TODO Auto-generated catch block e.printStackTrace(); } } else if(v == stop) { try { pService.stop(); isRunning = false; start.setEnabled(true); stop.setEnabled(false); } catch (RemoteException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } class ProgressThread extends Thread { @Override public void run() { while(isRunning) { try { if(pService.getMediaStatus() == CommonProperties.MEDIA_STATUS_COMPLETED) { handler.sendEmptyMessage(1); break; } else { mProgress.setProgress(pService.currentPosition()); SystemClock.sleep(1000); } } catch (RemoteException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } }
댓글 없음:
댓글 쓰기