티스토리 뷰
Stack Overflow에 자주 검색, 등록되는 문제들과 제가 개발 중 찾아 본 문제들 중에서 나중에도 찾아 볼 것 같은 문제들을 정리하고 있습니다.
Stack Overflow에서 가장 먼저 확인하게 되는 가장 높은 점수를 받은 Solution과 현 시점에 도움이 될 수 있는 가장 최근에 업데이트(최소 점수 확보)된 Solution을 각각 정리하였습니다.
아래 word cloud를 통해 이번 포스팅의 주요 키워드를 미리 확인하세요.
Example: Communication between Activity and Service using Messaging
메시징을 사용한 액티비티와 서비스 간 커뮤니케이션 예제
문제 내용
I couldn't find any examples of how to send messages between an activity and a service, and I have spent far too many hours figuring this out. Here is an example project for others to reference.
액티비티와 서비스 간에 메시지를 보내는 방법에 대한 예를 찾을 수 없었고, 이를 파악하는 데 너무 많은 시간을 보냈습니다. 다음은 다른 사용자가 참조할 수 있는 프로젝트의 예입니다.
This example allows you to start or stop a service directly, and separately bind/unbind from the service. When the service is running, it increments a number at 10 Hz. If the activity is bound to the Service
, it will display the current value. Data is transferred as an Integer and as a String so you can see how to do that two different ways. There are also buttons in the activity to send messages to the service (changes the increment-by value).
이 예에서는 서비스를 직접 시작하거나 중지하고 서비스와 별도로 바인딩/바인딩 해제할 수 있습니다. 서비스가 실행 중일 때는 10Hz에서 숫자가 증가합니다. 액티비티가 서비스에 바인딩된 경우 현재 값이 표시됩니다. 데이터는 정수와 문자열로 전송되므로 두 가지 다른 방법을 사용하는 방법을 확인할 수 있습니다. 액티비티에는 메시지를 서비스로 전송하는 버튼도 있습니다(증가 기준 값 변경).
Screenshot:
스크린샷:
AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.exampleservice"
android:versionCode="1"
android:versionName="1.0">
<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".MainActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".MyService"></service>
</application>
<uses-sdk android:minSdkVersion="8" />
</manifest>
res\values\strings.xml:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">ExampleService</string>
<string name="service_started">Example Service started</string>
<string name="service_label">Example Service Label</string>
</resources>
res\layout\main.xml:
<RelativeLayout
android:id="@+id/RelativeLayout01"
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
<Button
android:id="@+id/btnStart"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Start Service" >
</Button>
<Button
android:id="@+id/btnStop"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:text="Stop Service" >
</Button>
</RelativeLayout>
<RelativeLayout
android:id="@+id/RelativeLayout02"
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
<Button
android:id="@+id/btnBind"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Bind to Service" >
</Button>
<Button
android:id="@+id/btnUnbind"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:text="Unbind from Service" >
</Button>
</RelativeLayout>
<TextView
android:id="@+id/textStatus"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Status Goes Here"
android:textSize="24sp" />
<TextView
android:id="@+id/textIntValue"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Integer Value Goes Here"
android:textSize="24sp" />
<TextView
android:id="@+id/textStrValue"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="String Value Goes Here"
android:textSize="24sp" />
<RelativeLayout
android:id="@+id/RelativeLayout03"
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
<Button
android:id="@+id/btnUpby1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Increment by 1" >
</Button>
<Button
android:id="@+id/btnUpby10"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:text="Increment by 10" >
</Button>
</RelativeLayout>
src\com.exampleservice\MainActivity.java:
package com.exampleservice;
import android.app.Activity;
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.Messenger;
import android.os.RemoteException;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends Activity {
Button btnStart, btnStop, btnBind, btnUnbind, btnUpby1, btnUpby10;
TextView textStatus, textIntValue, textStrValue;
Messenger mService = null;
boolean mIsBound;
final Messenger mMessenger = new Messenger(new IncomingHandler());
class IncomingHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MyService.MSG_SET_INT_VALUE:
textIntValue.setText("Int Message: " + msg.arg1);
break;
case MyService.MSG_SET_STRING_VALUE:
String str1 = msg.getData().getString("str1");
textStrValue.setText("Str Message: " + str1);
break;
default:
super.handleMessage(msg);
}
}
}
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
mService = new Messenger(service);
textStatus.setText("Attached.");
try {
Message msg = Message.obtain(null, MyService.MSG_REGISTER_CLIENT);
msg.replyTo = mMessenger;
mService.send(msg);
}
catch (RemoteException e) {
// In this case the service has crashed before we could even do anything with it
}
}
public void onServiceDisconnected(ComponentName className) {
// This is called when the connection with the service has been unexpectedly disconnected - process crashed.
mService = null;
textStatus.setText("Disconnected.");
}
};
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
btnStart = (Button)findViewById(R.id.btnStart);
btnStop = (Button)findViewById(R.id.btnStop);
btnBind = (Button)findViewById(R.id.btnBind);
btnUnbind = (Button)findViewById(R.id.btnUnbind);
textStatus = (TextView)findViewById(R.id.textStatus);
textIntValue = (TextView)findViewById(R.id.textIntValue);
textStrValue = (TextView)findViewById(R.id.textStrValue);
btnUpby1 = (Button)findViewById(R.id.btnUpby1);
btnUpby10 = (Button)findViewById(R.id.btnUpby10);
btnStart.setOnClickListener(btnStartListener);
btnStop.setOnClickListener(btnStopListener);
btnBind.setOnClickListener(btnBindListener);
btnUnbind.setOnClickListener(btnUnbindListener);
btnUpby1.setOnClickListener(btnUpby1Listener);
btnUpby10.setOnClickListener(btnUpby10Listener);
restoreMe(savedInstanceState);
CheckIfServiceIsRunning();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString("textStatus", textStatus.getText().toString());
outState.putString("textIntValue", textIntValue.getText().toString());
outState.putString("textStrValue", textStrValue.getText().toString());
}
private void restoreMe(Bundle state) {
if (state!=null) {
textStatus.setText(state.getString("textStatus"));
textIntValue.setText(state.getString("textIntValue"));
textStrValue.setText(state.getString("textStrValue"));
}
}
private void CheckIfServiceIsRunning() {
//If the service is running when the activity starts, we want to automatically bind to it.
if (MyService.isRunning()) {
doBindService();
}
}
private OnClickListener btnStartListener = new OnClickListener() {
public void onClick(View v){
startService(new Intent(MainActivity.this, MyService.class));
}
};
private OnClickListener btnStopListener = new OnClickListener() {
public void onClick(View v){
doUnbindService();
stopService(new Intent(MainActivity.this, MyService.class));
}
};
private OnClickListener btnBindListener = new OnClickListener() {
public void onClick(View v){
doBindService();
}
};
private OnClickListener btnUnbindListener = new OnClickListener() {
public void onClick(View v){
doUnbindService();
}
};
private OnClickListener btnUpby1Listener = new OnClickListener() {
public void onClick(View v){
sendMessageToService(1);
}
};
private OnClickListener btnUpby10Listener = new OnClickListener() {
public void onClick(View v){
sendMessageToService(10);
}
};
private void sendMessageToService(int intvaluetosend) {
if (mIsBound) {
if (mService != null) {
try {
Message msg = Message.obtain(null, MyService.MSG_SET_INT_VALUE, intvaluetosend, 0);
msg.replyTo = mMessenger;
mService.send(msg);
}
catch (RemoteException e) {
}
}
}
}
void doBindService() {
bindService(new Intent(this, MyService.class), mConnection, Context.BIND_AUTO_CREATE);
mIsBound = true;
textStatus.setText("Binding.");
}
void doUnbindService() {
if (mIsBound) {
// If we have received the service, and hence registered with it, then now is the time to unregister.
if (mService != null) {
try {
Message msg = Message.obtain(null, MyService.MSG_UNREGISTER_CLIENT);
msg.replyTo = mMessenger;
mService.send(msg);
}
catch (RemoteException e) {
// There is nothing special we need to do if the service has crashed.
}
}
// Detach our existing connection.
unbindService(mConnection);
mIsBound = false;
textStatus.setText("Unbinding.");
}
}
@Override
protected void onDestroy() {
super.onDestroy();
try {
doUnbindService();
}
catch (Throwable t) {
Log.e("MainActivity", "Failed to unbind from the service", t);
}
}
}
src\com.exampleservice\MyService.java:
package com.exampleservice;
import java.util.ArrayList;
import java.util.Timer;
import java.util.TimerTask;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.util.Log;
public class MyService extends Service {
private NotificationManager nm;
private Timer timer = new Timer();
private int counter = 0, incrementby = 1;
private static boolean isRunning = false;
ArrayList<Messenger> mClients = new ArrayList<Messenger>(); // Keeps track of all current registered clients.
int mValue = 0; // Holds last value set by a client.
static final int MSG_REGISTER_CLIENT = 1;
static final int MSG_UNREGISTER_CLIENT = 2;
static final int MSG_SET_INT_VALUE = 3;
static final int MSG_SET_STRING_VALUE = 4;
final Messenger mMessenger = new Messenger(new IncomingHandler()); // Target we publish for clients to send messages to IncomingHandler.
@Override
public IBinder onBind(Intent intent) {
return mMessenger.getBinder();
}
class IncomingHandler extends Handler { // Handler of incoming messages from clients.
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_REGISTER_CLIENT:
mClients.add(msg.replyTo);
break;
case MSG_UNREGISTER_CLIENT:
mClients.remove(msg.replyTo);
break;
case MSG_SET_INT_VALUE:
incrementby = msg.arg1;
break;
default:
super.handleMessage(msg);
}
}
}
private void sendMessageToUI(int intvaluetosend) {
for (int i=mClients.size()-1; i>=0; i--) {
try {
// Send data as an Integer
mClients.get(i).send(Message.obtain(null, MSG_SET_INT_VALUE, intvaluetosend, 0));
//Send data as a String
Bundle b = new Bundle();
b.putString("str1", "ab" + intvaluetosend + "cd");
Message msg = Message.obtain(null, MSG_SET_STRING_VALUE);
msg.setData(b);
mClients.get(i).send(msg);
}
catch (RemoteException e) {
// The client is dead. Remove it from the list; we are going through the list from back to front so this is safe to do inside the loop.
mClients.remove(i);
}
}
}
@Override
public void onCreate() {
super.onCreate();
Log.i("MyService", "Service Started.");
showNotification();
timer.scheduleAtFixedRate(new TimerTask(){ public void run() {onTimerTick();}}, 0, 100L);
isRunning = true;
}
private void showNotification() {
nm = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
// In this sample, we'll use the same text for the ticker and the expanded notification
CharSequence text = getText(R.string.service_started);
// Set the icon, scrolling text and timestamp
Notification notification = new Notification(R.drawable.icon, text, System.currentTimeMillis());
// The PendingIntent to launch our activity if the user selects this notification
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, MainActivity.class), 0);
// Set the info for the views that show in the notification panel.
notification.setLatestEventInfo(this, getText(R.string.service_label), text, contentIntent);
// Send the notification.
// We use a layout id because it is a unique number. We use it later to cancel.
nm.notify(R.string.service_started, notification);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i("MyService", "Received start id " + startId + ": " + intent);
return START_STICKY; // run until explicitly stopped.
}
public static boolean isRunning()
{
return isRunning;
}
private void onTimerTick() {
Log.i("TimerTick", "Timer doing work." + counter);
try {
counter += incrementby;
sendMessageToUI(counter);
}
catch (Throwable t) { //you should always ultimately catch all exceptions in timer tasks.
Log.e("TimerTick", "Timer Tick Failed.", t);
}
}
@Override
public void onDestroy() {
super.onDestroy();
if (timer != null) {timer.cancel();}
counter=0;
nm.cancel(R.string.service_started); // Cancel the persistent notification.
Log.i("MyService", "Service Stopped.");
isRunning = false;
}
}
높은 점수를 받은 Solution
Look at the LocalService example.
LocalService 예제를 살펴봅니다.
Your Service
returns an instance of itself to consumers who call onBind
. Then you can directly interact with the service, e.g. registering your own listener interface with the service, so that you can get callbacks.
서비스는 Bind를 호출하는 소비자에게 자체 인스턴스를 반환합니다. 그런 다음 서비스와 직접 상호 작용할 수 있습니다. 예를 들어, 서비스에 자신의 리스너 인터페이스를 등록하여 콜백을 받을 수 있습니다.
가장 최근 달린 Solution
For sending data to a service you can use:
서비스로 데이터를 전송하는 경우 다음을 사용할 수 있습니다.
Intent intent = new Intent(getApplicationContext(), YourService.class);
intent.putExtra("SomeData","ItValue");
startService(intent);
And after in service in onStartCommand() get data from intent.
그리고 onStartCommand()에서 서비스를 시작한 후 인텐트에서 데이터를 가져옵니다.
For sending data or event from a service to an application (for one or more activities):
서비스에서 응용 프로그램으로 데이터 또는 이벤트를 전송하는 경우(하나 이상의 액티비티에 대해):
private void sendBroadcastMessage(String intentFilterName, int arg1, String extraKey) {
Intent intent = new Intent(intentFilterName);
if (arg1 != -1 && extraKey != null) {
intent.putExtra(extraKey, arg1);
}
sendBroadcast(intent);
}
This method is calling from your service. You can simply send data for your Activity.
이 메서드는 서비스에서 호출하는 것입니다. 액티비티에 대한 데이터를 전송할 수 있습니다.
private void someTaskInYourService(){
//For example you downloading from server 1000 files
for(int i = 0; i < 1000; i++) {
Thread.sleep(5000) // 5 seconds. Catch in try-catch block
sendBroadCastMessage(Events.UPDATE_DOWNLOADING_PROGRESSBAR, i,0,"up_download_progress");
}
For receiving an event with data, create and register method registerBroadcastReceivers() in your activity:
데이터가 포함된 이벤트를 수신하려면 액티비티에 BroadcastReceivers()를 등록하는 방법을 생성하고 등록합니다.
private void registerBroadcastReceivers(){
broadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
int arg1 = intent.getIntExtra("up_download_progress",0);
progressBar.setProgress(arg1);
}
};
IntentFilter progressfilter = new IntentFilter(Events.UPDATE_DOWNLOADING_PROGRESS);
registerReceiver(broadcastReceiver,progressfilter);
For sending more data, you can modify method sendBroadcastMessage();
. Remember: you must register broadcasts in onResume() & unregister in onStop() methods!
추가 데이터 전송을 위해 sendBroadcastMessage(); 메서드를 수정할 수 있습니다. 기억하세요: 브로드캐스트는 onResume()에 등록하고 onStop() 메서드에 등록 취소해야 합니다!
UPDATE
업데이트
Please don't use my type of communication between Activity & Service. This is the wrong way. For a better experience please use special libs, such us:
액티비티 및 서비스 간에 내가 하는 통신 방식을 사용하지 마세요. 이것은 잘못된 방법입니다. 더 나은 경험을 위해 다음과 같은 특별한 lib를 사용하십시오.
1) EventBus from greenrobot
2) Otto from Square Inc
P.S. I'm only using EventBus from greenrobot in my projects,
추신: 저는 프로젝트에서 greenbot의 이벤트 버스만 사용하고 있습니다.
출처 : https://stackoverflow.com/questions/4300291/example-communication-between-activity-and-service-using-messaging
'개발 > 안드로이드' 카테고리의 다른 글
AsyncTask Android 예제 (0) | 2022.12.06 |
---|---|
서비스에서 컨텍스트 가져오기 (0) | 2022.12.06 |
시스템 오버레이 윈도우(항상 다른 앱 위에) 만들기 (0) | 2022.12.05 |
컨텍스트 또는 액티비티 외부에서 getString 사용하기 (0) | 2022.12.05 |
WebView에서 파일 업로드하기 (0) | 2022.12.05 |