我正在尝试构建一个简单的MusicPlayer,但在方向更改方面遇到了问题。我正在使用一个处理MediaPlayer的服务,以便它在后台播放(即使"活动"不在前台),就像谷歌播放音乐一样。该服务绑定到我唯一的MainActivity。问题是,例如,当方向发生变化时,它会破坏活动和服务(我想这是预期的行为)。
我不知道如何有效地处理生命周期。当方向发生变化时,它会再次将服务绑定到活动。我的MainActivity使用ViewPager和FragmentPagerAdapter来处理选项卡并更新我对事件的视图。
当它再次创建活动(从方向更改)时,它会再次绑定服务,执行"加载",然后尝试更新我的视图,但由于某些原因,寻呼机适配器中的片段为空。我不知道为什么。理想情况下,我认为我应该在应用程序开始时加载所有曲目一次。我应该在"活动"或服务中这样做吗(因为它与服务有关)?
我不确定我应该如何处理我的服务、活动和寻呼机适配器的生命周期。
我制作了一个示例应用程序来重现我的错误:
公共类MyActivity扩展Activity{
private MediaPlayerService mediaPlayerService; private BroadcastReceiver broadcastReceiver; private MyPagerAdapter adapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_my); ViewPager viewPager = (ViewPager) findViewById(R.id.pager); adapter = new MyPagerAdapter(getFragmentManager()); viewPager.setAdapter(adapter); broadcastReceiver = buildBroadcastReceiver(); Intent intent = new Intent(this, MediaPlayerService.class); bindService(intent, connection, Context.BIND_AUTO_CREATE); } @Override protected void onDestroy() { if ( serviceBound ) { unbindService(connection); serviceBound = false; } super.onDestroy(); } @Override protected void onResume() { registerReceiver(broadcastReceiver, new IntentFilter(MediaPlayerService.BROADCAST)); super.onResume(); } @Override protected void onPause() { unregisterReceiver(broadcastReceiver); super.onPause(); } private boolean serviceBound = false; private ServiceConnection connection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName componentName, IBinder iBinder) { mediaPlayerService = ((MediaPlayerServiceBinder) iBinder).getService(); serviceBound = true; mediaPlayerService.load(); } @Override public void onServiceDisconnected(ComponentName componentName) { serviceBound = false; } }; private BroadcastReceiver buildBroadcastReceiver() { return new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { int action = intent.getIntExtra(MediaPlayerService.ACTION, 0); if ( action == MediaPlayerService.ACTION_UPDATE_PLAYLIST ) { List<String> cities = Arrays.asList("New York", "Toronto", "Tokyo"); //Data would be load from Database here ListFragment fragment = adapter.getFragment(); fragment.updatePlayList(cities); // Fragment is NULL on Orientation changes!? } } }; } }
公共类ListFragment扩展Fragment{
private ArrayAdapter<String> adapter; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View inflatedView = inflater.inflate(R.layout.playlist, container, false); adapter = new ArrayAdapter<String>(getActivity(), android.R.layout.simple_list_item_1, new ArrayList<String>()); ListView listView = (ListView) inflatedView.findViewById(R.id.list_view); listView.setAdapter(adapter); return inflatedView; } public void updatePlayList(List<String> items) { adapter.clear(); adapter.addAll(items); adapter.notifyDataSetChanged(); } }
public class MediaPlayerService extends Service { public static final String BROADCAST = "example.com.mediaplayersample.Broadcast"; public static final int ACTION_UPDATE_PLAYLIST = 3; public static final String ACTION = "ACTION"; private MediaPlayer mediaPlayer; public void load() { //Load... Intent intent = new Intent(MediaPlayerService.BROADCAST); intent.putExtra(MediaPlayerService.ACTION, ACTION_UPDATE_PLAYLIST); sendBroadcast(intent); } @Override public IBinder onBind(Intent intent) { return new MediaPlayerServiceBinder(); } public class MediaPlayerServiceBinder extends Binder { public MediaPlayerService getService() { return MediaPlayerService.this; } }
}
公共类MyPagerAdapter扩展FragmentPagerAdaper{
private ListFragment listFragment; public MyPagerAdapter(FragmentManager fragmentManager) { super(fragmentManager); }; @Override public Fragment getItem(int i) { if (i == 0) { if (listFragment == null) { listFragment = new ListFragment(); return listFragment; } } throw new IllegalStateException("Wrong index " + i); } @Override public int getCount() { return 1; } public ListFragment getFragment() { return listFragment; } }
编辑:我理解在清单文件中添加设置的建议方法:
<activity> android:name=.... android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize" </activity>
然而,它似乎没有被重新推荐。我计划使用几种语言和不同的布局,但我不认为刷新所有视图是最好的方法。
您可以尝试将configChanges添加到要在活动中定义的清单中<>它可能会解决你的问题:
<activity>
android:name=.....
android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize" />
</activity>
如果它不起作用,您可以尝试将onConfigurationChanged()方法实现到您的活动中。