android 壁纸服务,Android视频壁纸的实现
视频壁纸属于动态壁纸,所以视频壁纸就可以用Android系统提供的动态壁纸服务来实现。首先先介绍一下在实现过程中会用到的几个类。
WallpaperManager
Android提供的用于管理壁纸的类,里面有几个方法在实现过程中需要用到
getInstance(context) 获取一个实例
clear() 清空所有的壁纸
getWallpaperInfo() 获取当前壁纸的信息
WallpaperService
Android系统提供的壁纸服务的抽象类,实现一个动态壁纸必须要继承该类并实现onCreateEngine()方法,该类的唯一功能就是返回绘制动态壁纸所需要的Engine实例。
WallpaperService.Engine
Engine是WallpaperService一个内部类,动态壁纸的所有显示过程的绘制都由该类完成,我们需要继承该类并实现以下三个方法:
onSurfaceCreated()
onSurfaceDestroyed()
onVisibilityChanged()
当然还有其他的如onCreate()和onDestroy()方法等等。
视频壁纸的实现过程
首先我们需要自定义一个类VideoWallPaperService来继承WallpaperService类并实现onCreateEngine()方法,在该方法中需要返回一个Engine实例。
public class VideoWallPaperService extends WallpaperService {
@Override
public Engine onCreateEngine() {
return new VideoEngine();
}
}
所以我们需要再VideoWallPaperService内部自定义一个VideoEngine类来继承Engine类并实现onSurfaceCreated() 、onSurfaceDestroyed()和onVisibilityChanged()方法。然后在onSurfaceCreated()方法中初始化一个MediaPlayer;在onSurfaceDestroyed()中去释放和销毁MediaPlayer;在onVisibilityChanged()方法中去切换MediaPlayer的播放和暂停。
private class VideoEngine extends Engine {
private MediaPlayer mPlayer;
@Override
public void onVisibilityChanged(boolean visible) {
if(visible) {
mPlayer.start();
} else {
mPlayer.pause();
}
}
@Override
public void onSurfaceCreated(SurfaceHolder holder) {
super.onSurfaceCreated(holder);
mPlayer = new MediaPlayer();
//不能使用setDisplay()方法
mPlayer.setSurface(holder.getSurface());
mPlayer.setDataSource(videoPath);
mPlayer.prepare();
mPlayer.start();
}
@Override
public void onSurfaceDestroyed(SurfaceHolder holder) {
super.onSurfaceDestroyed(holder);
if(mPlayer.isPlaying()) {
mPlayer.stop();
}
mPlayer.release();
mPlayer = null;
}
}
以上都完成后我们还需要对VideoWallPaperService进行注册,这里在注册时写法和普通的Service相同,其中VideoWallPaperService需要一个"android.permission.BIND_WALLPAPER"的权限,需要添加一个action为"android.service.wallpaper.WallpaperService"(固定写法),还需要一个名为"android.service.wallpaper"(固定写法)的meta-data。
android:name=".VideoWallPaperService"
android:permission="android.permission.BIND_WALLPAPER">
android:name="android.service.wallpaper"
android:resource="@xml/wallpaper" />
上面一步的代码中meta-data中需要一个xml文件源,所以我们需要再res的xml文件夹(没有就自己建)下创建一个名为wallpaper的xml文件。xml文件的根标签为wallpaper,有一下三个属性:
description 动态壁纸的文字描述
thumbnail 动态壁纸的图片描述
settingsActivity 动态壁纸的设置界面(会在预览界面出现)
android:description="@string/wallpaper_description"
android:settingsActivity="com.example.videowallpaper.SettingsActivity"
android:thumbnail="@mipmap/ic_launcher">
接下来就是启动壁纸服务了,这里我们不能通过context的startService()方法来启动壁纸服务,我们需要通过启动系统的预览界面来间接启动服务。
Intent intent = new Intent(WallpaperManager.ACTION_CHANGE_LIVE_WALLPAPER);
intent.putExtra(WallpaperManager.EXTRA_LIVE_WALLPAPER_COMPONENT, new ComponentName(context, VideoWallPaperService.class));
context.startActivity(intent);
除了启动还需要关闭壁纸服务,我们可以通过WallpaperManager的clear()方法来关闭,也可以通过WallpaperService的clearWallpaper()(已经被标记过时)方法来关闭壁纸。
try {
WallpaperManager.getInstance(context).clear();
} catch(IOException e) {
e.printStackTrace();
}
其他需要注意的地方
设置壁纸需要"android.permission.SET_WALLPAPER"权限
播放本地视频需要"android.permission.READ_EXTERNAL_STORAGE"权限
VideoEngine的MediaPlayer的播放地址要使用持久化保存数据(数据库、Preference等),否则设置好视频壁纸后将手机关机再开机,就会出bug
WallpaperService的onCreateEngine()方法返回的Engine实例不能使用单例模式,必须每次都返回一个新的Engine实例
可以通过WallpaperManager的getWallpaperInfo()方法来判断当前自己的服务是否已经在运行,从而可以通过广播或者其他通知来直接修改壁纸播放的视频,从而避免每次更换一个视频都需要走一次系统的预览界面。
最后贴一下VideoWallPaperService的完整代码(仅供参考):
package com.example.videowallpaper;
import android.app.WallpaperInfo;
import android.app.WallpaperManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.media.MediaPlayer;
import android.preference.PreferenceManager;
import android.service.wallpaper.WallpaperService;
import android.text.TextUtils;
import android.view.SurfaceHolder;
import java.io.IOException;
public class VideoWallPaperService extends WallpaperService {
private static final String SERVICE_NAME = "com.example.videowallpaper.VideoWallPaperService";
@Override
public Engine onCreateEngine() {
return new VideoEngine();
}
public static void startWallPaper(Context context, String videoPath) {
WallpaperInfo info = WallpaperManager.getInstance(context).getWallpaperInfo();
if(info != null && SERVICE_NAME.equals(info.getServiceName())) {
changeVideo(context, videoPath);
} else {
startNewWallpaper(context, videoPath);
}
}
public static void closeWallpaper(Context context) {
try {
WallpaperManager.getInstance(context).clear();
} catch(IOException e) {
e.printStackTrace();
}
}
private static void startNewWallpaper(Context context, String path) {
saveVideoPath(context, path);
Intent intent = new Intent(WallpaperManager.ACTION_CHANGE_LIVE_WALLPAPER);
intent.putExtra(WallpaperManager.EXTRA_LIVE_WALLPAPER_COMPONENT, new ComponentName(context, VideoWallPaperService.class));
context.startActivity(intent);
}
private static void changeVideo(Context context, String path) {
saveVideoPath(context, path);
Intent intent = new Intent();
intent.setAction(Constant.ACTION);
intent.putExtra(Constant.BROADCAST_SET_VIDEO_PARAM, Constant.ACTION_SET_VIDEO);
context.sendBroadcast(intent);
}
public static void setVolume(Context context, boolean hasVolume) {
Intent intent = new Intent();
intent.setAction(Constant.ACTION);
if(hasVolume) {
intent.putExtra(Constant.BROADCAST_SET_VIDEO_PARAM, Constant.ACTION_VOICE_NORMAL);
} else {
intent.putExtra(Constant.BROADCAST_SET_VIDEO_PARAM, Constant.ACTION_VOICE_SILENCE);
}
context.sendBroadcast(intent);
}
private static void saveVideoPath(Context context, String path) {
SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(context).edit();
editor.putString(Constant.VIDEO_PATH, path);
editor.apply();
}
private String getVideoPath() {
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
return preferences.getString(Constant.VIDEO_PATH, null);
}
private class VideoEngine extends Engine implements MediaPlayer.OnPreparedListener,
MediaPlayer.OnCompletionListener, MediaPlayer.OnErrorListener {
private MediaPlayer mPlayer;
private boolean mLoop;
private boolean mVolume;
private boolean isPapered = false;
private VideoEngine() {
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(VideoWallPaperService.this);
mLoop = preferences.getBoolean("loop", true);
mVolume = preferences.getBoolean("volume", false);
}
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
int action = intent.getIntExtra(Constant.BROADCAST_SET_VIDEO_PARAM, -1);
switch(action) {
case Constant.ACTION_SET_VIDEO: {
setVideo(getVideoPath());
break;
}
case Constant.ACTION_VOICE_NORMAL: {
mVolume = true;
setVolume();
break;
}
case Constant.ACTION_VOICE_SILENCE: {
mVolume = false;
setVolume();
break;
}
}
}
};
@Override
public void onCreate(SurfaceHolder surfaceHolder) {
super.onCreate(surfaceHolder);
IntentFilter filter = new IntentFilter();
filter.addAction(Constant.ACTION);
registerReceiver(mReceiver, filter);
}
@Override
public void onDestroy() {
super.onDestroy();
unregisterReceiver(mReceiver);
}
@Override
public void onVisibilityChanged(boolean visible) {
if(isPapered) {
if(visible) {
mPlayer.start();
} else {
mPlayer.pause();
}
}
}
@Override
public void onSurfaceCreated(SurfaceHolder holder) {
super.onSurfaceCreated(holder);
mPlayer = new MediaPlayer();
setVideo(getVideoPath());
}
@Override
public void onSurfaceDestroyed(SurfaceHolder holder) {
super.onSurfaceDestroyed(holder);
if(mPlayer.isPlaying()) {
mPlayer.stop();
}
mPlayer.release();
mPlayer = null;
}
@Override
public void onPrepared(MediaPlayer mp) {
isPapered = true;
mp.start();
}
@Override
public void onCompletion(MediaPlayer mp) {
closeWallpaper(getApplicationContext());
}
@Override
public boolean onError(MediaPlayer mp, int what, int extra) {
closeWallpaper(getApplicationContext());
return true;
}
private void setVideo(String videoPath) {
if(TextUtils.isEmpty(videoPath)) {
closeWallpaper(getApplicationContext());
throw new IllegalArgumentException("video path is null");
}
if(mPlayer != null) {
mPlayer.reset();
isPapered = false;
try {
mPlayer.setOnPreparedListener(this);
mPlayer.setOnCompletionListener(this);
mPlayer.setOnErrorListener(this);
mPlayer.setLooping(mLoop);
// mPlayer.setDisplay(getSurfaceHolder());
mPlayer.setSurface(getSurfaceHolder().getSurface());
setVolume();
mPlayer.setDataSource(videoPath);
mPlayer.prepareAsync();
} catch(IOException e) {
e.printStackTrace();
}
}
}
private void setVolume() {
if(mPlayer != null) {
if(mVolume) {
mPlayer.setVolume(1.0f, 1.0f);
} else {
mPlayer.setVolume(0f, 0f);
}
}
}
}
}
还有一个SettingsActivity的代码也贴出来吧
这里说明一下推荐使用PreferenceFragment来代替PreferenceActivity
package com.example.videowallpaper;
import android.os.Bundle;
import android.preference.PreferenceActivity;
public class SettingsActivity extends PreferenceActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.setting_layout);
}
}
setting_layout
android:key="video_param"
android:title="设置">
android:defaultValue="true"
android:key="loop"
android:title="是否循环播放" />
android:checked="false"
android:key="volume"
android:title="是否开启声音" />
Constant.java(自定义的一些常量)
public class Constant {
public static final String BROADCAST_SET_VIDEO_PARAM = "broadcast_set_video_param";
public static final String ACTION = "action";
public static final String VIDEO_PATH = "action_video_path";
public static final int ACTION_SET_VIDEO = 0x101;
public static final int ACTION_VOICE_SILENCE = 0x102;
public static final int ACTION_VOICE_NORMAL = 0x103;
}
android 壁纸服务,Android视频壁纸的实现相关推荐
- android 壁纸服务,Android开发学习之WallPaper设置壁纸详细介绍与实例
今天和大家分享的是关于在android中设置壁纸的方法,在android中设置壁纸的方法有三种,分别是: 1.使用wallpapermanager的setresource(int resourceid ...
- android cne服务,android 自带APP 作用
AntHalService.apk 就是天线接口,用来连接天线的. ApplicationsProvider.apk 应用程序支持服务,主要用于同 ...
- 动态壁纸安卓_酷玩软件第7期:还在用无声的动态壁纸?短视频壁纸软件(Win+安卓版本)...
最近在刷某视频平台的时候,看到下面这个视频很喜欢,然后我就想能不能把这个视频设置成手机壁纸呢?还带声音那种. 今天终于找到一款叫做"飞火动态壁纸"的软件(包括安卓版和Win版本). ...
- android 闹钟服务,android开发笔记之 AlarmManager(闹钟服务)
手机闹钟服务AlarmManager AlarmManager通常用来开发手机闹钟,并且它是一个全局定时器,可在指定时间或指定周期启动其他组件(包括Activity,Service,Broadcast ...
- 安卓壁纸服务(动态壁纸)使用与源码分析
概览 安卓的动态壁纸可以归属到SystemUI中,是SystemUI管理的一部分,安卓支持静态壁纸,同时也支持动态壁纸(added in API level 7 ) 用户可以从设备的内部或者是外部存储 ...
- android 打印机服务,Android系统打印服务插件printservice开发
一 简介 从Android4.4开始,系统加入了打印相关的API,可以通过系统打印服务实现打印.对于需要使用打印功能的APP可参考官方教程接入打印服务. 这不是本文的内容,本文介绍打印机厂商如何使自己 ...
- android socket 服务,android 创建socket 通信型service
仿照instaled写的 1.声明 在system/core/rootdir/init.rc中添加: service testlang /system/bin/testlang # 名 ...
- android 手电筒服务,Android手电筒案例
最近在学习Android的开发,写了个手电筒的案例,分享一下!//Activity.xml package com.fq.flashlight; import android.app.Activity ...
- android 剪贴板服务,Android剪贴板用法详解
本文实例详述了Android剪贴板的用法,分享给大家供大家参考.具体方法分析如下: 这里首先需要注意的一点,就是在使用Android剪贴板的时候大家只记住一点就行了,不管是安卓设备还是PC机,复制粘贴 ...
最新文章
- Android异步处理三:Handler+Looper+MessageQueue深入详解
- Building Fire Stations 39届亚洲赛牡丹江站B题
- java 数组json_如何在Java中创建JSON数组
- Jsoup实现Iteye自动登录
- P4213 【模板】杜教筛
- AFN框架和SDWebImage框架的上手体验
- Paw 百度ai_直面落地!百度EasyDL产业智能创新大赛成果覆盖能源、交通、水利民生重业...
- 机器学习笔记(七):神经网络:表示
- php调用文章标题,zblogphp标题格式的标签调用详细说明
- VUe3 @cli(axios)跨域访问
- 分布式资本合伙人孙铭:分布式存储是未来趋势,非短期炒作
- centos6下yslow部署
- mac 生成公钥和私钥
- 使用Python的pandas库操作Excel
- 初赛知识点汇总(阶段性完结
- 最新二开版本的源码博客论坛源码,UI很漂亮。
- 微信小程序中实现吸顶效果(流畅、不卡顿)
- 《出版专业基础》2015年版(初级)思考与练习 第六章
- 【Javaweb】【答卷】萌狼蓝天大二上学期期末Javaweb考试复习卷(一)
- php生成二维码海报
热门文章
- 获取中国各省份的名称以及该省份中的市及该市中的区
- Ubuntu下安装国际版qq
- CentOS下网页百度网盘下载资料
- LeetCode--剑指offer 1137题 第 N 个泰波那契数
- Android SurfaceFlinger中Fence机制--个人理解整理
- 讲述30岁处男的悲惨经历
- Python输出简洁美观的文本化表格
- IOS版微信新功能!朋友圈评论支持表情包
- matlab可以仿真开关电源吗,开关电源系统可以用()软件进行仿真。A、AnsysB、MatlabC、ProtelD、AutoCAD...
- windows环境安装BehaviorTree.CPP【基于vscode】