예 : 메시징을 사용한 활동과 서비스 간의 통신
활동과 서비스간에 메시지를 보내는 방법에 대한 예를 찾을 수 없었고이를 파악하는 데 너무 많은 시간을 보냈습니다. 다음은 다른 사람들이 참조 할 수있는 예제 프로젝트입니다.
이 예제를 사용하면 서비스를 직접 시작하거나 중지 할 수 있으며 서비스와 별도로 바인딩 / 바인딩 해제 할 수 있습니다. 서비스가 실행 중이면 10Hz에서 숫자가 증가합니다. 활동이에 바인딩 된 경우 Service
현재 값이 표시됩니다. 데이터는 정수 및 문자열로 전송되므로 두 가지 방법으로 수행하는 방법을 볼 수 있습니다. 활동에는 서비스에 메시지를 보내는 버튼도 있습니다 (증가 값 변경).
스크린 샷 :
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;
}
}
상기 봐 LocalService를 예 .
귀하의 Service
반환 전화를 소비자에게 자신의 인스턴스 onBind
. 그런 다음 서비스와 직접 상호 작용할 수 있습니다 (예 : 서비스에 자체 리스너 인터페이스 등록). 그러면 콜백을받을 수 있습니다.
서비스에 데이터를 보내기 위해 다음을 사용할 수 있습니다.
Intent intent = new Intent(getApplicationContext(), YourService.class);
intent.putExtra("SomeData","ItValue");
startService(intent);
그리고 onStartCommand ()의 서비스 후에는 의도에서 데이터를 가져옵니다.
서비스에서 애플리케이션으로 데이터 또는 이벤트를 보내는 경우 (하나 이상의 활동에 대해) :
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);
}
이 메서드는 서비스에서 호출됩니다. 활동에 대한 데이터를 간단히 보낼 수 있습니다.
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");
}
데이터가있는 이벤트를 받으려면 활동에서 registerBroadcastReceivers () 메서드를 만들고 등록합니다.
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);
더 많은 데이터를 보내려면 method를 수정할 수 있습니다 sendBroadcastMessage();
. 기억하세요 : onResume ()에 방송을 등록하고 onStop () 메소드에 등록을 취소해야합니다!
최신 정보
활동과 서비스간에 내 유형의 커뮤니케이션을 사용하지 마십시오. 이것은 잘못된 방법입니다. 더 나은 경험을 위해 다음과 같은 특수 라이브러리를 사용하십시오.
1) 그린 로봇의 EventBus
2) Square Inc의 오토
추신 : 내 프로젝트에서 greenrobot의 EventBus 만 사용하고 있습니다.
참고 : 서비스가 실행되고 있지 않은 경우 시작 CheckIfServiceIsRunning()
되므로 서비스가 실행 중인지 확인할 필요 bindService()
가 없습니다.
또한 : 전화를 회전하면 bindService()
다시 onCreate()
호출 되기 때문에 다시 원하지 않습니다 . onConfigurationChanged()
이를 방지하기 위해 정의 해야합니다.
Message msg = Message.obtain(null, 2, 0, 0);
Bundle bundle = new Bundle();
bundle.putString("url", url);
bundle.putString("names", names);
bundle.putString("captions",captions);
msg.setData(bundle);
그래서 당신은 그것을 서비스로 보냅니다. 나중에 받으십시오.
모든 것이 괜찮습니다 . 메신저를activity/service
사용한 커뮤니케이션의 좋은 예입니다 .
하나의 코멘트 : 방법 MyService.isRunning()
은 필요하지 않습니다 .. bindService()
여러 번 수행 할 수 있습니다. 그것에 해를 끼치 지 않습니다.
MyService가 다른 프로세스에서 실행중인 경우 정적 함수 MyService.isRunning()
는 항상 false를 반환합니다. 따라서이 기능이 필요하지 않습니다.
이것이 내가 활동-> 서비스 커뮤니케이션을 구현 한 방법입니다.
private static class MyResultReciever extends ResultReceiver {
/**
* Create a new ResultReceive to receive results. Your
* {@link #onReceiveResult} method will be called from the thread running
* <var>handler</var> if given, or from an arbitrary thread if null.
*
* @param handler
*/
public MyResultReciever(Handler handler) {
super(handler);
}
@Override
protected void onReceiveResult(int resultCode, Bundle resultData) {
if (resultCode == 100) {
//dostuff
}
}
그런 다음 이것을 사용하여 서비스를 시작했습니다.
protected void onCreate(Bundle savedInstanceState) {
MyResultReciever resultReciever = new MyResultReciever(handler);
service = new Intent(this, MyService.class);
service.putExtra("receiver", resultReciever);
startService(service);
}
내 서비스에서 나는
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent != null)
resultReceiver = intent.getParcelableExtra("receiver");
return Service.START_STICKY;
}
도움이 되었기를 바랍니다
"Handler.Callback 구현"으로 활동을 선언하여 메모리를 절약 할 수 있었던 것 같습니다.
훌륭한 튜토리얼, 환상적인 프레젠테이션. 깔끔하고 간단하며 짧고 매우 설명 적입니다. 그러나 notification.setLatestEventInfo(this, getText(R.string.service_label), text, contentIntent);
방법은 더 이상 없습니다. trante가 여기 에 언급했듯이 좋은 접근 방식은 다음과 같습니다.
private static final int NOTIFICATION_ID = 45349;
private void showNotification() {
NotificationCompat.Builder builder =
new NotificationCompat.Builder(this)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle("My Notification Title")
.setContentText("Something interesting happened");
Intent targetIntent = new Intent(this, MainActivity.class);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, targetIntent, PendingIntent.FLAG_UPDATE_CURRENT);
builder.setContentIntent(contentIntent);
_nManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
_nManager.notify(NOTIFICATION_ID, builder.build());
}
@Override
public void onDestroy() {
super.onDestroy();
if (_timer != null) {_timer.cancel();}
_counter=0;
_nManager.cancel(NOTIFICATION_ID); // Cancel the persistent notification.
Log.i("PlaybackService", "Service Stopped.");
_isRunning = false;
}
직접 확인하면 모든 것이 매력처럼 작동합니다 (활동 및 서비스 이름은 원본과 다를 수 있음).
나는 모든 대답을 보았다. 나는 지금 하루 가장 강력한 방법을 말하고 싶다 . 그러면 Activity - Service - Dialog - Fragments
(Everything) 간에 소통 할 수 있습니다 .
내 프로젝트에서 사용중인이 lib에는 메시징과 관련된 훌륭한 기능이 있습니다.
3 단계의 EventBus
이벤트 정의 :
public static class MessageEvent { /* Additional fields if needed */ }
구독자 준비 :
구독 방법을 선언하고 주석을 달고 선택적으로 스레드 모드를 지정 합니다 .
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(MessageEvent event) {/* Do something */};
구독자를 등록 및 등록 취소하십시오. 예를 들어 Android에서 활동과 조각은 일반적으로 수명주기에 따라 등록해야합니다.
@Override
public void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}
@Override
public void onStop() {
super.onStop();
EventBus.getDefault().unregister(this);
}
이벤트 게시 :
EventBus.getDefault().post(new MessageEvent());
앱 수준 gradle에이 종속성을 추가하기 만하면됩니다.
compile 'org.greenrobot:eventbus:3.1.1'
'code' 카테고리의 다른 글
C # DateTime을 "YYYYMMDDHHMMSS"형식으로 (0) | 2020.10.03 |
---|---|
외래 키 제한 테이블을 자르는 방법은 무엇입니까? (0) | 2020.10.03 |
Visual Studio에서 모든 대문자 메뉴 제목을 비활성화하는 방법 (0) | 2020.10.03 |
StringBuilder를 어떻게 지우거나 비울 수 있습니까? (0) | 2020.10.03 |
사전 매핑 반전 / 반전 (0) | 2020.10.03 |