Android 仿火萤视频桌面 神奇的 LiveWallPaper

JaninaSirma 7年前
   <h2>一、概述</h2>    <p>上周我的微信公众号推送了一篇 <a href="/misc/goto?guid=4959748829024678809" rel="nofollow,noindex">Android 实现"透明屏幕</a> ,当时我看到之后就觉得特别感兴趣,也立即联系作者要了授权~~</p>    <p>感兴趣的原因是,我是内涵段子的资深用户,前段时间基本被一款叫火萤视频桌面的软件(就是将视频作为桌面)给刷屏了,所以看了下作者的代码,看到了SurfaceHolder,立刻想到了,肯定可以用来播放视频实现视频桌面的效果,于是周末尝试了下,果然很简单。</p>    <p>所以本篇文章无限感谢 <a href="/misc/goto?guid=4959748829024678809" rel="nofollow,noindex">Android 实现"透明屏幕</a> 一文,代码也部分参考自其提供的透明相机。</p>    <p><a href="/misc/goto?guid=4959748829138369436" rel="nofollow,noindex">https://github.com/songixan/Wallpaper</a></p>    <p>效果图是这样的:</p>    <p><img src="https://simg.open-open.com/show/237be053351e9ff74a4319fb6867f6d8.gif"></p>    <p>注:本文的测试机为小米5s ,可能不同手机会有一些兼容性问题,尝试解决下。</p>    <h2>二、实现</h2>    <h3>(1) 配置相关</h3>    <p>首先编写一个xml文件,用于描述wallpaper的 thumbnail 、 description 、 settingsActivity 等,这里为了简单,仅设置了thumbnail。</p>    <pre>  <code class="language-java"><?xml version="1.0" encoding="utf-8"?>  <wallpaper xmlns:android="http://schemas.android.com/apk/res/android"      android:thumbnail="@mipmap/ic_launcher" /></code></pre>    <h3>(2)编写代码</h3>    <p>Wallpaper需要在屏幕上一直显示,其背后其实是一个Service,所以实现一个Wallpaper需要继承自 WallpaperService ,实现其抽象方法 onCreateEngine ,如下:</p>    <pre>  <code class="language-java">public class VideoLiveWallpaper extends WallpaperService {      public Engine onCreateEngine() {          return new VideoEngine();      }      //...  }</code></pre>    <p>可以看到返回值是一个Engine,Engine为WallpaperService的内部类,其内部包含 onSurfaceCreated 、 onSurfaceChanged 、 onSurfaceDestroyed 、 onTouchEvent 等方法,看到这些方法,立刻想到了SurfaceView,关于SurfaceView相关知识可以参考:</p>    <ul>     <li><a href="/misc/goto?guid=4959748829218157407" rel="nofollow,noindex">Android SurfaceView实战 打造抽奖转盘</a></li>    </ul>    <p>此外,大家还记得在Android播放视频吗?</p>    <p>常规的做法有通过VideoView,除此以外还有通过MediaPlayer配合SurfaceView配合来实现,今天这个例子类似后者。</p>    <p>我们只需要通过MediaPlayer将解码的数据不断的输送到传入的Surface中即可。</p>    <pre>  <code class="language-java">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;        }</code></pre>    <p>代码非常简单,在onSurfaceCreated中去初始化mMediaPlayer,核心代码即为设置setSurface方法,这里我默认设置了静音。</p>    <p>onVisibilityChanged,即当桌面不可见时,我们要暂停播放,等回到桌面继续。</p>    <p>当onSurfaceDestroyed时释放资源~~</p>    <p>这样我们的VideoLiveWallpaper就写好了,别忘了他是个Service,需要我们去注册。</p>    <pre>  <code class="language-java"><service      android:name=".VideoLiveWallpaper"      android:label="@string/app_name"      android:permission="android.permission.BIND_WALLPAPER"      android:process=":wallpaper">      <!-- 配置intent-filter -->      <intent-filter>          <action android:name="android.service.wallpaper.WallpaperService" />      </intent-filter>      <!-- 配置meta-data -->      <meta-data          android:name="android.service.wallpaper"          android:resource="@xml/livewallpaper" />  </service></code></pre>    <h3>(3)设置为壁纸</h3>    <p>注册完成后,我们在MainActivity中添加一个按钮点击设置为桌面背景,调用代码如下</p>    <pre>  <code class="language-java">public static void setToWallPaper(Context context) {      final Intent intent = new Intent(WallpaperManager.ACTION_CHANGE_LIVE_WALLPAPER);      intent.putExtra(WallpaperManager.EXTRA_LIVE_WALLPAPER_COMPONENT,              new ComponentName(context, VideoLiveWallpaper.class));      context.startActivity(intent);  }</code></pre>    <p>这样就完成了代码的初步编写啦~~</p>    <h3>(4)增加一些参数的支持</h3>    <p>刚才我们设置了默认是静音,可能有时候我们会希望能够动态去控制视频桌面的参数,正常应该尝试去使用 settingsActivity ,不过我觉得其实广播也挺合适的,无非就是Service(可能在独立的进程)和Activity等通信嘛~~</p>    <p>这里我们增加一个复选框,支持设置开启声音or关闭声音。</p>    <pre>  <code class="language-java">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);          IntentFilter intentFilter = new IntentFilter(VIDEO_PARAMS_CONTROL_ACTION);          registerReceiver(mVideoParamsControlReceiver = new BroadcastReceiver() {              @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      public void onDestroy() {          unregisterReceiver(mVideoParamsControlReceiver);          super.onDestroy();        }  }</code></pre>    <p>Engine还有onCreate和onDestroy声明周期方法,可以在onCreate中注册动态广播,当接受到发送的action为 ACTION_VOICE_NORMAL 则开启声音;接收到发送的 ACTION_VOICE_SILENCE 则为静音状态。</p>    <p>最后直接在VideoLiveWallpaper中添加两个静态方法用于发送广播即可:</p>    <pre>  <code class="language-java">public static void voiceSilence(Context context) {      Intent intent = new Intent(VideoLiveWallpaper.VIDEO_PARAMS_CONTROL_ACTION);      intent.putExtra(VideoLiveWallpaper.KEY_ACTION, VideoLiveWallpaper.ACTION_VOICE_SILENCE);      context.sendBroadcast(intent);  }    public static void voiceNormal(Context context) {      Intent intent = new Intent(VideoLiveWallpaper.VIDEO_PARAMS_CONTROL_ACTION);      intent.putExtra(VideoLiveWallpaper.KEY_ACTION, VideoLiveWallpaper.ACTION_VOICE_NORMAL);      context.sendBroadcast(intent);  }</code></pre>    <p>在Actiivty中:</p>    <pre>  <code class="language-java">public class MainActivity extends AppCompatActivity {      private CheckBox mCbVoice;        @Override      protected void onCreate(Bundle savedInstanceState) {          super.onCreate(savedInstanceState);          setContentView(R.layout.activity_main);            mCbVoice = (CheckBox) findViewById(R.id.id_cb_voice);            mCbVoice.setOnCheckedChangeListener(                  new CompoundButton.OnCheckedChangeListener() {                      @Override                      public void onCheckedChanged(                              CompoundButton buttonView, boolean isChecked) {                          if (isChecked) {                              // 静音                              VideoLiveWallpaper.voiceSilence(getApplicationContext());                          } else {                              VideoLiveWallpaper.voiceNormal(getApplicationContext());                          }                      }                  });      }  }</code></pre>    <p>监听一下CheckBox状态,发送广播即可。</p>    <p>ok,这样一个简单的视频桌面就完成啦~~</p>    <p>  </p>   <h2>参考</h2>    <p></p>    <ul>     <li><a href="/misc/goto?guid=4959748829309283309" rel="nofollow,noindex">http://www.vogella.com/tutorials/AndroidLiveWallpaper/article.html</a></li>     <li><a href="/misc/goto?guid=4959748829393288462" rel="nofollow,noindex">http://www.jianshu.com/u/befb61deec9c</a></li>    </ul>    <p> </p>    <p>项目主页:<a href="http://www.open-open.com/lib/view/home/1494985986236">http://www.open-open.com/lib/view/home/1494985986236</a></p>    <p> </p>