Android视频播放自动转屏最佳实践

Posted by lx8421bcd on November 12, 2017

前段时间产品说要给直播间加个自动转屏,比较迷惑,因为自动转屏的话,躺着用聊天模式很容易误操作,基本没有直播平台采用自动转屏来切全屏,基本都是双击播放器切全屏。不过产品倒是很坚持,一直说先做上去看看效果,那就做呗。(埋点啥的也没有咋看效果,看客服投诉么2333)

提到转屏回调首先就想到了onConfigurationChanged()方法,所以就按这个方法出触发的事件监听写了个自动转屏方案

@Override
public void onConfigurationChanged(Configuration newConfig) {
  super.onConfigurationChanged(newConfig);
  Display getOrient = getWindowManager().getDefaultDisplay();
  int orientation;
  if(getOrient.getWidth() < getOrient.getHeight()){
    orientation = Configuration.ORIENTATION_PORTRAIT;
  }else {
    orientation = Configuration.ORIENTATION_LANDSCAPE;
  }
  switchOrientation(orientation); // 此方法内部主要是按横竖屏方向调整具体布局,不赘述
}

不过实践下来发现并不可取,有几点问题

  1. 不够灵敏,有的时候手机已经完全横过来了但却没有转屏,还要转两下子……
  2. 大幅度旋转,很有可能不会触发,比如一下子横屏旋转180度(躺在床上翻个身这种)

要做更灵敏准确的自动转屏肯定不能靠这个了,研究了一下,可以通过设置OrientationEventLister监听手机旋转角度。经过调试之后的自动转屏控制方法如下:

orientationEventListener = new OrientationEventListener(this) {
  @Override
  public void onOrientationChanged(int rotation) {
    if (!isSystemRotationEnabled()) {
      orientationEventListener.disable();
      return;
    }
    // UI按键锁定,不允许横竖屏切换
    if (isLock) {
      return;
    }
    // clickSwitchProtect用于在用户横着手机时点按钮切回竖屏时保持竖屏状态,
    // 或者竖着手机切横屏时保持状态,避免通过按钮切过去又马上被转回来
    // 在手机角度改变到与当前布局方向一致时取消保护
    if (rotation >= 345 && rotation <= 360 || rotation >= 0 && rotation <= 15) {
      if (clickSwitchProtect && !isFullScreen) { 
        clickSwitchProtect = false;
      }
      if (!isFullScreen || clickSwitchProtect) {
        return;
      }
      switchOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
    }
    else if (rotation >= 75 && rotation <= 105) {
      if (clickSwitchProtect && isFullScreen) {
        clickSwitchProtect = false;
      }
      if (clickSwitchProtect) {
        return;
      }
      int winRotation = getWindowManager().getDefaultDisplay().getOrientation();
      if (winRotation == Surface.ROTATION_270 && isFullScreen) {
        return;
      }
      switchOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE);
    }
    else if (rotation >=255 && rotation <= 285) {
      if (clickSwitchProtect && isFullScreen) {
        clickSwitchProtect = false;
      }
      if (clickSwitchProtect) {
        return;
      }
      int winRotation = getWindowManager().getDefaultDisplay().getOrientation();
      if (winRotation == Surface.ROTATION_90 && isFullScreen) {
        return;
      }
      switchOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
    }
  }
};

注意,由于OrientationEventLister是无视系统的屏幕旋转锁定的,为了跟系统设置保持一致,需要对系统的屏幕旋转锁定进行监听

orientationObserver = new ContentObserver(new Handler()) {
  @Override
  public void onChange(boolean selfChange) {
    if (isSystemRotationEnabled()) {
      orientationEventListener.enable();
    } else {
      orientationEventListener.disable();
    }
  }
};

另外还要注意的一点是,为避免对传感器长时间占用,需要及时注册/解除注册监听,建议在 onResume()onPause() 中进行。

@Override
protected void onResume() {
  super.onResume();
  if (isSystemRotationEnabled()) {
    orientationEventListener.enable();
  }
  getContentResolver().registerContentObserver(
    Settings.System.getUriFor(Settings.System.ACCELEROMETER_ROTATION),
    true, orientationObserver);
}

@Override
protected void onPause() {
  super.onPause();
  orientationEventListener.disable();
  getContentResolver().unregisterContentObserver(orientationObserver);
}

之所以不在onCreate()和onDestroy()中执行注册/解除注册,主要是因为如果用户在直播间锁屏或者退回Launcher,页面还是处于栈顶,并没有被销毁,就会造成长时间占用传感器。

这是提交审核后华为渠道那边反馈的问题,不得不说华为渠道的审核还是挺严格的,某种角度来说,对华为用户是好事。