动态壁纸是在Android 2.1新增的一个功能。动态壁纸可以添加到Android的桌面,具有交互式的动画背景效果。在本教程中,我们将教会你如何去制作一个交互式的动态壁纸。

动态壁纸是一个Android应用程序,包括一个服务(WallpaperService)。该服务必须包括一个引擎(WallpaperService.Engine)。该引擎是连接用户、桌面、系统之间的桥梁。它也可以绘制桌面壁纸。

首先,必须由内在的Engine类创建一个WallpaperService类。该服务必须在AndroidManifest.xml中声明为"android.service.wallpaper.WallpaperService",这样它才会作为动态壁纸被手机识别。而且还要在服务配置中附加"android.permission.BIND_WALLPAPER"的权限许可:

<service
android:name="LiveWallpaperService"
android:enabled="true"
android:icon="@drawable/icon"
android:label="@string/app_name"
android:permission="android.permission.BIND_WALLPAPER">

<intent-filter android:priority="1" >
<action android:name="android.service.wallpaper.WallpaperService" />
</intent-filter>
<meta-data
android:name="android.service.wallpaper"
android:resource="@xml/wallpaper" />

</service>

创建一个XML文件,放置在应用程序目录下的/res/xml/中。它用来描述你的动态壁纸。

<?xml version="1.0" encoding="UTF-8"?>

<wallpaper
xmlns:android="http://schemas.android.com/apk/res/android"
android:thumbnail="@drawable/thumbnail"
android:description="@string/description"
android:settingsActivity="PreferenceActivity"/>

再创建一个xml的属性文件 attrs.xml ,代码如下:

<declare-styleable name="Wallpaper">
<!-- Component name of an activity that allows the user to modify
the current settings for this wallpaper. -->
<attr name="settingsActivity" />

<!-- Reference to a the wallpaper's thumbnail bitmap. -->

<attr name="thumbnail" format="reference" />

<!-- Name of the author of this component, e.g. Google. -->
<attr name="author" format="reference" />


<!-- Short description of the component's purpose or behavior. -->
<attr name="description" />
</declare-styleable>

动态壁纸的服务代码如下

packagenet.androgames.blog.sample.livewallpaper;

importandroid.content.SharedPreferences;
importandroid.service.wallpaper.WallpaperService;
importandroid.view.MotionEvent;
importandroid.view.SurfaceHolder;

/**
*AndroidLiveWallpaperArchetype
*
@author antoinevianey
*underGPLv3:
http://www.gnu.org/licenses/gpl-3.0.html
*/
public classLiveWallpaperService extendsWallpaperService{

@Override
publicEngineonCreateEngine(){
return newSampleEngine();
}

@Override
public voidonCreate(){
super.onCreate();
}

@Override
public voidonDestroy(){
super.onDestroy();
}

public classSampleEngine extendsEngine{

privateLiveWallpaperPaintingpainting;

SampleEngine(){
SurfaceHolderholder=getSurfaceHolder();
painting= newLiveWallpaperPainting(holder,
getApplicationContext());
}

@Override
public voidonCreate(SurfaceHoldersurfaceHolder){
super.onCreate(surfaceHolder);
// registerlistenersandcallbackshere
setTouchEventsEnabled( true);
}

@Override
public voidonDestroy(){
super.onDestroy();
// removelistenersandcallbackshere
painting.stopPainting();
}

@Override
public voidonVisibilityChanged( booleanvisible){
if(visible){
// registerlistenersandcallbackshere
painting.resumePainting();
} else{
// removelistenersandcallbackshere
painting.pausePainting();
}
}

@Override
public voidonSurfaceChanged(SurfaceHolderholder, intformat,
intwidth, intheight){
super.onSurfaceChanged(holder,format,width,height);
painting.setSurfaceSize(width,height);
}

@Override
public voidonSurfaceCreated(SurfaceHolderholder){
super.onSurfaceCreated(holder);
// startpainting
painting.start();
}

@Override
public voidonSurfaceDestroyed(SurfaceHolderholder){
super.onSurfaceDestroyed(holder);
booleanretry= true;
painting.stopPainting();
while(retry){
try{
painting.join();
retry= false;
} catch(InterruptedExceptione){}
}
}

@Override
public voidonOffsetsChanged( floatxOffset, floatyOffset,
floatxStep, floatyStep, intxPixels, intyPixels){
}

@Override
public voidonTouchEvent(MotionEventevent){
super.onTouchEvent(event);
painting.doTouchEvent(event);
}

}

}

当壁纸的显示、状态或大小变化是,会调用Engine的onCreate, onDestroy, onVisibilityChanged, onSurfaceChanged, onSurfaceCreatedonSurfaceDestroyed方法。有了这些方法,动态壁纸才能展现出动画效果。而通过设置setTouchEventsEnabled(true),并且调用onTouchEvent(MotionEvent event)方法,来激活触摸事件。

我们在绘画墙纸的时候,也会使用一个单独的绘画线程

packagenet.androgames.blog.sample.livewallpaper;

importandroid.content.Context;
importandroid.graphics.Canvas;
importandroid.view.MotionEvent;
importandroid.view.SurfaceHolder;

/**
*AndroidLiveWallpaperpaintingthreadArchetype
*
@author antoinevianey
*GPLv3:
http://www.gnu.org/licenses/gpl-3.0.html
*/
public classLiveWallpaperPainting extendsThread{

/** ReferencetotheViewandthecontext */
privateSurfaceHoldersurfaceHolder;
privateContextcontext;

/** State */
private booleanwait;
private booleanrun;

/** Dimensions */
private intwidth;
private intheight;

/** Timetracking */
private longpreviousTime;
private longcurrentTime;

publicLiveWallpaperPainting(SurfaceHoldersurfaceHolder,
Contextcontext){
// keepareferenceofthecontextandthesurface
// thecontextisneededifyouwanttoinflate
// someresourcesfromyourlivewallpaper.apk
this.surfaceHolder=surfaceHolder;
this.context=context;
// don'tanimateuntilsurfaceiscreatedanddisplayed
this.wait= true;
}

/**
*Pausesthelivewallpaperanimation
*/
public voidpausePainting(){
this.wait= true;
synchronized( this){
this.notify();
}
}

/**
*Resumethelivewallpaperanimation
*/
public voidresumePainting(){
this.wait= false;
synchronized( this){
this.notify();
}
}

/**
*Stopthelivewallpaperanimation
*/
public voidstopPainting(){
this.run= false;
synchronized( this){
this.notify();
}
}

@Override
public voidrun(){
this.run= true;
Canvasc= null;
while(run){
try{
c= this.surfaceHolder.lockCanvas( null);
synchronized( this.surfaceHolder){
currentTime=System.currentTimeMillis();
updatePhysics();
doDraw(c);
previousTime=currentTime;
}
} finally{
if(c!= null){
this.surfaceHolder.unlockCanvasAndPost(c);
}
}
// pauseifnoneedtoanimate
synchronized( this){
if(wait){
try{
wait();
} catch(Exceptione){}
}
}
}
}

/**
*Invokewhenthesurfacedimensionchange
*/
public voidsetSurfaceSize( intwidth, intheight){
this.width=width;
this.height=height;
synchronized( this){
this.notify();
}
}

/**
*Invokewhilethescreenistouched
*/
public voiddoTouchEvent(MotionEventevent){
// handletheeventhere
// ifthereissomethingtoanimate
// thenwakeup
this.wait= false;
synchronized( this){
notify();
}
}

/**
*Dotheactualdrawingstuff
*/
private voiddoDraw(Canvascanvas){}

/**
*Updatetheanimation,spritesorwhatever.
*Ifthereisnothingtoanimatesetthewait
*attributeofthethreadtotrue
*/
private voidupdatePhysics(){
// ifnothingwasupdated:
// this.wait=true;
}

}

如果桌面壁纸是可见状态下,系统服务通知有新的东西,这个类会优先把它绘制在画布上。如果没有动画了,updatePhysics会通知线程去等待。通常SurfaceView在有两个画布交替绘制的时候,会在画布上绘制上一次......

如果要让你的动态墙纸有配置功能,只要创建一个PreferenceActivity,并将它在wallpaper.xml文件中声明。同时让SharedPreference对象可以找到你的配置选项。

教程就写到这里,如果还有什么不懂,你可以通过Eclipse来浏览完整的源代码:SampleLiveWallpaper

更多相关文章

  1. Android调Ajax和动态添加JS中的token(Android 和JS完全交互)
  2. Android 程序的动态调试
  3. android静态图片和动态壁纸
  4. Android动态部署五:如何从插件apk中启动Service
  5. Android UI详解之动态布局
  6. Android N 固定壁纸大小不拉伸
  7. android 设置壁纸几种方法
  8. 手机壁纸设置相关

随机推荐

  1. repo sync同步Android 源代码下载到99%出
  2. MUTF-8编码格式介绍
  3. Android播放视频之MediaPlayer和SurfaceV
  4. Android Studio--HelloWorld
  5. Android四种存储方式 sharedpreference,f
  6. Android的StrictMode(严苛模式)
  7. 自定义控件-进度条
  8. Android JSON 解析(一) JSONObject 和 JS
  9. Dialog自定义Style
  10. Android的系统服务一览 .