2012-05-13 4 views
48

내 프로젝트에서 장기 실행 스레드의 콜백으로 BroadcastReceiver을 사용하고 있습니다 (예 : 작업이 완료되었음을 알리고 작업자 Thread의 응답 데이터를 보내 작업이 사용자에게 적절한 메시지를 표시 할 수 있도록 함). ..). BroadcastReceiver s를 사용하려면 브로드 캐스트 수신기를 등록 할 때마다 브로드 캐스트 리시버를 등록 할 때마다 등록을 취소하고 더 ​​많은 작업 (예 : 다운로드, WebService 전화 등 ..). 또한 브로드 캐스트의 의도를 통해 사용자 지정 개체를 보내려면 개체도 만들 필요가 Parcelable.Android BroadcastReceiver 또는 간단한 콜백 메소드?

이 방법과 달리 콜백 메소드 접근법은 내가 사용하는 방법보다 단순 해 보입니다. 콜백 메소드는 BroadcastRecaiver의 앱 메시징과 같은 효과를 얻기 위해 사용할 수있는 간단한 인터페이스 메소드 구현입니다. 이 접근법은 복잡한 객체를 반환하기 위해 Parcelable 구현을 필요로하지 않으며 BroadcastReceiver과 같은 키를 사용하지 않습니다. 콜백 메소드를 호출하기 전에 Null 값에 대한 콜백 객체를 확인해야한다는 잘못된 부분이 있다고 생각합니다. 또한 오류없이 UI를 업데이트 할 수 있도록 UI 스레드에서 구현 코드를 실행하는지 확인해야합니다.

좋아, 내가 무슨 말을 하려는지 이해했으면 좋겠다.

이제는 단일 응용 프로그램 내에서 사용되는 BroadcastReceiver 접근 방식보다 콜백 방식이 더 좋습니다 (더 가볍고 깔끔하며 빠름). (배경 작업에 안드로이드 Service을 사용하지 않음에 유의하십시오. AsyncTaskThread)

고마워요!

답변

78

을 사용할 수 있습니다 그리고 난 같은 문제 다 퉜다. 필자의 의견으로는 두 가지 메커니즘을 모두 사용할 수 있으며 적절한 사용 방법은 사용 사례에 따라 다릅니다. 결정하기 전에 몇 가지 사항을 고려해야합니다. 콜백-메커니즘을 사용

몇 가지 장점이 있지만 한계도있다 : 구현하는 단순하고 정직

  • PRO는.

  • 서로 상호 작용하는 구성 요소간에 유형 안전성이 제공됩니다.
  • 임의의 개체를 반환 할 수 있습니다.
  • 단위 테스트에서 모의 ​​콜백 (예 : mockito 또는 비슷한 것을 통해 생성 됨) 만 삽입하면되므로 테스트가 간단 해집니다.

CONTRA

  • 당신은 UI 조작을하기 위해 메인 스레드로 전환해야합니다.
  • 1 : 1 관계 만 가질 수 있습니다. 1 대 n의 관계 (관찰자 패턴)는 더 이상의 작업 없이는 실현 될 수 없다. 이 경우 안드로이드의 Observer/Observable 메커니즘을 선호합니다.
  • 이미 말했듯이 콜백 기능이 선택적 일 수있는 경우 콜백 기능을 호출하기 전에 항상 null을 확인해야합니다.
  • 구성 요소가 다른 서비스 기능을 가진 일종의 서비스 API를 제공해야하며 몇 가지 일반 콜백 함수 만 사용하는 콜백 인터페이스를 원하지 않는 경우 각 서비스 함수에 대해 특수 콜백 인터페이스를 제공할지 여부를 결정해야합니다 또는 콜백 함수가 많은 단일 콜백 인터페이스를 제공하는지 여부를 결정합니다. 이후의 경우 대부분의 메서드 본문은 비어 있지만 API에 대한 서비스 호출에 사용되는 모든 콜백 클라이언트는 완전한 콜백 인터페이스를 구현해야합니다. 빈 시체가있는 스텁을 구현하여 콜백 클라이언트가 해당 스텁에서 상속되도록 만들 수 있지만 이미 다른 기본 클래스에서 상속 한 경우에는 불가능합니다. 어쩌면 어떤 종류의 동적 프록시 콜백 (http://developer.android.com/reference/java/lang/reflect/Proxy.html 참조)을 사용할 수 있지만 실제로 복잡해지고 다른 메커니즘을 사용하는 것이 좋습니다.
  • 콜백 호출 용 클라이언트는 서비스 호출자가 직접 액세스 할 수없는 경우 다양한 메소드/구성 요소를 통해 전파되어야합니다.BroadcastReceiver -approach에 대한

몇 가지 포인트 :

PRO

  • 당신은 당신의 구성 요소 간의 느슨한 결합을 달성한다.
  • 1 대 n 관계 (1 : 0 포함)를 가질 수 있습니다.
  • onReceive() 메서드는 항상 주 스레드에서 실행됩니다.
  • 전체 응용 프로그램에서 구성 요소에 알릴 수 있으므로 통신 구성 요소는 서로를 "볼"필요가 없습니다.

콘트라

  • 이 너무 마샬링과 Intent에 의해 전송 된 데이터의 비 정렬 화는 추가 오류 소스, 매우 일반적인 방법입니다.
  • 다른 앱과의 상관 관계를 없애려는 경우 원래의 목적은 애플리케이션간에 브로드 캐스트를 수행하는 것이므로 Intent의 작업을 고유해야합니다 (예 : 패키지 이름을 추가 함).
  • BroadcastReceiver- 등록 및 등록 취소를 관리해야합니다. 보다 편한 방법으로이를 수행하려는 경우 사용자 정의 주석을 구현하여 활동에 주석을 추가하여 등록해야하는 작업을 주석으로 처리하고 onResume() resp에 IntentFilter으로 등록 및 등록 취소를 수행하는 기본 클래스 Activity을 구현할 수 있습니다. onPause() 방법.
  • Intent과 함께 전송되는 데이터는 Parcelable 인터페이스를 구현해야하지만 더 엄격한 크기 제한이 있으므로 Intent으로 많은 양의 데이터를 전송하면 성능 문제가 발생할 수 있습니다. 그것에 대한 토론은 http://code.google.com/p/android/issues/detail?id=5878을 참조하십시오. 예를 들어 이미지를 보내려는 경우 임시 저장소에 임시 이미지를 저장하고 해당 ID 또는 URL을 보내어 사용 후 이미지를 저장소에서 삭제하는 Intent의 수신자로부터 이미지에 액세스해야합니다. 여러 개의 리시버가있는 경우 (이미지를 리포지토리에서 언제 제거해야합니까?)
  • 이러한 종류의 통지 메커니즘을 과도하게 사용하면 응용 프로그램의 제어 흐름이 숨겨지고 디버깅 할 때 Intent 시퀀스를 사용하여 그래프를 그려 특정 오류를 유발 한 원인 또는이 통지 체인이 왜 고장 났는지 이해할 수 있습니다 포인트.

제 생각에는 모바일 앱이라도 UI 레이어와 비즈니스 레이어 등 2 개 이상의 레이어에 아키텍처 기반이 있어야합니다. 일반적으로 장기 실행 작업은 코어 레이어 내부에서 AsyncTask 또는 HandlerThread을 사용하는 자체 스레드에서 실행되며이 작업이 완료되면 UI가 업데이트되어야합니다. 일반적으로 콜백을 사용하면 구성 요소간에 긴밀한 결합이 이루어 지므로이 방법은 레이어 내에서만 사용하고 레이어 간 통신에는 사용하지 않는 것이 좋습니다. UI와 코어 레이어 사이의 메시지 브로드 캐스트의 경우 로직 레이어에서 UI 레이어를 분리 할 수있는 BroadcastReceiver -approach를 사용합니다.

+0

나는 이것을 가장 좋은 답변이기 때문에 답으로주고 현상금을줍니다. 당신의 모든 생각에 감사드립니다! – Cata

+0

우수 답변. 나는 콜백/인터페이스 패턴의 팬이지만 방송 의도 패턴을 광범위하게 사용하여 프로젝트를 상속하고 종종 잘못된 방향으로 가고 있는지 궁금해합니다. 그것은 실제로 모범 사례 라기보다 디자인 선호의 문제라는 것을 듣는 것이 좋다. 나는 인터페이스에 의해 제공되는 타입 안전성과 코드 명확성을 좋아한다. 아마도 나는 지금 그것들을 고수 할 것이다. –

+0

매우 흥미롭고 상세한 의견 +1 – Jorgesys

6

귀하의 경우에는 BroadcastReceiver을 사용하여 얻는 결과가 보이지 않습니다. 콜백 또는 더 나은 것은 아마도 Handlers 일 것입니다. 가입자가 누구인지 모르는 경우 BroadcastReceiver이 좋습니다.

+0

답변 해 주셔서 감사합니다. 조금만 더 답변을 기다리 겠지만 .. – Cata

2

브로드 캐스트 수신기를 사용해야합니다. 상황에 따라 콜백 (또는 Alex가 제안한 처리기)을 사용하는 동안 브로드 캐스트를 응용 프로그램간에 전송해야하는 경우.

다른 두 가지를 사용하려면 Observer (Android에 인터페이스 포함) 및 위임을 고려해보십시오.

대리인의 경우 this SO post을 고려하십시오.

3

난 그냥 당신이 이미받은 다른 큰 응답에 다른 옵션을 추가 할 것입니다 ...

당신은 텐트를 수신하는 방송 수신기를 만들 필요가 없습니다. 당신의 안드로이드 매니페스트 파일에서 당신은 의도를받을 수있는 활동을 등록 할 수 있습니다

<activity android:name=".MyActivity"> 
     <intent-filter > 
       <action android:name="intent.you.want.to.receive" /> 
       <category android:name="android.intent.category.DEFAULT" /> 
     </intent-filter>  
.... 
</activity> 

이 그 다음을받을 활동에 onNewIntent(Intent) 메소드를 오버라이드 (override).

의도를 보내려면 Context.startActivity(Intent) 방법을 사용하십시오. 대부분 당신의 의도에 FLAG_ACTIVITY_SINGLE_TOP 플래그를 추가하여 이미 실행중인 활동의 새 인스턴스를 만들지 않기를 원할 것입니다.

편집 : 방금 한 응용 프로그램 내에서 실행되는 것으로 나타났습니다. 따라서 간단한 콜백이 가장 좋습니다.위의 솔루션은 단일 응용 프로그램에서 작동하지만 다른 응용 프로그램에 더 적합합니다. 누군가를 도울 수 있기를 바랍니다. 행운을 빕니다!

+0

Excelent tip!그렇지만 UI 이외의 특정 구현을 분리하고 싶다면 동일한' '접근법도 서비스에 적용한다는 것을 추가하고 싶습니다.이 경우에는 Context.startService (의도)'대신. 타겟 서비스가 ['IntentService'] (http://developer.android.com/reference/android/app/IntentService.html)를 확장하면 'IntentService'만이 무료로 "비동기 메시지 대기열"을 갖게됩니다 그 시점에 하나의'Intent'를 실행하면'onHandleIntent' 메소드가 작업자 스레드에서 실행됩니다. – dbm

1

목표가 무엇인지 확실하지 않지만 intent 및 broadcastReceiver를 사용하는 것과 동일한 아이디어를 유지하고 일반 broadcastReceivers보다 성능과 보안을 향상시키려는 경우 Android 데모 라이브러리에서 사용할 수있는이 데모를 사용해 볼 수 있습니다. 하지 않을 경우

http://developer.android.com/resources/samples/Support4Demos/src/com/example/android/supportv4/content/LocalServiceBroadcaster.html

, 당신은 항상 이것은 매우 흥미로운 질문이다 AsyncTask를, 서비스, 처리기 등 ...

관련 문제