react-native-video: The app hangs for more than 10 seconds to start play on Android.
Problems
When click thumbnail to open the player page to play video, the app hangs for more than 10 seconds to show the player page.
Env
react-native: 0.39.2 react-native-video: Commits on Dec 13, 2016, The newest version even can not be compiled.
Code
The player page:
/**
* 在球场
* zaiqiuchang.com
*/
import React, {Component} from 'react';
import {StyleSheet, View, Text, CameraRoll, TouchableWithoutFeedback, Alert, Platform} from 'react-native';
import flattenStyle from 'flattenStyle';
import Video from 'react-native-video';
import Orientation from 'react-native-orientation';
import {bindActionCreators} from 'redux';
import {connect} from 'react-redux';
import {COLOR, DEFAULT_NAV_BAR_STYLE, SCREEN_WIDTH, SCREEN_HEIGHT} from '../config';
import {navToPostDetail} from '../navigation';
import {VIDEO_RATES} from '../const';
import * as components from './';
import * as helpers from '../helpers';
import * as actions from '../actions';
class Player extends Component {
static navigatorStyle = Object.assign({}, DEFAULT_NAV_BAR_STYLE, {
navBarBackgroundColor: COLOR.backgroundDarkLighter,
drawUnderNavBar: true,
navBarTranslucent: true,
navBarHideOnScroll: true,
tabBarHidden: true,
});
constructor(props) {
super(props);
this.screenId = props.screenId || 'Player';
let {navigator, cbRemove} = props;
let rightButtons = [];
if (cbRemove) {
rightButtons.push({
title: '删除',
id: 'delete',
});
} else {
rightButtons.push({
title: '保存',
id: 'save',
});
}
navigator.setButtons({rightButtons});
navigator.setOnNavigatorEvent(event => this.onNavigatorEvent(event));
}
componentDidMount() {
let {navigator, network} = this.props;
if (!network.isConnected || !network.reach) {
Alert.alert(
'播放失败',
'网络未连接,或者类型未知。',
[
{text: '确认', onPress: () => navigator.pop()},
],
);
return;
}
this.orientationListener = orientation => {
let {setPlayerState} = this.props;
if (orientation == 'LANDSCAPE-LEFT' || orientation == 'LANDSCAPE-RIGHT') {
setPlayerState({orientation});
} else {
setPlayerState({orientation: 'PORTRAIT'});
}
}
Orientation.addSpecificOrientationListener(this.orientationListener);
Orientation.unlockAllOrientations();
let {autoPlay, account, setPlayerState} = this.props;
if (autoPlay === undefined) {
autoPlay = account.settings.video.autoPlay[network.reach];
}
setPlayerState({paused: !autoPlay});
this.autoHideNavBar();
}
componentWillUnmount() {
clearTimeout(this.navBarHiddenTimeout);
let {resetPlayerState} = this.props;
resetPlayerState();
Orientation.removeOrientationListener(this.orientationListener);
Orientation.lockToPortrait();
}
onNavigatorEvent(event) {
let {navigator, videoUri, errorFlash, cbRemove} = this.props;
if (event.type == 'NavBarButtonPress') {
if (event.id == 'delete') {
navigator.pop();
cbRemove(videoUri);
} else if (event.id == 'save') {
CameraRoll.saveToCameraRoll(videoUri)
.then(result => errorFlash('保存成功'))
.catch(error => errorFlash('保存失败'));
}
}
}
autoHideNavBar(seconds=3000) {
clearTimeout(this.navBarHiddenTimeout);
this.navBarHiddenTimeout = setTimeout(() => {
let {player, setPlayerState} = this.props;
let {paused, rateSelectorVisible} = player;
if (!paused && !rateSelectorVisible) {
setPlayerState({navBarHidden: true});
}
}, seconds);
}
render() {
let {navigator, network, object, videoUri, videoId, postId, prevScreen,
account, player, fileFavor, errorFlash, setPlayerState, favorFile,
unfavorFile} = this.props;
if (!network.isConnected || !network.reach) {
return null;
}
let {navBarHidden, orientation, loaded, paused, ended, rate, rateSelectorVisible,
naturalSize, currentTime, duration} = player;
let videoFile = helpers.fileFromCache(object, videoId);
let post;
if (postId) {
post = helpers.postFromCache(object, postId);
}
let maxRate = 'fhd';
if (videoFile.pixelSize[0] < 1280) {
maxRate = 'ld';
} else if (videoFile.pixelSize[0] < 1920) {
maxRate = 'hd';
}
rate = rate || account.settings.video.playRate[network.reach];
if (maxRate == 'ld' && (rate == 'hd' || rate == 'fhd')) {
rate = 'ld';
} else if (maxRate == 'hd' && rate == 'fhd') {
rate = 'hd';
}
let favoredFiles = fileFavor.favoredFiles || [];
favored = favoredFiles.includes(videoId);
navigator.toggleNavBar({'to': (navBarHidden ? 'hidden' : 'shown')});
let videoWidth = orientation == 'PORTRAIT' ? SCREEN_WIDTH : SCREEN_HEIGHT;
let videoHeight = Math.round(videoWidth * videoFile.pixelSize[1] / videoFile.pixelSize[0]);
let {width: opBarWidth, height: opBarHeight} = flattenStyle(styles.opBar);
let opBarLeft = Math.round(((orientation == 'PORTRAIT' ? SCREEN_WIDTH : SCREEN_HEIGHT) - opBarWidth) / 2);
let opBarTop = Math.round(((orientation == 'PORTRAIT' ? SCREEN_HEIGHT : SCREEN_WIDTH) - opBarHeight) / 2);
return (
<components.Layout screenId={this.screenId}>
<TouchableWithoutFeedback
onPress={() => {
setPlayerState({navBarHidden: !navBarHidden});
this.autoHideNavBar();
}}
>
<View style={{flex: 1, justifyContent: 'center', backgroundColor: 'black'}}>
<Video
source={helpers.videoSource(videoUri, rate)}
repeat={false}
paused={paused}
onLoadStart={event => {
let {src} = event;
setPlayerState({src});
}}
onLoad={event => {
let {duration, naturalSize} = event;
setPlayerState({duration, naturalSize, loaded: true});
this.player.seek(0);
}}
onProgress={event => {
let {currentTime, playableDuration} = event;
setPlayerState({currentTime, playableDuration});
}}
onEnd={event => {
Orientation.lockToPortrait();
setPlayerState({
navBarHidden: false,
paused: true,
ended: true,
});
}}
onError={error => errorFlash(error)}
ref={ref => this.player = ref}
style={[styles.video, {width: videoWidth, height: videoHeight}]}
/>
{!navBarHidden ?
<View style={[styles.opBar, {top: opBarTop, left: opBarLeft}]}>
{!ended ?
<components.Icon
name={paused ? 'play-circle-outline' : 'pause-circle-outline'}
onPress={() => {
setPlayerState({paused: !paused});
this.autoHideNavBar();
}}
style={styles.opText}
/> :
null}
{ended ?
<View style={styles.opContainer}>
<components.Icon
name='replay'
onPress={() => {
this.player.seek(0);
setPlayerState({ended: false, paused: false});
this.autoHideNavBar();
}}
style={styles.opText}
/>
{videoId ?
<components.Icon
name={favored ? 'favorite' : 'favorite-border'}
onPress={() => {
navigator.pop();
if (favored) {
unfavorFile({fileId: videoId, cbOk: () => errorFlash('取消收藏成功。')});
} else {
favorFile({fileId: videoId, cbOk: () => errorFlash('收藏成功。')});
}
}}
style={[styles.opText, (favored ? {color: COLOR.favored} : null)]}
/> :
null}
{post ?
<components.Icon
name='more-horiz'
onPress={() => {
navigator.pop();
if (prevScreen != 'PostDetail') {
navToPostDetail(navigator, post);
}
}}
style={styles.opText}
/> :
null}
</View> :
null}
</View> :
null}
{!navBarHidden ?
<View style={styles.ctlBar}>
<View style={{flexDirection: 'row', alignItems: 'center'}}>
<components.Text style={styles.ctlBarText}>{helpers.durationText(currentTime)} / {helpers.durationText(duration)}</components.Text>
</View>
<View style={{flexDirection: 'row', alignItems: 'center'}}>
<components.Text style={styles.ctlBarText}
onPress={() => {
setPlayerState({rateSelectorVisible: !rateSelectorVisible});
this.autoHideNavBar();
}}
>
{helpers.videoRateText(rate)}
</components.Text>
{Platform.OS == 'ios' ?
<components.Icon
name={orientation == 'PORTRAIT' ? 'fullscreen' : 'fullscreen-exit'}
onPress={() => {
setPlayerState({paused: true});
if (orientation == 'PORTRAIT') {
setPlayerState({orientation: 'LANDSCAPE-LEFT'});
Orientation.lockToLandscapeLeft();
} else {
setPlayerState({orientation: 'PORTRAIT'});
Orientation.lockToPortrait();
}
setPlayerState({paused: false});
}}
style={[styles.ctlBarText, {padding: 5, fontSize: 22}]}
/> :
null}
</View>
</View> :
null}
{!navBarHidden && rateSelectorVisible ?
<View style={styles.rateSelector}>
{VIDEO_RATES.filter(v => {
if (v.value == rate) {
return false;
}
if (maxRate == 'ld' && (v.value == 'hd' || v.value == 'fhd')) {
return false;
} else if (maxRate == 'hd' && v.value == 'fhd') {
return false;
}
return true;
})
.map(({label, value}) =>
<components.Text
key={value}
onPress={() => {
setPlayerState({
rate: value,
rateSelectorVisible: false,
loaded: false,
paused: false,
ended: false,
});
this.autoHideNavBar();
}}
style={styles.ctlBarText}
>
{label}
</components.Text>
)
}
</View> :
null}
</View>
</TouchableWithoutFeedback>
</components.Layout>
);
}
}
const styles = StyleSheet.create({
video: {},
opBar: {
position: 'absolute',
width: 300,
height: 100,
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
},
opContainer: {
flexDirection: 'row',
padding: 5,
borderRadius: 10,
backgroundColor: COLOR.backgroundDarkLighter + '80',
},
opText: {
color: COLOR.textLightNormal,
opacity: 0.8,
backgroundColor: 'transparent',
fontSize: 48,
margin: 5,
},
ctlBar: {
position: 'absolute',
left: 0,
right: 0,
bottom: 0,
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
backgroundColor: COLOR.backgroundDarkLighter + '80',
},
ctlBarText: {
color: COLOR.textLightNormal,
fontSize: 12,
padding: 10,
},
rateSelector: {
position: 'absolute',
bottom: 32,
right: (Platform.OS == 'ios' ? 32 : 0),
alignItems: 'flex-end',
},
});
function mapStateToProps(state) {
let {network, object, account, player, fileFavor} = state;
return {
network,
object,
account,
player,
fileFavor,
};
}
function mapDispatchToProps(dispatch) {
return bindActionCreators(actions, dispatch);
}
export default connect(mapStateToProps, mapDispatchToProps)(Player);
Screenshot
It works great on iOS, and the ui is as following.

About this issue
- Original URL
- State: closed
- Created 7 years ago
- Reactions: 1
- Comments: 18 (3 by maintainers)
Seems like ExoPlayer / prepareAsync fixes this issue.
@haroonob search through similar issues and you will find the answer. Let’s try and keep the discussion on this thread down, as these are NPM basics. Thank you.
same problem, need to rollback 0.9.0
Hi guys, I get the same problem. I’m using RN 0.41.2, RN Video 1.0.0, Whenever the video is loaded, It makes the app hang for 10 seconds. I downgrade RN Video to 0.9.0 then it’s not hang any more but got other problems: full screen is not working and when the app is switched to landscape mode, the video screen is not scaled, the width is expanded but the height is not expanded, so the video is displayed with a half of screen size. What should I do now 😦