Android 仿火萤视频桌面 神奇的LiveWallPaper
上周我在微信公众号上推送了一篇题为《Android实现透明屏幕》的文章,并获得了广泛的关注和授权。这篇文章详细介绍了如何利用SurfaceHolder和MediaPlayer等API实现视频桌面效果,并分享了完整的代码实现过程。文章还提供了扩展功能示例,并附上了相关技术教程链接供读者参考学习。通过这篇文章的学习和实践,我对Android的视频播放与显示技术有了更深入的理解,并掌握了如何通过Service机制实现动态壁纸功能。
改写说明
欢迎大家扫描左侧二维码关注我的公众号,每天7点半推送优秀技术博文。
我对该软件有浓厚的兴趣,在一段时间内一直对其保持关注状态。然而,在最近的一段时间里,该平台频繁向我推送了一些与该功能相关的通知信息(即将视频作为桌面进行展示)。这让我对相关技术产生了一定好奇心理,在查看源代码时意外发现了SurfaceHolder组件的存在(即通过这一组件可实现视频展示的效果)。于是周末便着手进行了测试尝试(即尝试将视频播放到桌面上),结果发现其实操作起来非常简单(即这一功能实现起来相当便捷)。
因此本篇文章对Android 实现"透明屏幕"一文进行了深入学习与参考,在代码实现上也进行了部分优化与调整。
效果图是这样的:

注:本文采用的小米5S型号手机作为测试设备,在不同环境下可能存在一定的兼容性问题。
我们正在尝试解决这一问题。
如需进一步讨论,请随时留言。
二、实现
(1) 配置相关
请先创建一个XML文件,并将其用于存储wallpaper的thumbnail、description和settingsActivity信息。为了简化说明,默认情况下我们目前只实现了thumbnail功能。
<wallpaper xmlns:android=“http://schemas.android.com/apk/res/android”
android:thumbnail=“@mipmap/ic_launcher” />
(2)编写代码
在屏幕上持续展示的Wallpaper背后其实是一个Service。为了实现这一目标,在此基础上需要继承自WallpaperService并负责实现核心功能模块onCreateEngine的具体逻辑。具体来说onCreateEngine将负责初始化必要的组件和服务资源,并确保整个 WallPaper系统能够稳定运行。
public class VideoLiveWallpaper extends WallpaperService {
public Engine onCreateEngine() {
return new VideoEngine();
}
//…
}
可以看出返回结果是一个名为Engine的特殊对象,在WallpaperService这个类中作为内部类存在。该引擎包括多个事件处理方法:如onSurfaceCreated用于表面创建时的操作、onSurfaceChanged用于表面变化时的处理逻辑以及onSurfaceDestroyed用于表面销毁时的动作;此外还有on.TouchEvent来响应触摸事件的发生。一想到这些事件处理方法的存在,“表面视图”的概念自然浮现在脑海里。“表面视图”是Android系统中一个重要的组件,在使用触摸屏设备时尤其常见。
此外,大家还记得在Android播放视频吗?
传统的方法主要依赖于VideoView。除此之外, 另一种实现方式是利用MediaPlayer与SurfaceView协同工作。例如今天的案例采用了类似的方式。
为了实现数据流的有效传输至Surface端点,建议采用MediaPlayer的技术来持续不断地输入经过解码的数据块。
class VideoEngine extends Engine {
private MediaPlayer mMediaPlayer;
@Override
public void onSurfaceCreated(SurfaceHolder holder) {
L.d("VideoEngine#onSurfaceCreated ");
super.onSurfaceCreated(holder);
mMediaPlayer = new MediaPlayer();
mMediaPlayer.setSurface(holder.getSurface());
try {
AssetManager assetMg = getApplicationContext().getAssets();
AssetFileDescriptor fileDescriptor = assetMg.openFd(“test1.mp4”);
mMediaPlayer.setDataSource(fileDescriptor.getFileDescriptor(),
fileDescriptor.getStartOffset(), fileDescriptor.getLength());
mMediaPlayer.setLooping(true);
mMediaPlayer.setVolume(0, 0);
mMediaPlayer.prepare();
mMediaPlayer.start();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void onVisibilityChanged(boolean visible) {
L.d("VideoEngine#onVisibilityChanged visible = " + visible);
if (visible) {
mMediaPlayer.start();
} else {
mMediaPlayer.pause();
}
}
@Override
public void onSurfaceDestroyed(SurfaceHolder holder) {
L.d("VideoEngine#onSurfaceDestroyed ");
super.onSurfaceDestroyed(holder);
mMediaPlayer.release();
mMediaPlayer = null;
}
代码极为简洁,在onSurfaceCreated事件中进行初始化mMediaPlayer。其核心实现方式即为调用setSurface方法。其中,默认采用了静音处理。
当桌面不可见时触发的事件函数 onVisibilityChanged 表示我们需要在不可见状态暂停播放,并等待桌面重新可见后再继续播放。
当onSurfaceDestroyed时释放资源~~
完成我们的VideoLiveWallpaper开发工作,请记住:该应用属于Service类型,请确保已注册。
<service
android:name=“.VideoLiveWallpaper”
Android:Label设置为(@String)/app_name)
android:permission=“android.permission.BIND_WALLPAPER”
android:process=“:wallpaper”>
<meta-data
android:name=“android.service.wallpaper”
android:resource=“@xml/livewallpaper” />
(3)设置为壁纸
完成注册后,在 MainActivity 中部署一个按钮功能用于设置为主屏幕图标。
public static void setToWallPaper(Context context) {
final Intent intent = new Intent(WallpaperManager.ACTIONCHANGE LIVELY WALLPAINTER);
intent.putExtra(WallpaperManager.EXTRA_LIVE_WALLPAPER_COMPONENT,
new ComponentName(context, VideoLiveWallpaper.class));
context.startActivity(intent);
}
这样就完成了代码的初步编写啦~~
(4)增加一些参数的支持
上一次我们默认将视频桌面设置为静音状态,在某些情况下我们需要动态调整视频桌面的参数设置。常规做法是尝试使用settingsActivity进行配置。但我也觉得广播机制同样适用——基本上就是Service(尤其当其运行于独立进程中)与Activity之间的通信方式。
这里我们增加一个复选框,支持设置开启声音or关闭声音。
public static final String VIDEO_PARAMS_CONTROL_ACTION = "com.zhy.livewallpaper";
public static final String KEY_ACTION = “action”;
public static final int ACTION_VOICE_SILENCE = 110;
public static final int ACTION_VOICE_NORMAL = 111;
class VideoEngine extends Engine {
// 省略其他代码
private BroadcastReceiver mVideoParamsControlReceiver;
@Override
public void onCreate(SurfaceHolder surfaceHolder) {
super.onCreate(surfaceHolder);
该视频控制意图过滤器实例由指定参数初始化
注册函数registerReceiver被调用以实现将参数mVideoParamsControlReceiver初始化为新的广播接收器并开始监听指定的事件类型
@Override
public void onReceive(Context context, Intent intent) {
L.d(“onReceive”);
int action = intent.getIntExtra(KEY_ACTION, -1);
switch (action) {
case ACTION_VOICE_NORMAL:
mMediaPlayer.setVolume(1.0f, 1.0f);
break;
case ACTION_VOICE_SILENCE:
mMediaPlayer.setVolume(0, 0);
break;
}
}
}, intentFilter);
}
@Override
总结
在金融公司任职期间, 笔者并未表现出对技术的特别追求, 但个人对于技术创新始终保持较高的热情. 然而由于两者之间的不协调, 笔者并不太融洽, 因此不得不将主要目标锁定在互联网大厂这样的平台. 希望大家能够勇敢地去尝试实现自己的职业理想与创新理念.




觉得有收获的记得点赞,关注+收藏哦!你们的点赞就是我的动力!
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》 ,点击传送门,即可获取!
不入,只能把目标放在互联网大厂了。也希望大家都去敢于尝试和追逐自己的梦想!
BATJ大厂Android高频面试题
[外链图片转存中…(img-ZRb3Jbqd-1714407482609)]
[外链图片转存中…(img-Xy1034Do-1714407482611)]
[外链图片转存中…(img-7CaNz9ws-1714407482611)]
[外链图片转存中…(img-fgmI6yDb-1714407482612)]
觉得内容对您有帮助,请点个赞并关注订阅号以及星标公众号!您的支持是我创作的动力源泉!
觉得内容对您有帮助,请点个赞并关注订阅号以及星标公众号!您的支持是我创作的动力源泉!
《Android学习要点归纳 + 移动架构教学视频 + 大厂面试题解析 + 项目实战源码》 ,点击下方传送门 这里 即可获取!
