等待操作,直到创建Fragment的视图

tol*_*gap 9 android transactions android-service android-fragments

我正在编写音乐播放器,音乐在后台播放Service.当用户关闭Activity它承载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);
    }
}
Run Code Online (Sandbox Code Playgroud)

Dee*_*eeV 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);
   }
}
Run Code Online (Sandbox Code Playgroud)

然后,在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
   }
}
Run Code Online (Sandbox Code Playgroud)

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

注意:您只能setArguments()在将片段附加到活动之前调用.但是,您可以通过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
   }
}
Run Code Online (Sandbox Code Playgroud)


tol*_*gap 3

我是如何解决这个问题的

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

这件事正在发生

  • FragmentActivity被建造
  • Service开始并绑定到
  • 同时Fragments异步创建 get
  • 一旦启动Service,它会发出一个Broadcast带有最新信息的
  • 因为 和Service创建Fragment都是异步的,所以广播将从服务发送,但因为 甚至BroadcastReceiversFragments没有初始化,所以它们不会接收到Intent

我做了什么来修复它

我不得不使用回调来确保

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

所以我使用了,ServiceConnection准确地说,是onServiceConnected()方法。在那里,我获得了保存最后一首歌曲的首选项,然后发送Broadcast并接收了Fragments它并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);
    }
};
Run Code Online (Sandbox Code Playgroud)