MediaSession分页解决appClient和appServer间Meida传输数据过大问题

108 阅读2分钟

在不修改服务appA(appServer)的前提下,可以通过在appB(appClient)中调整Bundle的分页参数解决binder传输数据过大的问题。以下是具体方案:

解决方案核心思路

通过MediaBrowser的subscribe方法传递分页参数,控制每次请求的数据量(如每次100条),避免单次传输超过1000条数据导致binder失败。需在appB中实现分页逻辑,循环请求所有数据。

步骤详解

  1. 定义分页参数
    Bundle中添加分页控制键值,使用Android MediaSession的标准参数或自定义参数:

    Bundle requestBundle = new Bundle();
    requestBundle.putInt(MediaConstants.EXTRA_PAGE, pageIndex);  // 当前页码
    requestBundle.putInt(MediaConstants.EXTRA_PAGE_SIZE, pageSize); // 每页数据量
    
  2. 设置合理的分页大小
    根据binder传输上限(通常1MB),将pageSize设为安全值(例如100):

    private static final int SAFE_PAGE_SIZE = 100; // 单页最大数据量
    
  3. 分页请求数据
    循环发送分页请求,直到获取全部数据:

    int currentPage = 0;
    boolean hasMoreData = true;
    List<MediaItem> allItems = new ArrayList<>();
    
    while (hasMoreData) {
        Bundle bundle = new Bundle();
        bundle.putInt(MediaConstants.EXTRA_PAGE, currentPage);
        bundle.putInt(MediaConstants.EXTRA_PAGE_SIZE, SAFE_PAGE_SIZE);
        
        mediaBrowser.subscribe(parentId, bundle, new SubscriptionCallback() {
            @Override
            public void onChildrenLoaded(String parentId, List<MediaItem> children) {
                allItems.addAll(children);
                if (children.size() < SAFE_PAGE_SIZE) {
                    hasMoreData = false; // 已获取全部数据
                }
            }
        });
        currentPage++;
    }
    
  4. 处理边界情况

    • 超时处理:设置超时回调,避免网络异常导致无限等待。
    • 错误重试:在onError中实现重试机制(如指数退避)。
    • 同步控制:使用CountDownLatch或回调链确保分页请求顺序执行。

关键代码优化

// 分页请求封装方法
public void loadPaginatedData(String mediaId) {
    AtomicInteger page = new AtomicInteger(0);
    List<MediaItem> resultList = new ArrayList<>();
    
    SubscriptionCallback callback = new SubscriptionCallback() {
        @Override
        public void onChildrenLoaded(String parentId, List<MediaItem> children) {
            resultList.addAll(children);
            if (children.size() == SAFE_PAGE_SIZE) {
                // 继续请求下一页
                requestNextPage(page.incrementAndGet());
            } else {
                // 全部数据加载完成
                processFullData(resultList);
            }
        }
        
        @Override
        public void onError(String parentId) {
            // 实现重试逻辑(最多3次)
            if (retryCount < 3) {
                requestNextPage(page.get());
            }
        }
    };
    
    requestNextPage(0); // 启动第一页请求
}

private void requestNextPage(int pageIndex) {
    Bundle bundle = new Bundle();
    bundle.putInt(MediaConstants.EXTRA_PAGE, pageIndex);
    bundle.putInt(MediaConstants.EXTRA_PAGE_SIZE, SAFE_PAGE_SIZE);
    mediaBrowser.subscribe(mediaId, bundle, callback);
}

注意事项

  1. 服务端兼容性
    虽然appA未显式支持分页,但MediaSession框架会自动处理Bundle参数。需确保服务端能解析EXTRA_PAGEEXTRA_PAGE_SIZE(标准Android常量,位于android.media.MediaConstants)。

  2. 性能平衡

    • 增大SAFE_PAGE_SIZE可减少请求次数,但需测试binder极限(建议200-500条)。
    • 分页请求间隔建议≥300ms,避免服务端压力。
  3. 数据一致性
    在分页过程中若数据发生变化,建议:

    • 首次请求时获取数据版本号(如timestamp)
    • 后续分页携带该版本号确保数据一致性
  4. 备用方案
    若分页参数无效(服务端完全忽略),可改用MediaController.TransportControls.sendCustomAction()实现自定义分页协议,但需服务端配合(需基础包预留接口)。

重要提示:实际测试中需验证分页参数在服务端的有效性。若服务端完全不处理分页,需推动基础包升级或采用备用传输机制(如直接HTTP接口)。