You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Xamarin.Android:Android4.4下视频启动卡顿及媒体交替播放问题

解决Xamarin.Android中视频切换时的卡顿问题

你遇到的视频启动短暂卡顿,大概率是因为视频切换时没有提前预加载,加上在OnCompletion回调里堆叠了太多UI操作和文件IO,再配合Android 4.4本身的性能限制,就容易出现卡顿。下面给你几个针对性的优化方案:

一、提前预加载下一个视频

在当前视频播放过程中就把下一个视频资源加载好,而非等到播放结束才临时加载,这是解决卡顿的核心优化点:

// 在MainActivity中添加预加载相关的成员
private MediaPlayer _preloadedMediaPlayer;

// 提前预加载下一个视频的方法
public void PreloadNextVideo()
{
    int videoListLength = vidList.Count;
    if (videoListLength == 0) return;
    
    int nextVideoIndex = (videoIndex + 1) % videoListLength;
    var nextVideoFile = new Java.IO.File(vidList[nextVideoIndex]);
    
    // 先释放之前的预加载资源
    if (_preloadedMediaPlayer != null)
    {
        _preloadedMediaPlayer.Release();
        _preloadedMediaPlayer = null;
    }
    
    _preloadedMediaPlayer = new MediaPlayer();
    try
    {
        _preloadedMediaPlayer.SetDataSource(this, Android.Net.Uri.FromFile(nextVideoFile));
        // 异步准备,避免阻塞UI线程
        _preloadedMediaPlayer.PrepareAsync();
        _preloadedMediaPlayer.SetOnPreparedListener(mp => {
            // 预加载完成,可以在这里标记状态,比如打印日志
        });
    }
    catch (Exception ex)
    {
        // 处理加载异常,比如记录日志
    }
}

然后修改OnCompletion回调,直接使用预加载好的资源:

public void OnCompletion(MediaPlayer mp)
{
    // 先释放当前视频的资源
    mp.Release();
    
    // 切换到图片显示的逻辑
    MainActivity.RunOnUiThread(() => {
        int imageListLength = MainActivity.imgList.Count;
        if (imageListLength > 0)
        {
            MainActivity.imageIndex = (MainActivity.imageIndex + 1) % imageListLength;
            MainActivity.fullScreenVideo.Visibility = ViewStates.Gone;
            MainActivity.dividedLayout.Visibility = ViewStates.Visible;
            
            // 后续可以优化图片加载,这里先保留原有逻辑
            MainActivity.imgSwitcher1.SetImageURI(Android.Net.Uri.FromFile(new Java.IO.File(MainActivity.imgList[MainActivity.imageIndex])));
            MainActivity.imageIndex = (MainActivity.imageIndex + 1) % imageListLength;
            MainActivity.imgSwitcher2.SetImageURI(Android.Net.Uri.FromFile(new Java.IO.File(MainActivity.imgList[MainActivity.imageIndex])));
        }
        
        // 图片显示期间,预加载下一个视频
        MainActivity.PreloadNextVideo();
        
        // 5秒后切换回视频
        MainActivity._handler.PostDelayed(() => {
            MainActivity.dividedLayout.Visibility = ViewStates.Gone;
            MainActivity.fullScreenVideo.Visibility = ViewStates.Visible;
            
            // 使用预加载好的MediaPlayer,避免临时加载卡顿
            if (MainActivity._preloadedMediaPlayer != null)
            {
                MainActivity.fullScreenVideo.SetMediaPlayer(MainActivity._preloadedMediaPlayer);
                MainActivity._preloadedMediaPlayer.Start();
                // 重置预加载引用,准备下一次预加载
                MainActivity._preloadedMediaPlayer = null;
            }
            else
            {
                // 预加载失败的降级逻辑,保留原有加载方式
                int videoListLength = MainActivity.vidList.Count;
                if (videoListLength > 0)
                {
                    MainActivity.videoIndex = (MainActivity.videoIndex + 1) % videoListLength;
                    MainActivity.fullScreenVideo.SetVideoURI(Android.Net.Uri.FromFile(new Java.IO.File(MainActivity.vidList[MainActivity.videoIndex])));
                    MainActivity.fullScreenVideo.Start();
                }
            }
        }, 5000);
    });
}

二、优化图片加载逻辑

每次从本地文件加载图片会消耗IO资源,Android 4.4的文件IO性能有限,可以提前把图片缓存成Bitmap,避免重复加载:

// 在MainActivity中添加图片缓存成员
private List<Bitmap> _cachedImages = new List<Bitmap>();

// 初始化图片缓存的方法,在应用启动时调用
public void CacheImages()
{
    foreach (var imgPath in imgList)
    {
        // 直接解码文件为Bitmap
        var bitmap = BitmapFactory.DecodeFile(imgPath);
        // 按布局尺寸压缩图片,减少内存占用
        var compressedBitmap = Bitmap.CreateScaledBitmap(bitmap, 
            dividedLayout.Width, dividedLayout.Height, true);
        // 释放原Bitmap的内存
        bitmap.Recycle();
        _cachedImages.Add(compressedBitmap);
    }
}

// 切换图片时直接使用缓存的Bitmap
MainActivity.imgSwitcher1.SetImageBitmap(MainActivity._cachedImages[MainActivity.imageIndex]);
MainActivity.imgSwitcher2.SetImageBitmap(MainActivity._cachedImages[MainActivity.imageIndex]);

三、简化UI线程操作

你原来的代码嵌套了多层Runnable和Post,会导致UI线程任务堆积,建议直接用RunOnUiThread替代多层嵌套,逻辑更清晰:

// 替代原来的多层Runnable嵌套
MainActivity.RunOnUiThread(() => {
    // 所有UI相关操作都在这里执行
});

四、注意资源释放

Android 4.4的内存管理较为严格,务必及时释放不再使用的资源,避免内存泄漏导致性能下降:

  • 视频播放完成后,调用mp.Release()释放当前媒体资源
  • 应用退出或图片缓存不再使用时,遍历_cachedImages调用bitmap.Recycle()并清空列表

内容的提问来源于stack exchange,提问作者entidzow

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 03:53:25