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;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值