android - 偶尔出现 "Too much time to handle tune request"错误

标签 android android-tv exoplayer

我已经构建了一个 Android TV Live Channels 应用程序,总的来说它运行良好。但是,有时我会收到用户的崩溃报告,其中会出现如下错误:

02-11 13:32:21.135 29165-29165/? E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.felkertech.sample.channelsurfer, PID: 29165
    java.lang.RuntimeException: Too much time to handle tune request. (2160ms > 2000ms) Consider handling the tune request in a separate thread.
    at android.media.tv.ITvInputSessionWrapper.executeMessage(ITvInputSessionWrapper.java:166)
    at com.android.internal.os.HandlerCaller$MyHandler.handleMessage(HandlerCaller.java:37)
    at android.os.Handler.dispatchMessage(Handler.java:102)
    at android.os.Looper.loop(Looper.java:135)
    at android.app.ActivityThread.main(ActivityThread.java:5254)
    at java.lang.reflect.Method.invoke(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:372)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)

我真的不知道如何解决这个问题,因为该错误没有引用我的任何代码。此外,我无法一致地重现此错误。

这是我的 onTune 方法的一部分。请注意,它确实调用另一个类的方法来实际获取视频:

    @Override
public boolean onTune(Uri channelUri) {
    notifyVideoUnavailable(TvInputManager.VIDEO_UNAVAILABLE_REASON_TUNING);
    setOverlayViewEnabled(true);
    Log.d(TAG, "Tuning to " + channelUri.toString());
    String[] projection = {TvContract.Channels.COLUMN_DISPLAY_NAME, TvContract.Channels.COLUMN_ORIGINAL_NETWORK_ID,
            TvContract.Channels.COLUMN_SERVICE_ID, TvContract.Channels.COLUMN_TRANSPORT_STREAM_ID,
            TvContract.Channels.COLUMN_INPUT_ID, TvContract.Channels.COLUMN_DISPLAY_NUMBER};
    //Now look up this channel in the DB
    try (Cursor cursor = tvInputProvider.getContentResolver().query(channelUri, projection, null, null, null)) {
        if (cursor == null || cursor.getCount() == 0) {
            return false;
        }
        cursor.moveToNext();
        Channel channel = new Channel()
                .setNumber(cursor.getString(cursor.getColumnIndex(TvContract.Channels.COLUMN_DISPLAY_NUMBER)))
                .setName(cursor.getString(cursor.getColumnIndex(TvContract.Channels.COLUMN_DISPLAY_NAME)))
                .setOriginalNetworkId(cursor.getInt(cursor.getColumnIndex(TvContract.Channels.COLUMN_ORIGINAL_NETWORK_ID)))
                .setTransportStreamId(cursor.getInt(cursor.getColumnIndex(TvContract.Channels.COLUMN_TRANSPORT_STREAM_ID)))
                .setServiceId(cursor.getInt(cursor.getColumnIndex(TvContract.Channels.COLUMN_SERVICE_ID)))
                .setVideoHeight(1080)
                .setVideoWidth(1920);
        this.currentChannel = channel;
        TvInputManager mTvInputManager = (TvInputManager) tvInputProvider.getApplicationContext().getSystemService(Context.TV_INPUT_SERVICE);
        if(mTvInputManager.isParentalControlsEnabled()) {
            TvContentRating blockedRating = null;
            for(int i=0;i<tvInputProvider.getProgramRightNow(channel).getContentRatings().length;i++) {
                blockedRating = (mTvInputManager.isRatingBlocked(tvInputProvider.getProgramRightNow(channel).getContentRatings()[i]) && blockedRating == null)?tvInputProvider.getProgramRightNow(channel).getContentRatings()[i]:null;
            }
            if(blockedRating != null) {
                notifyContentBlocked(blockedRating);
            }
        }
        notifyContentAllowed();
        return tvInputProvider.onTune(channel);
    } catch (Exception e) {
        e.printStackTrace();
    }
    return false;
}

tvInputPlayer.onTune:

public boolean onTune(Channel channel) {
    this.currentChannel = channel;
    this.lastTune = new Date();
    Toast.makeText(SampleTvInputProvider.this, "Tuning to "+channel.getName()+" with program "+getProgramRightNow(channel).getTitle()+" at "+getProgramRightNow(channel).getInternalProviderData(), Toast.LENGTH_SHORT).show();
    Log.d(TAG, "Tuning to " + channel.getName());
    Log.d(TAG, "Playing "+getProgramRightNow(channel).getTitle());
    Log.d(TAG, "Play the video "+getProgramRightNow(channel).getInternalProviderData());

    //Only my local channels will have the ability to be time shifted, so I should update that every tuning.
    //Timeshifting only works for API >= 23
    if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        if (isLocal()) {
            getSession().notifyTimeShiftStatusChanged(TvInputManager.TIME_SHIFT_STATUS_AVAILABLE);
        } else {
            //If it's not a local channel, I cannot pause or seek in the program
            getSession().notifyTimeShiftStatusChanged(TvInputManager.TIME_SHIFT_STATUS_UNAVAILABLE);
        }
    }

    play(getProgramRightNow(channel).getInternalProviderData());
    if(currentChannel.getNumber().equals("4")) {
        Handler h = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                setOverlayEnabled(true);
            }
        };
        h.sendEmptyMessageDelayed(0, 16);
    }
    return true;
}

play 方法在 ExoPlayer 中加载 URL。我觉得缓冲可能会导致 ExoPlayer 稍微滞后,从而产生此问题,但我不知道如何解决此问题。

有人知道吗?

谢谢。

最佳答案

我最近遇到了类似的问题,通过对代码块进行计时,我将其隔离到查询:

tvInputProvider.getContentResolver().query(.....

如果您的 channel 是第一个调谐的 channel ,则在直播 channel 应用启动后,此查询有时会超过 2 秒。 我删除了查询(通过保留我自己的表)并且避免了问题。

关于android - 偶尔出现 "Too much time to handle tune request"错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35355101/

相关文章:

android-youtube-api - Android TV 嵌入式 youtube 1080p

android - 如何在主屏幕上设置 Fire TV "icon"?

android - Android TV 上的 RecyclerView item 焦点

java - 无法控制 exoplayer 的音量和亮度

java - Exoplayer 播放器视频 mp4 e 流 m3u8

android - 是否可以将通知推送和接收到具有相同源代码的另一个克隆应用程序

java - 刷新 Activity 中的方法

java - OutOfMemoryError 创建位图

android - 在缓存重新缩放的图像之前重新缩放在 Universal Image Loader 中下载的位图

java - ExoPlayer 测试 - 无法在未调用 Looper.prepare() 的线程内创建处理程序