java - MediaPlayer 服务、ViewPagerAdapter 方向更改

标签 java android android-service android-orientation android-pageradapter

我正在尝试构建一个简单的音乐播放器,但在方向更改方面遇到问题。我正在使用处理 MediaPlayer 的服务,以便它在后台播放(即使 Activity 不在前台),例如 Google PlayMusic。该服务绑定(bind)到我独特且单一的 MainActivity。问题是,例如,当方向发生变化时,它会破坏 Activity 和服务(我猜这是预期的行为)。

我不确定如何有效地处理生命周期。当方向发生变化时,它会再次将服务绑定(bind)到 Activity 。我的 MainActivity 使用 ViewPager 和 FragmentPagerAdapter 来处理选项卡并更新我对事件的 View 。

当它再次创建 Activity (从方向更改)时,它再次绑定(bind)服务,执行“加载”,然后尝试更新我的 View ,但由于某些原因,寻呼机适配器中的 fragment 为空。我不知道为什么。理想情况下,我认为我应该在应用程序开始时加载所有轨道一次。我应该在 Activity 还是服务中执行此操作(因为它与服务相关)?

我不确定应该如何处理我的服务、 Activity 和寻呼机适配器的生命周期。

我制作了一个示例应用程序来重现我的错误:

public class MyActivity extends 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!?
            }
        }
    };
} }

.

public class ListFragment extends 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;
    }
}

}

.

public class MyPagerAdapter extends FragmentPagerAdapter {

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;
} }

编辑: 我了解按照建议在 list 文件中添加设置的方法:

<activity> 
  android:name=....
  android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize" 
</activity>

但是,似乎不推荐。我计划有几种语言和不同的布局,我不认为刷新我所有的观点是最好的方法。

最佳答案

您可以尝试将 configChanges 添加到要在 Activity 中定义的 list 中<>它可能会解决您的问题:

<activity>
android:name=.....
android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize" />
</activity>

如果它不起作用,您可以尝试在您的 Activity 中实现 onConfigurationChanged() 方法。

关于java - MediaPlayer 服务、ViewPagerAdapter 方向更改,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25648443/

相关文章:

java - Java API 核心类的 maven-javadoc-plugin 和 inheritDoc

java - java中线程的使用方法

java - 如何在不点击屏幕的情况下放置物体 - Android AR

java - 我的 checkGPS 方法从未运行过,gps 保持 0.0,0.0

android - 带复选框的 ListView Holder

android - PhoneStateListener 超出了 Android 11 上允许的注册监听器数量

java - 对话框 fragment 定位

android - 即使在 onDestroy() 方法中将实例设置为 null,Activity 仍然会泄漏

android - 清除 Activity 堆栈并从 Android 服务启动新 Activity

android - 来自原生 Android 服务的 Unity3d 脚本