Android 서비스가 활동과 통신하도록하는 방법 활동이 있습니다. 먼저, 활동이 시작될 때

첫 번째 Android 응용 프로그램을 작성 중이며 서비스와 활동 간의 통신에 대해 잘 알고 있습니다. 백그라운드에서 실행되며 일부 GPS 및 시간 기반 로깅을 수행하는 서비스가 있습니다. 서비스를 시작하고 중지하는 데 사용할 활동이 있습니다.

먼저, 활동이 시작될 때 서비스가 실행되고 있는지 알아낼 수 있어야합니다. 여기에 다른 질문이 있으므로 알아낼 수 있다고 생각합니다 (그러나 조언을 자유롭게 제공하십시오).

내 진짜 문제 : 활동이 실행 중이고 서비스가 시작된 경우 서비스가 활동에 메시지를 보내는 방법이 필요합니다. 이 시점에서 간단한 문자열과 정수-대부분 상태 메시지. 메시지는 정기적으로 발생하지 않으므로 다른 방법이 있다면 서비스 폴링이 좋은 방법이라고 생각하지 않습니다. 사용자가 활동을 시작한 경우에만이 통신을 원합니다. 서비스에서 활동을 시작하고 싶지 않습니다. 즉, 활동을 시작하고 서비스가 실행중인 경우 흥미로운 일이 발생하면 활동 UI에 일부 상태 메시지가 표시됩니다. 활동을 시작하지 않으면이 메시지가 표시되지 않습니다 (그다지 흥미롭지 않습니다).

서비스가 실행 중인지 확인할 수 있어야하며, 그렇다면 서비스를 리스너로 추가하십시오. 그런 다음 활동이 일시 정지되거나 중지 될 때 활동을 리스너로 제거하십시오. 실제로 가능합니까? 내가 알아낼 수있는 유일한 방법은 Activity가 Parcelable을 구현하고 AIDL 파일을 빌드하여 서비스의 원격 인터페이스를 통해 전달할 수 있도록하는 것입니다. 그것은 과잉으로 보이지만 Activity가 어떻게 writeToParcel () / readFromParcel ()을 구현 해야하는지 전혀 모른다.

더 쉬운 방법이 있습니까? 도움을 주셔서 감사합니다.

편집하다:

나중에 관심이 있으신 분은 샘플 디렉토리에 AIDL을 통해이를 처리하기위한 Google의 샘플 코드가 있습니다. /apis/app/RemoteService.java



답변

서비스와 통신하는 방법에는 세 가지가 있습니다.

  1. 의도 사용
  2. AIDL 사용
  3. 서비스 객체 자체 사용 (싱글 톤으로)

귀하의 경우 옵션 3을 사용합니다. 서비스 자체를 정적 참조로 만들고 onCreate ()에 채 웁니다.

void onCreate(Intent i) {
  sInstance = this;
}

static 함수 MyService getInstance()를 작성하여 static을 리턴하십시오 sInstance.

그런 다음 Activity.onCreate()서비스를 시작하면 서비스가 실제로 시작될 때까지 비동기식으로 대기하고 (활동에 인 텐트를 보내어 서비스가 준비되었음을 앱에 알릴 수 있음) 인스턴스를 가져옵니다. 인스턴스가 있으면 서비스 리스너 오브젝트를 서비스에 등록하면 설정됩니다. 참고 : 활동 내에서 뷰를 편집 할 때 UI 스레드에서 뷰를 수정해야하며 서비스는 자체 스레드를 실행하므로을 호출해야합니다 Activity.runOnUiThread().

마지막으로해야 할 일은의 리스너 객체에 대한 참조를 제거하는 것입니다 Activity.onPause(). 그렇지 않으면 활동 컨텍스트의 인스턴스가 누출되어 좋지 않습니다.

참고 :이 방법은 응용 프로그램 / 활동 / 작업이 서비스에 액세스하는 유일한 프로세스 인 경우에만 유용합니다. 그렇지 않은 경우 옵션 1 또는 2를 사용해야합니다.


답변

asker는 아마도 오랫동안 이것을 지나쳐 왔지만 다른 사람이 이것을 찾고있는 경우를 대비하여 …

이것을 처리하는 다른 방법이 있는데, 이것이 가장 간단하다고 생각합니다.

BroadcastReceiver활동에를 추가 하십시오. 사용자 지정 의도를 수신 onResume하고 등록을 취소하려면 등록하십시오onPause . 그런 다음 상태 업데이트를 보내거나 가지고있는 내용을 서비스에서 보내십시오.

다른 앱이 사용자의 말을 듣더라도 Intent(누구든지 악의적 인 일을 할 수 있습니까?) 불행하지 않은지 확인하십시오 .

코드 샘플이 요청되었습니다.

내 서비스에는 다음이 있습니다.

// Do stuff that alters the content of my local SQLite Database
sendBroadcast(new Intent(RefreshTask.REFRESH_DATA_INTENT));

( RefreshTask.REFRESH_DATA_INTENT그냥 상수 문자열입니다.)

듣기 활동에서 다음을 정의합니다 BroadcastReceiver.

private class DataUpdateReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        if (intent.getAction().equals(RefreshTask.REFRESH_DATA_INTENT)) {
          // Do stuff - maybe update my view based on the changed DB contents
        }
    }
}

클래스 상단에 수신자를 선언합니다.

private DataUpdateReceiver dataUpdateReceiver;

이것을 onResume추가하기 위해 재정의 합니다.

if (dataUpdateReceiver == null) dataUpdateReceiver = new DataUpdateReceiver();
IntentFilter intentFilter = new IntentFilter(RefreshTask.REFRESH_DATA_INTENT);
registerReceiver(dataUpdateReceiver, intentFilter);

그리고 나는 onPause추가하기 위해 재정의 합니다.

if (dataUpdateReceiver != null) unregisterReceiver(dataUpdateReceiver);

이제 내 활동은 “이봐, 너 스스로 업데이트 해.”라는 내 서비스를 듣고 있습니다. Intent데이터베이스 테이블을 업데이트 하는 대신 데이터를 전달한 다음 활동 내에서 변경 사항을 찾기 위해 다시 돌아갈 수 있지만 변경 사항을 유지하려면 DB를 통해 데이터를 전달하는 것이 좋습니다.


답변

사용하다 LocalBroadcastManager앱 내부의 로컬 서비스에서 전송 된 방송을 청취하기 위해 수신기를 등록하는 데 합니다.

http://developer.android.com/reference/android/support/v4/content/LocalBroadcastManager.html


답변

오토 이벤트 버스 라이브러리에 대한 아무도 언급하지 않은 것에 놀랐습니다.

http://square.github.io/otto/

내 안드로이드 앱에서 이것을 사용했으며 완벽하게 작동합니다.


답변

메신저를 사용하는 것은 서비스와 활동간에 통신하는 또 다른 간단한 방법입니다.

활동에서 해당 메신저로 핸들러를 작성하십시오. 이 서비스에서 메시지를 처리합니다.

class ResponseHandler extends Handler {
    @Override public void handleMessage(Message message) {
            Toast.makeText(this, "message from service",
                    Toast.LENGTH_SHORT).show();
    }
}
Messenger messenger = new Messenger(new ResponseHandler());

메시지에 메시지를 첨부하여 메신저를 서비스에 전달할 수 있습니다.

Message message = Message.obtain(null, MyService.ADD_RESPONSE_HANDLER);
message.replyTo = messenger;
try {
    myService.send(message);
catch (RemoteException e) {
    e.printStackTrace();
}

API 데모 ( MessengerService 및 MessengerServiceActivity) 에서 전체 예제를 찾을 수 있습니다 . MyService의 작동 방식에 대한 전체 예를 참조하십시오.


답변

다른 주석에서 언급되지 않은 다른 방법은 bindService ()를 사용하여 활동에서 서비스에 바인딩하고 ServiceConnection 콜백에서 서비스 인스턴스를 얻는 것입니다. 여기에 설명 된대로 http://developer.android.com/guide/components/bound-services.html


답변

당신은 또한 LiveData처럼 작동합니다 EventBus.

class MyService : LifecycleService() {
    companion object {
        var BUS = MutableLiveData<Object>()
    }

    override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
        super.onStartCommand(intent, flags, startId)

        val testItem : Object

        // expose your data
        if (BUS.hasActiveObservers()) {
            BUS.postValue(testItem)
        }

        return START_NOT_STICKY
    }
}

그런 다음에서 관찰자를 추가하십시오 Activity.

MyService.BUS.observe(this, Observer {
    it?.let {
        // Do what you need to do here
    }
})

블로그 에서 더 많은 내용을 읽을 수 있습니다 .