9

我正在编写音乐播放器,音乐在后台播放Service。当用户杀死Activitywhich hosts 3 Fragments,然后再次重新启动时,我从Activity发送一个包含有关当前播放歌曲的信息以及用户添加到其会话的歌曲列表的信息。BroadcastService

问题是,每次我想将最后的信息设置为什么都Fragments没有发生,因为它们的创建时间太长,并且Broadcast没有得到应有的处理。

我怎样才能让ServiceBroadcast等到创建片段以便适当处理它们?

以下是相关的代码片段:

//When the activity binds to the service, refresh the fragments
private ServiceConnection conn = new ServiceConnection() {
    public void onServiceConnected(ComponentName className, IBinder service) {
        LocalBinder binder = (LocalBinder) service;
        myService = binder.getService();
        myService.setBound(true);
        if(myService.startedOnce) {
            myService.refreshFragments();
        }
        myService.startedOnce = true;
    }
}

//This is the broadcast receiver of the Fragment
//it receives the broadcast too soon, and I can't set the
//Views so they are always empty.
public void onReceive(Context context, Intent intent) {
    String action = intent.getAction();
    if (action.equals(MusicService.REFRESH_ALL)) {
        Song current = intent.getParcelableExtra("song");
        setCurrentSong(current);
    }
}
4

4 回答 4

14

最简单的做法就是保留信息,直到 Fragment 准备好显示它。使用 Fragment 的setArguments()方法将信息附加到 Fragment 中。

@Override
public void onReceive() {
   String action = intent.getAction();
   if(action.equals(MusicService.REFRESH_ALL)) {
      // Creating a new Bundle so the Fragment can control its own object
      Bundle args = new Bundle(intent.getExtras()); 
      Fragment fr = getUsingFragment();
      fr.setArguments(fr);
   }
}

然后,在 Fragment 中,onCreateView()只需从中提取参数getArguments()并使用这些值构建视图。

@Override
public void onCreateView (LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
   Bundle args = getArguments();
   if(args != null) {
      // code to set values if arguments are set
   } else {
      // code to set values if arguments are not set
   }
}

另一种方法是使用 setter 方法,其中 Fragment 本身将值放入 Bundle for setArguments(). 这样,当 Fragment 的视图被销毁并且必须重新创建时,您可以在创建视图时更新视图,并为可能的事件设置参数。

注意:您只能setArguments()在 Fragment 附加到 Activity 之前调用。setArguments但是,您可以通过从中检索对它的引用来更新您传入的 Bundle getArguments(),然后只需输入值。setArguments()因此,不要从您的接收器呼叫,而是执行以下操作:

public void setCurrentSong(Song extra) {
   Bundle args = getArguments();
   args.putParcable(KEY_MAP, extra);
   if(/* Views are created */) {
      // update and invalidate the views
   }
}
于 2012-11-12T14:44:11.833 回答
3

我是如何解决这个问题的

当我使用媒体播放服务时,我想从服务中调出最后收听的歌曲,以便直接播放。这是旧逻辑,但我实际上围绕它构建了我的代码。直到到目前为止我碰到了它。

这正在发生

  • FragmentActivity被建造
  • Service开始并绑定到
  • 同时Fragmentsget异步创建
  • Service开始,它就会发出一个Broadcast带有最新信息的
  • 因为 theServiceFragmentCreation 都是异步的,广播将从服务发送,但因为BroadcastReceiversinFragments甚至还没有初始化,所以他们不会收到Intent.

我做了什么来解决它

我不知何故不得不使用一个回调来确保

  • 服务已创建并绑定到
  • 创建的片段和视图已设置

所以我使用了ServiceConnectionand 准确地说,这个onServiceConnected()方法。在那里,我得到了保存最后一首歌曲的偏好,然后发送BroadcastFragments接收它,Views并适当地设置了。这也适用于方向变化。

编码

//This is the code in the FragmentActivity
private ServiceConnection conn = new ServiceConnection() {
    public void onServiceConnected(ComponentName className, IBinder service) {
        LocalBinder binder = (LocalBinder) service;
        myService = binder.getService();
        myService.setBound(true);
        if (myService.startedOnce) {
            myService.refreshFragments();
        } else {
            sendLastSavedSong();
        }
        myService.startedOnce = true;
    }

    public void onServiceDisconnected(ComponentName className) {
        myService.setBound(false);
    }
};
于 2012-11-13T16:36:31.150 回答
0

你不能在片段中做一些事情吗?

Song current=null;
public void onReceive(Context context, Intent intent) {
    String action = intent.getAction();
    if (action.equals(MusicService.REFRESH_ALL)) {
        current = intent.getParcelableExtra("song");
    }
}

@Override
public void onResume()
{
    if(current!=null) setCurrentSong(current);
    super.onResume();
}
于 2012-11-12T13:13:39.543 回答
0

我的解决方案只是创建自己的回调接口。在你的片段的 onCreateView 方法的最后调用你的回调方法,它告诉你的 mainactivity 创建已经完成。

它对我有用,希望对你也有帮助。

于 2014-06-29T03:00:24.857 回答