Ich habe in SO diesbezüglich viele Beiträge gesehen, konnte aber nicht die genaue und einfachste Methode zum Aufrufen einer Aktivitätsmethode aus der Serviceklasse erhalten. Ist der Broadcast-Empfänger nur die Option? Kein einfacher Ausweg ? Ich muss nur die folgende Methode in der Activity-Klasse aufrufen, nachdem der Media Player in der Service-Klasse vorbereitet wurde.
Aktivitätsklasse:
public void updateProgress() {
// set Progress bar values
songProgressBar.setProgress(0);
songProgressBar.setMax(100);
// Updating progress bar
updateProgressBar();
}
Serviceklasse:
@Override
public IBinder onBind(Intent intent) {
Log.d(this.getClass().getName(), "BIND");
return musicBind;
}
@Override
public boolean onUnbind(Intent intent) {
return false;
}
@Override
public void onPrepared(MediaPlayer mp) {
try {
mp.start();
} catch (IllegalStateException e) {
e.printStackTrace();
}
// updateProgress();// Need to call the Activity method here
}
Definieren Sie eine Schnittstelle, die Ihr Service zur Kommunikation von Ereignissen verwendet:
public interface ServiceCallbacks {
void doSomething();
}
Schreiben Sie Ihre Service-Klasse. Ihre Aktivität wird an diesen Dienst gebunden. Folgen Sie dem hier gezeigten Beispiel . Zusätzlich fügen wir eine Methode hinzu, um ServiceCallbacks
festzulegen.
public class MyService extends Service {
// Binder given to clients
private final IBinder binder = new LocalBinder();
// Registered callbacks
private ServiceCallbacks serviceCallbacks;
// Class used for the client Binder.
public class LocalBinder extends Binder {
MyService getService() {
// Return this instance of MyService so clients can call public methods
return MyService.this;
}
}
@Override
public IBinder onBind(Intent intent) {
return binder;
}
public void setCallbacks(ServiceCallbacks callbacks) {
serviceCallbacks = callbacks;
}
}
Schreiben Sie Ihre Activity-Klasse nach demselben Leitfaden, implementieren Sie jedoch auch Ihre ServiceCallbacks-Schnittstelle. Wenn Sie den Dienst binden/die Bindung aufheben, werden Sie ihn registrieren bzw. die Registrierung aufheben, indem Sie setCallbacks
im Dienst aufrufen.
public class MyActivity extends Activity implements ServiceCallbacks {
private MyService myService;
private boolean bound = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(...);
}
@Override
protected void onStart() {
super.onStart();
// bind to Service
Intent intent = new Intent(this, MyService.class);
bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
}
@Override
protected void onStop() {
super.onStop();
// Unbind from service
if (bound) {
myService.setCallbacks(null); // unregister
unbindService(serviceConnection);
bound = false;
}
}
/** Callbacks for service binding, passed to bindService() */
private ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName className, IBinder service) {
// cast the IBinder and get MyService instance
LocalBinder binder = (LocalBinder) service;
myService = binder.getService();
bound = true;
myService.setCallbacks(MyActivity.this); // register
}
@Override
public void onServiceDisconnected(ComponentName arg0) {
bound = false;
}
};
/* Defined by ServiceCallbacks interface */
@Override
public void doSomething() {
...
}
}
Wenn Ihr Dienst nun wieder mit der Aktivität kommunizieren möchte, rufen Sie einfach eine der Schnittstellenmethoden von früher auf. In Ihrem Dienst:
if (serviceCallbacks != null) {
serviceCallbacks.doSomething();
}
Verwenden Sie den Broadcast-Empfänger mit Dienst zum Aktualisieren Ihrer Ansicht aus der Dienstklasse . Beispiel:
In meiner Aktivitätsklasse
public class ServiceDemoActivity extends Activity {
Intent intent;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
final TextView notification = (TextView) findViewById(R.id.notification);
if (CheckIfServiceIsRunning()) {
} else {
startService(new Intent(this, MyService.class));
}
}
private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
updateDate(intent);
}
};
private void updateDate(Intent intent) {
String time = intent.getStringExtra("time");
Toast.makeText(getApplicationContext(), "Yea!!! Service called", Toast.LENGTH_SHORT).show();
TextView date = (TextView) findViewById(R.id.date);
date.setText(time);
}
@Override
public void onResume() {
super.onResume();
registerReceiver(broadcastReceiver, new IntentFilter(
MyService.BROADCAST_ACTION));
}
}
In meiner Service-Klasse rufe ich nach einiger Zeit, in der meine Benutzeroberfläche aktualisiert wird, mein Update auf.
public class MyService extends Service {
public static final String
BROADCAST_ACTION = "com.mukesh.service";
private final Handler handler = new Handler();
@Override
public void onCreate() {
intent = new Intent(BROADCAST_ACTION);
}
@Override
public void onDestroy() {
stopService(intent);
}
@Override
public void onStart(Intent intent, int startid) {
int i = 0;
while (i <= 2) {
if (i > 1) {
i++;
this.onDestroy();
} else {
counter = i;
i++;
handler.removeCallbacks(sendUpdatesToUI);
handler.postDelayed(sendUpdatesToUI, 1 * 1000); // 1 sec
}
}
}
private Runnable sendUpdatesToUI = new Runnable() {
public void run() {
DisplayLoggingInfo();
handler.postDelayed(this, 7 * 1000); // 7 sec
}
};
private void DisplayLoggingInfo() {
intent.putExtra("time", new Date().toLocaleString());
intent.putExtra("counter", String.valueOf(counter));
sendBroadcast(intent);
stopService(intent);
}
}
Vollständigen Code finden Sie unter link
Ich habe eine allgemeine Klasse namens Delegate erstellt (dies ist kein spezieller Name, Sie können sie John nennen) und die MainActivity-Klasse als statisches Feld übergeben. Dann kann ich vom Dienst aus auf den Dienst zugreifen. Ich bin nicht sicher, ob es kostengünstig ist, aber es hat das Problem für mich einfach gelöst.
Mein Service:
package com.some.package;
import com.google.firebase.iid.FirebaseInstanceId;
import com.google.firebase.iid.FirebaseInstanceIdService;
public class FirebaseInstanceIDService extends FirebaseInstanceIdService {
@Override
public void onTokenRefresh() {
String token = FirebaseInstanceId.getInstance().getToken();
Delegate.theMainActivity.onDeviceTokenChange(token);
}
}
Delegierte Klasse:
package com.some.package;
public class Delegate {
static MainActivity theMainActivity;
}
Was ich in MainActivity gemacht habe:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Delegate.theMainActivity = this;
//rest of the code...
}
public void onDeviceTokenChange(String token){
Log.e("updated token:", token);
}
Sie können Ihre Dienstmethode nicht direkt aus Ihrer Aktivität oder umgekehrt aufrufen. Es gibt drei Möglichkeiten, mit einem Dienst zu kommunizieren. Verwenden von Broadcastern und Empfängern, Verwenden von Messenger
oder Binden an den Dienst. Weitere Informationen finden Sie unter http://developer.Android.com/guide/components/bound-services.html
Sie können von Ihrem Dienst anrufen
getContentResolver().notifyChange(uri, null);
und in Ihrer Aktivität richten Sie ein
getContentResolver().registerContentObserver(uri, false, new ContentObserver(getHandler())
{
public void onChange(boolean selfChange)
{
updateProgress()
}
};
die onChange-Methode wird für den UI-Thread aufgerufen
Sie können eine Aktivitätsmethode aus dem Dienst aufrufen, indem Sie Ihren eigenen Listener wie folgt implementieren https://stackoverflow.com/a/18585247/5361964
Sie könnten Ihre Aktivitätsmethode in runOnUiThread
wie folgt ausführen:
// method will be called from service
override fun callback(activity: Activity, result: String) {
runOnUiThread{
Toast.makeText(activity, result, Toast.LENGTH_LONG).show()
}
}