[video_player_android] Avoid sending unset duration on initialization#11709
[video_player_android] Avoid sending unset duration on initialization#11709dao-wkm wants to merge 2 commits into
Conversation
|
It looks like this pull request may not have tests. Please make sure to add tests or get an explicit test exemption before merging. If you are not sure if you need tests, consider this rule of thumb: the purpose of a test is to make sure someone doesn't accidentally revert the fix. Ask yourself, is there anything in your PR that you feel it is important we not accidentally revert back to how it was before your fix? Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing. If you believe this PR qualifies for a test exemption, contact "@test-exemption-reviewer" in the #hackers channel in Discord (don't just cc them here, they won't see it!). The test exemption team is a small volunteer group, so all reviewers should feel empowered to ask for tests, without delegating that responsibility entirely to the test exemption group. |
|
Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA). View this failed invocation of the CLA check for more information. For the most up to date status, view the checks section at the bottom of the pull request. |
There was a problem hiding this comment.
Code Review
This pull request modifies ExoPlayerEventListener to delay the initialization event until a valid media duration is available, implementing a 500ms fallback mechanism using a Handler. Feedback suggests adding a release method to cancel pending callbacks and prevent potential crashes upon disposal. Additionally, the reviewer recommended ensuring the fallback timer is not repeatedly reset and requested the inclusion of unit tests to verify the new logic and timeout behavior.
| @@ -51,6 +65,32 @@ public ExoPlayerEventListener( | |||
|
|
|||
| protected abstract void sendInitialized(); | |||
There was a problem hiding this comment.
The use of Handler.postDelayed introduces a risk of crashing if the player is disposed before the timeout expires. If initializationFallback runs after exoPlayer.release(), calling sendInitialized() (which typically accesses the player) will likely result in an IllegalStateException.
Please add a cleanup method to cancel the pending callback, and ensure the VideoPlayer implementation stores the listener and calls this method during disposal.
protected abstract void sendInitialized();
/**
* Cancels any pending initialization callbacks.
*
* <p>This should be called when the listener is no longer needed to prevent memory leaks or
* crashes from delayed execution.
*/
public void release() {
mainHandler.removeCallbacks(initializationFallback);
}| if (!hasValidDuration() && shouldWaitForValidDuration()) { | ||
| isWaitingForValidDuration = true; | ||
| mainHandler.removeCallbacks(initializationFallback); | ||
| mainHandler.postDelayed(initializationFallback, DURATION_UNSET_INITIALIZATION_TIMEOUT_MS); | ||
| return; | ||
| } |
There was a problem hiding this comment.
The current implementation resets the initialization fallback timer on every call to maybeSendInitialized if the duration is still unset. If there are frequent timeline updates or state changes, this could delay the fallback initialization significantly beyond the intended 500ms.
Consider only posting the delayed runnable if isWaitingForValidDuration is not already true to ensure the fallback fires within the expected timeframe.
| if (!hasValidDuration() && shouldWaitForValidDuration()) { | |
| isWaitingForValidDuration = true; | |
| mainHandler.removeCallbacks(initializationFallback); | |
| mainHandler.postDelayed(initializationFallback, DURATION_UNSET_INITIALIZATION_TIMEOUT_MS); | |
| return; | |
| } | |
| if (!hasValidDuration() && shouldWaitForValidDuration()) { | |
| if (!isWaitingForValidDuration) { | |
| isWaitingForValidDuration = true; | |
| mainHandler.postDelayed(initializationFallback, DURATION_UNSET_INITIALIZATION_TIMEOUT_MS); | |
| } | |
| return; | |
| } | |
| public void onTimelineChanged(@NonNull Timeline timeline, int reason) { | ||
| if (isWaitingForValidDuration && exoPlayer.getPlaybackState() == Player.STATE_READY) { | ||
| maybeSendInitialized(); | ||
| } | ||
| } |
There was a problem hiding this comment.
The PR description mentions that new tests were added, but no changes to ExoPlayerEventListenerTest.java are included in this pull request. The new logic for waiting for a valid duration and the fallback mechanism should be thoroughly tested. The existing tests pass by default because the mock ExoPlayer returns a valid duration (0) instead of C.TIME_UNSET.
Please add unit tests that verify:
- Initialization is delayed when duration is
C.TIME_UNSETfor non-live media. - Initialization occurs immediately when a valid duration is provided.
- The fallback mechanism triggers after the timeout if the duration remains unset.
onTimelineChangedcorrectly triggers initialization when the duration becomes available.
References
- Code should be tested. Changes to plugin packages should have appropriate tests. (link)
Description
Fixes flutter/flutter#176575
Avoid sending an
initializedevent with an unset duration invideo_player_android.On Android, ExoPlayer can briefly report
C.TIME_UNSETfor non-live, non-dynamic media when playback first reachesSTATE_READY. That value can be converted into an invalidDurationon the Dart side, causing some videos to report a duration such as0:00:00.001000.This PR delays sending the
initializedevent until a valid duration is available for regular media. It also listens for timeline updates and retries initialization when the timeline becomes ready. A short fallback timeout is kept so initialization is not blocked indefinitely if a valid duration is never reported.Breaking Changes
None - all changes are additive and backward compatible.
Pre-Review Checklist
[shared_preferences]///).