Android 等待操作,直到片段';将创建用户的视图
我正在为音乐播放器编程,音乐在后台Android 等待操作,直到片段';将创建用户的视图,android,transactions,android-fragments,android-service,Android,Transactions,Android Fragments,Android Service,我正在为音乐播放器编程,音乐在后台服务中播放。当用户终止承载3个片段的活动,然后再次重新启动活动时,我会从服务发送一个广播,其中包含有关当前播放歌曲的信息,以及用户添加到会话中的歌曲列表 问题是,每次我想将最后的信息设置到片段中时,都不会发生任何事情,因为它们的创建时间太长,而且广播没有得到应有的处理 我如何让服务或广播等待片段被创建,以便正确处理它们 以下是相关的代码片段: //When the activity binds to the service, refresh the fragme
服务中播放。当用户终止承载3个片段的活动
,然后再次重新启动活动
时,我会从服务
发送一个广播
,其中包含有关当前播放歌曲的信息,以及用户添加到会话中的歌曲列表
问题是,每次我想将最后的信息设置到片段中时,都不会发生任何事情,因为它们的创建时间太长,而且广播
没有得到应有的处理
我如何让服务
或广播
等待片段被创建,以便正确处理它们
以下是相关的代码片段:
//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);
}
}
你不能在碎片里做点什么吗
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();
}
最简单的方法就是保留信息,直到片段准备好显示它。使用片段的setArguments()
方法将信息附加到片段中
@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);
}
}
然后,在片段的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方法,其中片段本身将值放入setArguments()
的Bundle中。这样,当片段的视图被破坏并且必须重新创建时,只要在为可能的事件设置参数的基础上创建了视图,就可以更新视图
注意:您只能在片段附加到活动之前调用setArguments()
。但是,您可以通过从getArguments()
检索对包的引用,然后简单地输入值,来更新通过setArguments
传入的包。因此,不要从接收方调用setArguments()
,而是执行以下操作:
public void setCurrentSong(Song extra) {
Bundle args = getArguments();
args.putParcable(KEY_MAP, extra);
if(/* Views are created */) {
// update and invalidate the views
}
}
我是怎么修好的
当我使用一项媒体播放服务时,我想从该服务中调出上次听过的歌曲,以便直接播放。这是一个古老的逻辑,但我实际上是围绕它构建代码的。直到苏斯法我撞上它
这种情况正在发生
FragmentActivity
已创建
服务
启动并绑定到
- 同时,异步创建
片段
服务一旦启动
,它就会发送一个包含最新信息的广播
- 由于
服务
和片段
创建都是异步的,广播将从服务发送,但由于片段
中的广播接收器
甚至还没有初始化,它们将不会接收意图
我做了什么来修复它
我不得不使用回调来确保
- 服务已创建并绑定到
- 创建的片段和视图已设置
因此,我使用了ServiceConnection
,准确地说,是onServiceConnected()
方法。在那里,我得到了保存最后一首歌曲的首选项,然后发送广播
,片段
接收到它,并适当地设置了视图
。这也有助于改变方向
代码
我的解决方案只是创建自己的回调接口。在ur片段的onCreateView方法的最后,只需调用回调方法,它告诉ur mainactivity创建完成
它对我有用,希望对你也有帮助。这不起作用。当我在onResume()
中时,current
变量为null,这会导致NPE
,如果我检查null,则不会设置它。这是因为我从服务
发送广播
,该服务尚未完成所述广播
的发送。因此,onReceive在onResume之后收到。根据片段生命周期,所有视图都应该在调用onResume时创建(更确切地说,在调用onReceive时创建)。您能否详细说明从onReceive内部调用setCurrentSong时出现的问题?视图应该存在。我已将所有与片段相关的创建代码移动到FragmentActivity
的onServiceConnection()
,并且只固定了所有操作的顺序。因此,您认为片段的BroadcastReceiver
首先接收广播,然后移动到onResume()
的假设在技术上是错误的。我的假设是基于您在代码中的评论,即“它接收广播太快,我无法设置视图,因此它们总是空的。”这表明在创建视图之前调用了onReceive。第一个测试(这里的前两个注释)确实表明onReceive是在onResume之后调用的。是的,但是由于我做错了什么,我的注释也错了;)所以我很抱歉,但我不能接受这个答案,因为其他人可能会尝试实现这个代码,但它可能无法完全工作。嗯,谢谢你解释得很好的答案。我也会尝试你的方法,并再次考虑最佳答案。什么是getUsingFragment()
?对于v4支持Fragment
或股票Fragment
类,该方法不存在。抱歉。我忘了澄清。它不存在。这就是你用来获取片段的任何方法。您可以使用findFramgentByTag()
或任何检索要更新的片段的方法来替换它。我试图使它更通用,因为有多种方法可以检索片段。实际上,我通过将所有片段创建代码移动到FragmentActivity
中的ServiceConnection
内部类,解决了我的问题。信息技术
//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);
}
};