所谓实时壁纸,就是指手机桌面不再是简单的图片,而是运行中的动画,这个动画是由程序实时绘制的,因此被称为实时壁纸。

为了开发实时壁纸,Android提供了WallpaperService基类,实时壁纸的实现类需要继承该基类,在Android应用中开发实时壁纸的步骤如下:

1、开发一个子类继承WallpaperService基类。

2、继承WallpaperService基类时必须重写onCreateEngine()方法,该方法返回WallpaperService.Engine子类对象。

3、开发者需要实现WallpaperService.Engine子类,并重写其中的public  void  onVisibilityChanged(boolean  visible)、public  void  onOffsetsChanged()方法。不仅如此,由于WallpaperService.Engine子类采用了与SurfaceView相同的绘图机制,因此还可选择性地重写在SurfaceHolder.Callback中的三个方法。重写这些方法时可通过SurfaceHolder动态地绘制图形。

下面的Service类就代表了实时壁纸服务,程序代码如下:

import android.graphics.Canvas;
import android.graphics.Paint;
import android.os.Handler;
import android.service.wallpaper.WallpaperService;
import android.view.MotionEvent;
import android.view.SurfaceHolder;public class LiveWallPaper extends WallpaperService{
	  //实现WallpaperService必须实现的抽象方法
	  @Override
	  public Engine onCreateEngine() {
		    // 返回自定义的Engine
		    return new MyEngine();
	  }
	  class MyEngine extends Engine{
		    //记录程序界面是否可见
		    private boolean mVisible;
		    //记录当前用户动作事件的发生位置
		    private float mTouchX = -1;
		    private float mTouchY = -1;
		    //记录当前圆圈的绘制位置
		    private float cx = 15;
		    private float cy = 20;
		    //定义画笔
		    private Paint mPaint = new Paint();
		    //定义一个Handler
		    Handler mHandler = new Handler();
		    //定义一个周期性执行的任务
		    private final Runnable drawTarget = new Runnable() {

			      @Override
			      public void run() {
				        drawFrame();
			      }
		    };
		    public void onCreate(android.view.SurfaceHolder surfaceHolder) {
			      super.onCreate(surfaceHolder);
			      //初始化画笔
			      mPaint.setColor(0xffffffff);
			      mPaint.setAntiAlias(true);
			      mPaint.setStrokeWidth(2);
			      mPaint.setStrokeCap(Paint.Cap.ROUND);
			      mPaint.setStyle(Paint.Style.STROKE);
			      //设置处理触摸事件
			      setTouchEventsEnabled(true);
		    };
		    @Override
		    public void onDestroy() {
			      super.onDestroy();
			      //删除回调
			      mHandler.removeCallbacks(drawTarget);
		    }
		    @Override
		    public void onVisibilityChanged(boolean visible) {
			      mVisible = visible;
			      //当界面可见时,执行drawFrame()方法
			      if(visible){
				        //动态地绘制图形
				        drawFrame();
			      }else{
				        //如果界面不可见,删除回调
				        mHandler.removeCallbacks(drawTarget);
			      }
		    }
		    @Override
		    public void onOffsetsChanged(float xOffset, float yOffset,
				            float xOffsetStep, float yOffsetStep, int xPixelOffset,
				            int yPixelOffset) {
			      drawFrame();
		    }
    //		//当屏幕大小改变时调用该方法
    //		@Override
    //		public void onSurfaceChanged(SurfaceHolder holder, int format,
    //              int width, int height) {
    //   super.onSurfaceChanged(holder, format, width, height);
    //	  		drawFrame();
    //		}
    //		@Override
    //		public void onSurfaceCreated(SurfaceHolder holder) {
    //	  		super.onSurfaceCreated(holder);
    //		}
    //		@Override
    //		public void onSurfaceDestroyed(SurfaceHolder holder) {
    //	  		super.onSurfaceDestroyed(holder);
    //	    mVisible = false;
    //	  		mHandler.removeCallbacks(drawTarget);
    //		}
		    @Override
		    public void onTouchEvent(MotionEvent event) {
			      // 如果检测到滑动操作
			      if(event.getAction() == MotionEvent.ACTION_MOVE){
				        mTouchX = event.getX();
				        mTouchY = event.getY();
			      }else{
				        mTouchX = -1;
				        mTouchY = -1;
			      }
			      super.onTouchEvent(event);
		    }
		    //定义绘制图形的工具方法
		    private void drawFrame(){
			      //获取该壁纸的SurfaceHolder
			      final SurfaceHolder holder = getSurfaceHolder();
			      Canvas c = null;
			      try {
				        //获取该壁纸的SurfaceHolder
				        c = holder.lockCanvas();
				        if(c != null){
					          c.save();
					          //绘制背景色
					          c.drawColor(0xff000000);
					          //在触碰点绘制圆圈
					          drawTouchPoint(c);
					          //绘制圆圈
					          c.drawCircle(cx, cy, 80, mPaint);
					          c.restore();
				        }
			      } catch (Exception e) {
				        e.printStackTrace();
			      }finally{
				        if(c != null){
					          holder.unlockCanvasAndPost(c);
				        }
			      }
			      mHandler.removeCallbacks(drawTarget);
			      //调度下一次重绘
			      if(mVisible){
				        cx += 15;
				        cy += 20;
				        //如果cx、cy移除屏幕,从左上角重新开始
				        if(cx > 320){
					          cx = 15;
				        }
				        if(cy > 400){
					          cy = 20;
				        }
				        //指定0.1秒后重新执行mDrawCube一次
				        mHandler.postDelayed(drawTarget, 100);
			      }

		    }
		    //在屏幕触碰点绘制圆圈
		    private void drawTouchPoint(Canvas c){
			      if(mTouchX >= 0 && mTouchY >= 0){
				        c.drawCircle(mTouchX, mTouchY, 40, mPaint);
			      }
		    }
	  }}

上面的程序中粗体字代码就是实现实时壁纸Service的关键代码,这两段粗体字代码重写了WallpaperService.Engine的onVisibilityChanged、onOffsetsChanged方法,并指定当桌面显示时调用drawFrame()方法进行绘制,drawFrame()方法绘制完成后通过Handler对象指定0.1秒后重绘。

上面的程序中被注释的代码是可有可无地,如果程序需要桌面的Surface改变事件提供响应,则可以考虑重写被注释代码。

定义了该Service类之后,接下来还需要在AndroidManifest.xml文件中配置该Service,配置实时壁纸Service与配置普通Service存在小小的区别。它需要指定如下两项:

1、指定运行实时壁纸需要android.permission.BIND_WALLPAPER权限。

2、为实时壁纸指定meta-data配置。

在AndroidManifest.xml文件中配置实时壁纸,也就是需要增加如下配置片段:

<!-- 配置实时壁纸Service -->
        <service android:name=".LiveWallPaper"
              android:label="@string/app_name"
              android:permission="android.permission.BIND_WALLPAPER"
              >
              <!-- 为实时壁纸配置intent-filter -->  <intent-filter >
                    <action android:name="android.service.wallpaper.WallPapreService"/>
              </intent-filter>
              <!-- 为实时壁纸配置meta-filter -->              <meta-data 
                    android:name="android.service.wallpaper"
                    android:resource="@xml/livewallpaper"
                  />
        </service>

上面的配置文件中粗体字配置部分就是配置实时壁纸的关键代码,上面的配置文件中指定了实时壁纸的meta-data放在@xml/livewallpaper中定义,因此程序还需要zaires\xml\目录下增加一个livewallpaper.xml文件,该代码如下:

 

<?xml version="1.0" encoding="utf-8"?>
<wallpaper xmls:android="http://schemas.android.com/apk/res/android"/>