Java 如何从后台服务更新 Android Activity 中的信息

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2468874/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 08:06:20  来源:igfitidea点击:

How can I update information in an Android Activity from a background Service

javaandroidandroid-listviewobserver-pattern

提问by rhinds

I am trying to create a simple Android application that has a ActivityList of information, when the application starts, I plan to start a Service that will be constantly calculating the data (it will be changing) and I want the ActivityList to be in sync with the data that the service is calculating for the life of the app.

我正在尝试创建一个具有 ActivityList 信息的简单 Android 应用程序,当应用程序启动时,我计划启动一个将不断计算数据(它会发生变化)的服务,并且我希望 ActivityList 与服务为应用程序的生命周期计算的数据。

How can I set up my Activity to be listening to the Service? Is this the best way to approach this problem?

如何设置我的活动以收听服务?这是解决这个问题的最佳方法吗?

For example, if you imagine a list of stock prices - the data would be being changed regularly and need to be in sync with the (in my case) Service that is calculating/fetching the data constantly.

例如,如果您想象一个股票价格列表 - 数据将定期更改,并且需要与(在我的情况下)不断计算/获取数据的服务同步。

Thanks in advance

提前致谢

采纳答案by CommonsWare

How can I set up my Activity to be listening to the Service? Is this the best way to approach this problem?

如何设置我的活动以收听服务?这是解决这个问题的最佳方法吗?

You have three major options, as I see it:

在我看来,您有三个主要选择:

  1. Polling. The Activityperiodically asks the Servicefor the latest data. IMHO, this option sucks, but it's certainly possible.

  2. Callbacks. Per jax's answer, the Activityregisters a callback object ("observer") with the Service. The Serviceinvokes a method on the callback when the data changes, which in turn updates the UI. You can see an example of using that with a Servicehere.

  3. Broadcast Intents. The Servicebroadcasts an Intentvia sendBroadcast()on a data change. The Activityregisters a BroadcastReceiverusing registerReceiver(), and that BroadcastReceiveris notified of an incoming broadcast. This triggers the Activityto load the latest data from the Service, or possibly just to get the latest data out of extras in the broadcast Intent. You can see an example of using that technique with a Servicehere.

  1. 轮询。将Activity定期询问Service最新数据。恕我直言,这个选项很糟糕,但这当然是可能的。

  2. 回调。根据 jax 的回答,它Activity使用Service. 在Service上调用回调方法在数据改变时,这反过来又更新UI。您可以Service在此处查看使用它的示例。

  3. 广播Intents。该Service播放器Intent通过sendBroadcast()对数据的变化。的Activity一个寄存器BroadcastReceiver使用registerReceiver(),而且BroadcastReceiver被通知传入的广播。这会触发从Activity加载最新数据Service,或者可能只是从广播中的附加数据中获取最新数据Intent。您可以Service在此处查看使用该技术的示例。

回答by jax

This sound like a good candidate for the Observer Pattern. Basically your activity (The Observer) will register itself with the background service (The Observable) and you can push or pull data from your Activity. Your Observer in this case will be your Activity and the Observable will be your Service.

这听起来像是观察者模式的一个很好的候选者。基本上你的活动(观察者)会向后台服务(观察者)注册自己,你可以从你的活动中推送或拉取数据。在这种情况下,您的观察者将是您的 Activity,而 Observable 将是您的服务。

If you know nothing about Design Patterns buy "Head First Design Patterns", it is easy to read and is full of great information.

如果您对设计模式一无所知,请购买“Head First Design Patterns”,它很容易阅读并且包含大量信息。

PS: I am reading it now.

PS:我现在正在阅读。

回答by Janusz

You will have a background thread running that calculates the changes in the list. This thread now needs a possibility to notify the GUI that the list was updated.

您将运行一个后台线程来计算列表中的更改。该线程现在需要通知 GUI 列表已更新。

You can use some kind of ArrayAdapterto get the data into the ListView. The ArrayAdapter has a method called adpater.notifyDataSetChanged()every time you call this method the adapter will see that the corresponding data has changed and then notify the listview that it should update at the next possibility.

您可以使用某种ArrayAdapter将数据放入 ListView。ArrayAdapter 有一个名为adpater.notifyDataSetChanged()的方法,每次调用此方法时,适配器都会看到相应的数据已更改,然后通知列表视图它应该在下一次更新。

回答by Arun kumar

You need to use bindService() to bind the activity with running service and communicate with it.

您需要使用 bindService() 将活动与正在运行的服务绑定并与之通信。

public class BindingActivity extends Activity {
YourService mService;
boolean mBound = false;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
}

@Override
protected void onStart() {
    super.onStart();
    // Bind to Your Service
    Intent intent = new Intent(this, YourService.class);
    bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}

@Override
protected void onStop() {
    super.onStop();
    // Unbind from the service
    if (mBound) {
        unbindService(mConnection);
        mBound = false;
    }
}

/** Called when a button is clicked (the button in the layout file attaches to
  * this method with the android:onClick attribute) */
public void onButtonClick(View v) {
    if (mBound) {
        // Call a method from your Service.
        // However, if this call were something that might hang, then this request should
        // occur in a separate thread to avoid slowing down the activity performance.
        int num = mService.getRandomNumber();
        Toast.makeText(this, "number: " + num, Toast.LENGTH_SHORT).show();
    }
}

/** Defines callbacks for service binding, passed to bindService() */
private ServiceConnection mConnection = new ServiceConnection() {

    @Override
    public void onServiceConnected(ComponentName className,
            IBinder service) {
        // We've bound to the running Service, cast the IBinder and get instance
        LocalBinder binder = (LocalBinder) service;
        mService = binder.getService();
        mBound = true;
    }

    @Override
    public void onServiceDisconnected(ComponentName arg0) {
        mBound = false;
    }
 };
}

and your service like:

以及您的服务,例如:

public class LocalService extends Service {
    // Binder given to clients
   private final IBinder mBinder = new LocalBinder();
   // Random number generator
   private final Random mGenerator = new Random();

/**
 * Class used for the client Binder.  Because we know this service always
 * runs in the same process as its clients, we don't need to deal with IPC.
 */
public class LocalBinder extends Binder {
    LocalService getService() {
        // Return this instance of LocalService so clients can call public methods
        return LocalService.this;
    }
}

@Override
public IBinder onBind(Intent intent) {
    return mBinder;
}

/** method for clients */
public int getRandomNumber() {
  return mGenerator.nextInt(100);
  }
}

回答by miroslavign

I am really, really wondering why no one mentioned a simple approach using an EventBus by whatever library. This is of course if you are not using RX. My personal favorite is EventBus by GreenRobot. https://github.com/greenrobot/EventBus

我真的非常想知道为什么没有人提到任何库都使用 EventBus 的简单方法。这当然是如果您不使用 RX。我个人最喜欢的是 GreenRobot 的 EventBus。 https://github.com/greenrobot/EventBus

With just a couple of lines of code, and no interfaces. Fire an event, and listen for it wherever you want. It is decoupled, it is thread safe, and it will not crash your app.

只需几行代码,没有接口。触发一个事件,并在任何你想要的地方收听它。它是解耦的,它是线程安全的,并且不会使您的应用程序崩溃。