由于最近工作需要了解android的壁纸机制,当时急切地想在网上找点资料来了解WallpaperManager.setResource()之后的流程,但网上仅有一点不全的东西,其它的全是粘贴复制那点不全的内容,真是捉急。今天自己来写下关于设置壁纸的流程,希望后来者不用像本人一样找不到能用的资料。

假设调用WallpaperManager.setResource()方法来设置壁纸(还有wallpaperManager的其它方法也可以设置壁纸,但流程是一样的),

public void setResource(int resid) throws IOException {

if (sGlobals.mService == null) {

Log.w(TAG, "WallpaperService not running");

return;

}

try {

Resources resources = mContext.getResources();

/* Set the wallpaper to the default values */

ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(

"res:" + resources.getResourceName(resid));

if (fd != null) {

FileOutputStream fos = null;

try {

fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd);

setWallpaper(resources.openRawResource(resid), fos);

} finally {

if (fos != null) {

fos.close();

}

}

}

} catch (RemoteException e) {

}

}

代码里牵涉到sGlobals.mService,这个mService是WallpaperManagerService的实例对象,它是通过下面这两句话来初始化的。

IBinder b = ServiceManager.getService(Context.WALLPAPER_SERVICE);

mService = IWallpaperManager.Stub.asInterface(b);

可以去查看WallpaperManagerService的代码,发现WallpaperManagerService正是实现了IWallpaperManager.Stub,而ServiceManager中正是以关键字Context.WALLPAPER_SERVICE保存的WallpaperManagerService实例,由以上两点可以得知mService正是WallpaperManagerService的实例对象。WallpaperManagerService的setWallpaper其实主要作用是取得一个ParcelFileDescriptor对象,这个对象指向了/data/system/user/0/wallpaper这个文件,接着根据ParcelFileDescriptor生成文件输出流fos,再调用resources.openRawResource(resid)获得源壁纸的文件输入流,传入WallpaperManager的下一个方法,setWallpaper(InputStream,FileOutputStream)。

而在这个方法中主要代码为

while ((amt=data.read(buffer)) > 0) {

fos.write(buffer, 0, amt);

if (mSaveBakFlag && null != fos_bak) {

fos_bak.write(buffer, 0, amt);

}

}

到了这里可能有读者纳闷了,这不是文件的复制吗?对,WallpaperManager.setResource方法到最后就是进行文件复制而已,把源壁纸图片复制到之前曾经提到过的

/data/system/user/0/wallpaper这个文件中(可能不同的厂商做的定制化rom文件路径会有不一样,但大体相同),那接下来如何在桌面绘制所设壁纸呢?这就与之前提到的WallpaperManagerService和另一个新类ImageWallpaper有关。(如何有读者对ParcelFileDescriptor类不大理解,可以不求甚解把它当成一个类似于File的类就可以了)

WallpaperManagerService中含有一个WallpaperObserver内部类,这个内部类继承自FileObserver,FileObserver主要用于对文件进行监听,如果被监听的文件被重写了或删除或其它操作它都能监听并触发相应的方法。

public WallpaperObserver(WallpaperData wallpaper) {

super(getWallpaperDir(wallpaper.userId).getAbsolutePath(),

CLOSE_WRITE | DELETE | DELETE_SELF);

mWallpaperDir = getWallpaperDir(wallpaper.userId);

mWallpaper = wallpaper;

mWallpaperFile = new File(mWallpaperDir, WALLPAPER);

}

WallpaperObserver在构造方法中指明了它要监听的文件及对文件的操作,

super(getWallpaperDir(wallpaper.userId).getAbsolutePath(),CLOSE_WRITE | DELETE | DELETE_SELF);

getWallpaperDir(wallpaper.userId).getAbsolutePath()是它是监听的文件路径/data/system/user/0/,这个路径包含wallpaperManager复制的wallpaper文件,所以一旦通过wallpaperManager设置壁纸,文件监听器WallpaperObserver就会监听到关执行相应方法。

public void onEvent(int event, String path) {

if (path == null) {

return;

}

synchronized (mLock) {

// changing the wallpaper means we'll need to back up the new one

long origId = Binder.clearCallingIdentity();

BackupManager bm = new BackupManager(mContext);

bm.dataChanged();

Binder.restoreCallingIdentity(origId);

File changedFile = new File(mWallpaperDir, path);

if (mWallpaperFile.equals(changedFile)) {

notifyCallbacksLocked(mWallpaper);

if (mWallpaper.wallpaperComponent == null || event != CLOSE_WRITE

|| mWallpaper.imageWallpaperPending) {

if (event == CLOSE_WRITE) {

mWallpaper.imageWallpaperPending = false;

}

bindWallpaperComponentLocked(mWallpaper.imageWallpaperComponent, true,

false, mWallpaper);

saveSettingsLocked(mWallpaper);

}

}

}

}

在bindWallpaperComponentLocked方法中传入的第一个参数是mWallpaer.imageWallpaperComponent,这个Component指向ImageWallpaper,这个方法太过复杂,关键代码在于

mContext.bindService(intent, newConn, Context.BIND_AUTO_CREATE, serviceUserId)这句话的执行,

intent:Intent intent = new Intent(WallpaperService.SERVICE_INTERFACE);

intent.setComponent(componentName);  componentName即是之前传入的imageWallpaperComponent,表明这个intent最终会被解析定位到ImageWallpaper这个类中,ImageWallpaper继承了WallpaperService。接下来看newConn的代码

public void onServiceConnected(ComponentName name, IBinder service) {

synchronized (mLock) {

if (mWallpaper.connection == this) {

mWallpaper.lastDiedTime = SystemClock.uptimeMillis();

mService = IWallpaperService.Stub.asInterface(service);

attachServiceLocked(this, mWallpaper);

// XXX should probably do saveSettingsLocked() later

// when we have an engine, but I'm not sure about

// locking there and anyway we always need to be able to

// recover if there is something wrong.

saveSettingsLocked(mWallpaper);

}

}

}

注意这句话,mService = IWallpaperService.Stub.asInterface(service),而wallpaperService中的内部类IWallpaperServiceWrapper实现了IWallpaperService.stub,

class IWallpaperServiceWrapper extends IWallpaperService.Stub

所以根据之前的intent和IWallpaperService.Stub可知最终bindService会得到一个WallpaperService中的内部类IWallpaerServiceWrapper的引用(注意到但WallpaperService是一个abstract类,而ImageWallpaper是WallpaerService的子类,所以最终是得到的是ImageWallpaper中IWallpaerServiceWrapper的引用),看上面的onServiceConnected方法,主要执行两个方法。attachServiceLocked           saveSettingsLocked。

void attachServiceLocked(WallpaperConnection conn, WallpaperData wallpaper) {

try {

conn.mService.attach(conn, conn.mToken,

WindowManager.LayoutParams.TYPE_WALLPAPER, false,

wallpaper.width, wallpaper.height);

} catch (RemoteException e) {

Slog.w(TAG, "Failed attaching wallpaper; clearing", e);

if (!wallpaper.wallpaperUpdating) {

bindWallpaperComponentLocked(null, false, false, wallpaper);

}

}

}

attachServiceLocked方法将执行mService中的attach方法,转到WallpaperService查看attach方法,发现此方法将生成一个IWallpaperEngineWrapper对象(之前说bindService将定位到ImageWallpaper,怎么现在去WallpaperService去查看代码呢?因为ImageWallaper中没有attach方法,自然只能去其父类中查找相关的方法),在

IWallpaperEngineWrapper构造方法中将发送一个message

Message msg = mCaller.obtainMessage(DO_ATTACH);

mCaller.sendMessage(msg);

在message的处理代码中将创建绘图引擎并调用 engine.attach(this),继续追查engine.attach方法(注意ImageWallpaper中有内部类继承Engine类),发现在些方法中会调用Engine.onCreate(mSurfaceHolder),查看ImageWallpaper中的onCreate(mSurfaceHolder),接下来有一系列的逻辑来进行壁纸的绘制工作。

至些,文章里边提到了四个类,每个类都已经联系起来了。接着看ImageWallaper的绘图工作吧。

在onCreate(SurfaceHolder)方法中执行updateSurfaceSize方法,用于更新surface的大小,在updateSurfaceSize方法中调用WallpaperManager.isUseSingleWallPaper()方法确定是绘制单屏壁纸还是宽屏壁纸,updateSurfaceSize方法执行完后,onSurfaceChanged这个回调函数自动执行,在这个回调函数中再执行drawFrameLocked方法,在drawFrameLocked中就是真正绘制地方,在drawFrameLocked方法中将首先获取设置好的壁纸图片,再由是否执行硬件加速来决定是用opengl绘图还是用canvas绘图。至此,设置壁纸的整个流程已然介绍完毕。       由于本人对于绘图这一块还不是很熟悉,所以在ImageWallpaper的绘图工作介绍的不是很详细,如有哪位清楚的欢迎补充。

android壁纸服务,android壁纸服务流程浅析相关推荐

  1. Android 4.4 Kitkat Phone工作流程浅析(三)__MO(去电)流程分析

    本文来自http://blog.csdn.net/yihongyuelan 转载请务必注明出处 本文代码以MTK平台Android 4.4为分析对象,与Google原生AOSP有些许差异,请读者知悉. ...

  2. Android 5.1 Lollipop Phone工作流程浅析(十三)__InCallActivity启动Performance浅析

    前置文章: < Android 4.4 Kitkat Phone工作流程浅析(一)__概要和学习计划> <Android 4.4 Kitkat Phone工作流程浅析(二)__UI结 ...

  3. Android 2.3 SD卡挂载流程浅析(三)

    在前面两篇博文<Android 2.3 SD卡挂载流程浅析(一)><Android 2.3 SD卡挂载流程浅析(二)>中,主要简单介绍了SD卡的挂载流程以及所涉及的关键文件.在 ...

  4. Android存储设备(U盘,SD卡)状态监测(《Android 2.3 SD卡挂载流程浅析1234567)

    我们是以DV6300-T的平台来做测试的,发现有2种方式来检测android中external media(包括SD卡,USB)的状态. 一种是使用StorageListener监听,还有一种是使用广 ...

  5. 8、Zookeeper服务注册与发现原理浅析

    了解Zookeeper的我们都知道,Zookeeper是一种分布式协调服务,在分布式应用中,主要用来实现分布式服务的注册与发现以及分布式锁,本文我们简单介绍一下Zookeeper是如何实现服务的注册与 ...

  6. 玩转Windows服务系列——Windows服务小技巧

    伴随着研究Windows服务,逐渐掌握了一些小技巧,现在与大家分享一下. 将Windows服务转变为控制台程序 由于默认的Windows服务程序,编译后为Win32的窗口程序.我们在程序启动或运行过程 ...

  7. android 壁纸服务,Android视频壁纸的实现

    视频壁纸属于动态壁纸,所以视频壁纸就可以用Android系统提供的动态壁纸服务来实现.首先先介绍一下在实现过程中会用到的几个类. WallpaperManager Android提供的用于管理壁纸的类 ...

  8. android 壁纸服务,Android开发学习之WallPaper设置壁纸详细介绍与实例

    今天和大家分享的是关于在android中设置壁纸的方法,在android中设置壁纸的方法有三种,分别是: 1.使用wallpapermanager的setresource(int resourceid ...

  9. Android Wallpaper之设置壁纸流程

    What? 什么是壁纸? android wallpaper包括锁屏壁纸和桌面壁纸,壁纸又区分静态和动态两种.我们每天使用手机第一眼看到的就是壁纸,好看的壁纸对于手机的颜值也有大大的提升(滑稽),就让 ...

  10. Android静态壁纸和动态壁纸的使用和理解

    这两天在公众号上偶然看到一篇关于设置动态壁纸的文章,觉得蛮有意思的,学习了一下,以此文章记录一下怎样给手机设置静态壁纸和动态壁纸,设置壁纸的使用方法. 静态壁纸 Android中WallpaperMa ...

最新文章

  1. TensorFlow各版本下载地址,强烈推荐
  2. 博客转移至:www.bugsafe.cn
  3. 手机通过WIFI连上ZXV10 H618B路由器但不能上网问题的解决
  4. mysql 自己写数据库,自己写了一个简单的mysql数据库连接类
  5. 重命名Jakarta EE的Java EE规范
  6. 【资料整理】proftpd安装配置
  7. [转]使用 LDAP 组或角色限制访问,包含部分单点登录SSO说明
  8. [css] 浏览器是怎样判断元素是否和某个CSS选择器匹配?
  9. 如何快速的打造python 版的vim ide
  10. Django restframework 嵌套关系处理
  11. python怎么读写文件-一文看懂Python文件的读取写入操作,建议收藏-bak文件怎么打开...
  12. Min(BZOJ 1441)
  13. SQL Server2016安装教程
  14. 手机通过外网(HFS)访问电脑文件
  15. 强大TOP版淘客程序(带后台管理)
  16. 【Linux】putty 出现 inactive
  17. SQL Server 数据查询
  18. apicloud菜鸟教程_APICloud 对象之 Method
  19. 科研教育「双目视觉技术」首选!维视MV-VS220双目立体视觉系统开发平台
  20. 搜狐邮箱的Python经验

热门文章

  1. 裁员潮下,工程师该何去何从?
  2. 用matlab解系统框图,第10章MATLAB的控制系统数学建模课题.ppt
  3. 锋利jquery第三章案例 总结
  4. 电脑出现问题,你的PIN不可用。请单击以重新设置。
  5. 奥哲徐平俊:乘风、冒险与未来
  6. 基于python的表情识别_python表情识别
  7. win10升级助手_Win10系统易升如何彻底关闭?「系统天地」
  8. 现代控制理论——非线性系统的lyapunov
  9. Egg.js上传图片总结
  10. python数据分析——pyecharts地图全解