如何将 IntentService 中的结果返回到 Activity?

43

我正在使用IntentService通过JSON与服务器处理网络通信。 JSON / 服务器部分工作正常,但我在将结果返回到需要它们的位置方面遇到了问题。以下代码显示了我如何从onClick()内部启动意图服务,然后使服务更新全局变量以将结果传递回主活动。

public class GXActivity extends Activity {

    private static final String TAG = "GXActivity";

    @Override
    public void onCreate(Bundle savedInstanceState) {
        // === called when the activity is first created

        Log.i(TAG, "GXActivity Created");

        super.onCreate(savedInstanceState);
        setContentView(R.layout.start);

        View.OnClickListener handler = new View.OnClickListener() {
            public void onClick(View v) {

                // === set up an application context to hold a global variable
                // === called user, to contain results from the intent service
                GXApp appState = ((GXApp) getApplicationContext());
                User user = new User(-1); // initialize user id to -1
                appState.setUser(user);

                // === next start an intent service to get JSON from the server;
                // === this service updates the user global variable with
                // === results from the JSON transaction
                Intent intent = new Intent(this, GXIntentService.class);
                startService(intent);

                // === check app context for results from intent service
                appState = ((GXApp) getApplicationContext());
                if (appState.getUser().getId() != -1)...

            }
        }
    }
}

我遇到的问题是,解析JSON的Intent服务直到onCreate()完成后才被调用,因此我的代码在查看未初始化的结果时会被卡住。

我应该怎么做才能在检查结果之前调用Intent服务?如果将点击监听器从onCreate()函数中拉出来,是否有效?还有其他更好的编写代码结构的方法吗?非常感谢。


1
请查看此链接,可能会有所帮助:https://dev59.com/42ox5IYBdhLWcg3wnViz#9089086 - Zaz Gmy
4个回答

86
你应该在你的活动中创建自己的ResultReceiver子类。 ResultReceiver实现了Parcelable,因此可以作为Intent的额外参数从你的Activity传递到你的Service中。
你需要像这样做:
  1. 在您的活动类中实现一个 ResultReceiver 的子类。要实现的关键方法是 onReceiveResult()。此方法为您提供了一个结果数据的 Bundle,可用于传递您在 Service 中检索的任何信息。只需解包所需的数据并使用它来更新您的活动即可。

  2. 在您的活动中,创建您自定义的 ResultReceiver 的新实例,并将其添加到您用于启动服务的 Intent 中。

  3. 在您的 ServiceonStartCommand() 方法中,检索在 Intent 上传递的 ResultReceiver 并将其存储在本地成员变量中。

  4. 一旦您的 Service 完成其工作,就让它调用 send() 在 ResultReceiver 上,将您想要发送回活动的任何数据都传递给一个 Bundle

这是一种非常有效的模式,意味着您不会将数据存储在难看的静态变量中。


3
еҰӮжһңеңЁз»“жһңи°ғз”ЁResultReceiverзҡ„send()ж—¶пјҢActivityдёҚеҶҚеӨ„дәҺжҙ»еҠЁзҠ¶жҖҒпјҢдјҡеҸ‘з”ҹд»Җд№Ҳпјҹ - Dheeraj Vepakomma
这是一个不错的解决方案。以前我一直在编写接口。 - Prashanth Debbadwar
1
假设我使用Activity A传递ResultReceiverIntentService中启动。现在,当IntentService正在执行时,我旋转设备,Activity A被杀死并重新创建。然后,IntentService完成任务并在ResultReceiver上调用send()。但是原始活动已不再存在。你如何处理这个问题?这种模式如何处理方向更改 - Henry
2
我有类似的需求并进入了这个线程。有没有关于Activity被销毁和重新创建的问题的答案? - Gordon Liang
1
请纠正我,如果原始Activity被销毁并重新创建(例如通过设备旋转),那么ResultReceiver将无法工作,对吗? - Micro
显示剩余5条评论

12

在后台执行任务并返回结果的方式有很多种(AsyncTask,将Activity绑定到Service...),但如果你想保持IntentService的代码不变,你可以简单地执行以下操作:

1- 在IntentService工作结束时发送一个带有状态信息扩展数据的广播Intent。

2- 在您的Activity中实现一个LocalBroadcastReceiver,以消费来自Intent的数据。

这也是官方文档中推荐的方式(如果你想保持你的IntentService):

https://developer.android.com/training/run-background-service/report-status.html


7

如果您只需要从服务器获取JSON而不会锁定UI线程,那么使用AsyncTask可能更简单。


2
异步任务的生命周期绑定在它运行的线程上,因此如果我旋转屏幕,它将会被重新启动! - hadi

1
您可以使用Otto库。 Otto是一个开源项目,旨在提供事件总线实现,以便组件可以发布和订阅事件。

不确定Otto或GreenBus是否能在IntentService的线程中工作。 - Genc

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接