728x90
반응형
곤란한 상황을 마주하였다.
상황은 다음과 같다
- TestService.java에서 TestWebviewActivity로 data를 전달한다.
- 전달 받은 값을 parameter 삼아서 webview를 연다.
- Web에서 JavascriptInterface를 호출, webview에서 web의 javascript를 호출한다.
- javascript에서 필요한 값을 다시 TestService.java에 전달한다.
여기서 startActivityForResult()를 쓸 수 없다.
intent를 사용하는 곳이 Activity가 아닌 service이기 때문이다.
이 때 사용한 것이 다름아닌 ResultReceiver이다.
Activity와 Service 간 통신할 때 자주 사용한다.
객체를 전달하면서 callback을 같이 받고 싶을 때를 위해 android에서는 ResultReceiver를 제공한다. (출저)
나 역시 필요하니깐 아래와 같이 구현했다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | // Defines a generic receiver used to pass data to Activity from a Service public class WebviewReceiver extends ResultReceiver { private Receiver receiver; // Constructor takes a handler public WebviewReceiver(Handler handler) { super(handler); } // Setter for assigning the receiver public void setReceiver(Receiver receiver) { this.receiver = receiver; } // Defines our event interface for communication public interface Receiver { void onReceiveResult(int resultCode, Bundle resultData); } // Delegate method which passes the result to the receiver if the receiver has been assigned @Override protected void onReceiveResult(int resultCode, Bundle resultData) { if (receiver != null) { receiver.onReceiveResult(resultCode, resultData); } } } | cs |
위 코드는 Starting Background Services라는 글에서 가지고 왔다.
위 인터페이스에 주목해야 한다. 결국 저기에 callback을 받아 내기 때문이다.
이해가 가지 않는다면 아래 코드에서 이용한 사례를 보면 이해가 갈 것이다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | public WebviewReceiver receiverForTest; setupServiceReceiver(); intent.putExtra("receiver", receiverForTest); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); mContext.startActivity(intent); /** * Setup the callback for when data is received from the service */ public void setupServiceReceiver() { receiverForTest = new WebviewReceiver(new Handler()); // This is where we specify what happens when data is received from the service receiverForTest.setReceiver(new WebviewReceiver.Receiver() { @Override public void onReceiveResult(int resultCode, Bundle resultData) { if (resultCode == RESULT_OK) { String resultValue = resultData.getString("resultValue"); Log.e(TAG, "onReceiveResult ::: "+response.toString()); } } }); } | cs |
setupServiceReceiver method를 살펴보자
Receiver()가 callback 자리를 잡고 있다.
그렇다면 intent를 받은 자리는 어떻게 하고 있을까?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | // Extract the receiver passed into the service final ResultReceiver rec = mainIntent.getParcelableExtra("receiver"); class MyJavaScriptInterface { @JavascriptInterface public void processWebData(String html) { // Extract additional values from the bundle // To send a message to the Activity, create a pass a Bundle Bundle bundle = new Bundle(); bundle.putString("resultValue", html); // Here we call send passing a resultCode and the bundle of extras rec.send(Activity.RESULT_OK, bundle); finish(); } } | cs |
getParcelableExtra를 ResultReceiver에 담는다.
선언된 ResultReceiver에서 보내야 될 값을 send에 담아서 수행하면
receiverForTest.setReceiver에서 override된 onReceiveResult가 동작하게 된다.
이렇게 무사히 service에 원하는 값을 전달했다.
참고로 Lifecycle에서 자유롭게 data를 쓰고 싶다면 ViewModel을 사용할 수 있다.
728x90
반응형
'Android, iOS' 카테고리의 다른 글
intent.addFlags로 자주 쓰는 상수 세트 (0) | 2018.05.31 |
---|---|
화면 전환할 때 IllegalStateException이 나타난다면? commitAllowingStateLoss (0) | 2018.04.02 |
EditText로인해 키보드가 나타나는 것을 막으려면? (0) | 2018.03.22 |
여러분, Volley라고 들어봤어요? (젠장) (0) | 2018.01.18 |
setFocusable. 키보드에도 관심을 가져줄 때. (0) | 2017.01.30 |
Comment