2014-09-11 2 views
1

을 위해 메신저를 사용하여 동기/차단 API를 구현 나는 서비스에 대한 매니페스트 항목에서안드로이드 : IPC

android:process=":deamon" 

를 사용하여 별도의 프로세스에서 실행되는 백그라운드 서비스가있다. 내 활동에서 서비스 (원격 프로세스)와 통신하고 데이터를 수신하려고합니다. 그때 당신은 또한 클라이언트에 메신저를 만들어야과 http://developer.android.com/guide/components/bound-services.html#Messenger과 같이 설명 된대로 원격 프로세스에서 메시지를 전송하여 그들은 당신이 서비스가 응답하려면 내가

을 따라 제안 것을하고 있어요 . > 그런 다음 클라이언트가 onServiceConnected() 콜백을 수신하면 send() 메서드의 replyTo 매개 변수에 클라이언트의 메신저가 포함 된 Message를> 서비스로 보냅니다.

원격 서비스에서 데이터를 가져 오기 위해 차단/동기 API를 제공해야합니다. "get"함수가 호출자를 차단 한 다음 수신 Handler에서받은 데이터를 반환 할 수 있습니까? 그렇게하기위한 최선의 방법은 무엇입니까?

+1

AIDL을 시도해보고 메소드를 정의하고 호출하면 모든 것이 동기화되고 프로토콜을 정의하는 데 더 이상 문제가 없습니다 http://developer.android.com/guide/components/aidl.html – eduyayo

+0

aidl에 대한 "반대"느낌 그러나 지금 나는 그것을 들여다 볼 것입니다 –

+0

감사합니다, 그것의 명확하게 훨씬 더 approch –

답변

3

이 클라이언트

SparseArray<CountDownLatch> lockArray = new SparseArray<>(); 
    SparseArray<Bundle> msgDataArray = new SparseArray<>(); 

    public Bundle sendAndWaitResponse(Message msg) throws 
           RemoteException, InterruptedException { 
     int msgId = msg.arg2; 
     Log.d("PlatformConnector", "Sending message to service, Type: " 
           + msg.what + ", msgId: " + msg.arg2); 
     CountDownLatch latch = new CountDownLatch(1); 
     lockArray.put(msgId, latch); 
     platformMessenger.send(msg); 
     latch.await(); 

     Bundle response = msgDataArray.get(msgId); 
     lockArray.delete(msgId); 
     msgDataArray.delete(msgId); 

     return response; 
    } 

    void storeResponseAndNotify(Message msg) { 
     int msgId = msg.arg2; 
     // Because the message itself is recycled after Handler returns, 
     // we should store only the data of message 
     msgDataArray.put(msgId, msg.getData()); 
     lockArray.get(msgId).countDown(); 
    } 


    private class ClientMessageHandler extends Handler { 
     @Override 
     public void handleMessage(Message msg) { 
      storeResponseAndNotify(msg); 
     } 
    } 

이 코드 위의 활용의 예이다의 메시지 부분에 대한 코드입니다. RandomInt.getNextInt()Random.nextInt()으로 임의의 정수를 생성하는 내 사용자 정의 정적 메서드입니다. 다음과 같이

public JSONObject doSomething(JSONObject object) { 
     Message msg = Message.obtain(null, Constants.MESSAGE_SOMETHING, 0, RandomInt.getNextInt()); 
     Bundle bundle = new Bundle(); 
     bundle.putString(Constants.MESSAGE_DATA_SOMETHING, object.toString()); 
     msg.setData(bundle); 
     try { 
      Bundle responseData = sendAndWaitResponse(msg); 
      return new JSONObject(responseData.getString(Constants.MESSAGE_DATA_RETURN)); 
     } catch (RemoteException e) { 
      Log.e(TAG, "Failed to send message to platform"); 
      e.printStackTrace(); 
     } catch (InterruptedException e) { 
      Log.e(TAG, "Interrupted while waiting message from platform"); 
      e.printStackTrace(); 
     } catch (JSONException e) { 
      e.printStackTrace(); 
     } 
     return null; 
    } 

순서가

  1. 클라이언트는 Message을 준비하고 설정, 자사의 arg2 어떤 임의의 정수 (이 정수 동기화를위한 메시지 ID 예정) 등.
  2. 클라이언트가 새로 CountDownLatch을 준비하고 LockArray에 넣습니다.
  3. 클라이언트가 sendAndWaitResponse()과 함께 메시지를 보냅니다. Messenger을 통해 서비스에 메시지를 보내고 latch.await()을 호출합니다.
  4. 서비스 프로세스는 메시지를 수신하고 응답 메시지를 준비합니다. 이 회신 메시지의 arg2은 수신 메시지와 같아야합니다.
  5. 서비스가 replyTo에 Messenger을 통해 클라이언트에 응답 메시지를 보냅니다.
  6. 클라이언트 메시지 처리기는 storeResponseAndNotify으로 메시지를 처리합니다.
  7. 클라이언트 스레드 차단이 완료되면 응답 데이터는 이미 msgDataArray에 준비되어 있습니다.

CountDownLatch은 스레드를 차단하고 차단 해제하는 간단한 스위치입니다. (http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CountDownLatch.html)

SparseArrayHashMap과 유사하지만 작은 세트의 경우 메모리 효율이 우수합니다. (http://developer.android.com/reference/android/util/SparseArray.html)

Messenger의 스레드를 차단하지 않도록주의하십시오.Messenger은 단일 스레드에서 실행되며 handleMessage()에서 차단하면 다른 모든 메시지가 차단되어 디 잠금 문제가 발생합니다.

+0

좋은 것. 아마도 서비스 메신저가받은 메시지가 대기열에 들어 있다고 문서에서 말하기 때문에 응답을 기다리고있는 희귀 한 메시지 배열을 피할 수 있습니다. 당신은 더 간단하게 응답의 동기화 대기열을 설정할 수 있습니다. "Messenger는 모든 요청을 단일 스레드에 대기시키기 때문에 프로세스 간 통신 (IPC)을 수행하는 가장 간단한 방법이므로 스레드로부터 서비스를 보호 할 필요가 없습니다." https://developer.android.com/guide/components/bound-services.html – xpmatteo