您的位置:首页 > 教育 > 培训 > 网络游戏制作公司_有寓意的logo设计图片_推广文案范文100字_广州网站排名优化报价

网络游戏制作公司_有寓意的logo设计图片_推广文案范文100字_广州网站排名优化报价

2025/5/19 3:52:15 来源:https://blog.csdn.net/ItJavawfc/article/details/146482923  浏览:    关键词:网络游戏制作公司_有寓意的logo设计图片_推广文案范文100字_广州网站排名优化报价
网络游戏制作公司_有寓意的logo设计图片_推广文案范文100字_广州网站排名优化报价

提示:Android 平台,静态壁纸实现方案

文章目录

  • 需求:Android 实现壁纸 设置
    • 场景
  • 参考资料
  • 实现方案
    • 直接调用系统 API,WallpaperManager 来实现 wallpaperManager.setResource
    • 系统源码分析
      • 系统app WallpaperPicker
      • WallpaperPickerActivity ->WallpaperCropActivity
        • onClick 底部壁纸图片点击事件
      • AlphaDisableableButton
        • actionbar_set_wallpaper.xml
      • DialogUtils
        • DialogUtils ->executeCropTaskAfterPrompt
      • WallpaperManagerCompat
      • WallpaperPicker 源码小结
    • WallpaperManager
  • 拓展
    • 放置默认壁纸 供选择
    • 配置壁纸资源包
    • 加载壁纸配置
  • 总结


需求:Android 实现壁纸 设置

最近看到一个友商实现了一个功能,壁纸作为单独apk 拎出来作为一个apk 单独出现形式,比较有意义。 自己也实现一个,实现需求同时,分析源码实现方案 和 流程。

#需求
将壁纸设置作为一个apk形式,实现壁纸设置功能

场景

很多平板方案,将这个功能单独实现,作为一个app,方便客户使用。
这里只是用一个静态壁纸设置实现的方式,来初步了解Android壁纸相关内容。

参考资料

android WallpaperPicker7.0源码分析
Android 切换壁纸代码流程追踪:
Android 12新特性之获取壁纸主色调并设置系统主题色

实现方案

直接调用系统 API,WallpaperManager 来实现 wallpaperManager.setResource

WallpaperManager wallpaperManager = WallpaperManager.getInstance(this);
try {wallpaperManager.setResource(R.drawable.picture);
} catch (IOException e) {e.printStackTrace();
}

设置静态壁纸有很多途径,但归根结底都是一下三种方法:

  • 使用WallpaperManager的setResource(int ResourceID)方法
  • 使用WallpaperManager的setBitmap(Bitmap bitmap)方法
  • 使用WallpaperManager的setStream(InputStream data)方法

可以参考WallpaperManager 源码分析,源码代码量还好,不多。

\frameworks\base\core\java\android\app\WallpaperManager.java 

在这里插入图片描述

系统源码分析

系统app WallpaperPicker

我们先看一下如何进入到WallpaperPicker 的, 实际上 我们设置壁纸两个入口:

  • 首页 长按,设置壁纸
  • 进入设置目录,进入壁纸设置【接下来从设置入口进行分析】
    在这里插入图片描述

![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/a1222db5ee604392b1faf8bdb67ace90.png

在这里插入图片描述

在这里插入图片描述

一路跟踪界面,我们发现了以下几个类,可以看出最终是从设置跳转到了一个wallpaperpicker 的包中。

com.android.settings/.Settings$WallpaperSettingsActivity 
com.android.wallpaperpicker/.WallpaperPickerActivity  

系统里面搜索结果如下:
在这里插入图片描述
可以肯定的是 wallpaperpicker 就是一个单独apk, 将这个apk 源码进行分析下。

WallpaperPickerActivity ->WallpaperCropActivity

上面已经分析了,系统对应的壁纸选择跳转到一个apk 进行选择,对应的Activity 为 WallpaperPickerActivity

public class WallpaperPickerActivity extends WallpaperCropActivityimplements OnClickListener, OnLongClickListener, ActionMode.Callback {static final String TAG = "WallpaperPickerActivity";
onClick 底部壁纸图片点击事件

这里突破点是左上角设置壁纸图标,当无壁纸选中 默认情况是不可点击的,下面壁纸选项点击选中时候左上角 设置壁纸按钮可点击了。
看该方法的注释:

Called when a wallpaper tile is clicked 也就是点击后底部弹框的操作 
 /*** Called when a wallpaper tile is clicked*/@Overridepublic void onClick(View v) {if (mActionMode != null) {// When CAB is up, clicking toggles the item insteadif (v.isLongClickable()) {onLongClick(v);}return;}WallpaperTileInfo info = (WallpaperTileInfo) v.getTag();if (info.isSelectable() && v.getVisibility() == View.VISIBLE) {selectTile(v);setWallpaperButtonEnabled(true);}info.onClick(this);}public void setWallpaperButtonEnabled(boolean enabled) {mSetWallpaperButton.setEnabled(enabled);}mSetWallpaperButton = findViewById(R.id.set_wallpaper_button);

在 WallpaperPickerActivity 类中并没有找到 mSetWallpaperButton 定义地方,只是找到加载地方 findViewById,那么去父类 WallpaperCropActivity.java 看看


protected View mSetWallpaperButton;// WallpaperCropActivity.java  类中,也是通过findViewById 来加载,并声明它是一个View 
mSetWallpaperButton = findViewById(R.id.set_wallpaper_button);那这个set_wallpaper_button 对应的到底是什么,继续找

在这里插入图片描述

这里看到了 在一个布局文件和上面所讲WallpaperPickerActivity 、WallpaperCropActivity 两个类加载了。
看看布局文件如下

<com.android.wallpaperpicker.AlphaDisableableButtonxmlns:android="http://schemas.android.com/apk/res/android"style="@style/ActionBarSetWallpaperStyle"android:id="@+id/set_wallpaper_button"android:layout_width="match_parent"android:layout_height="match_parent"android:paddingRight="20dp"android:drawableLeft="@drawable/ic_actionbar_accept"android:drawablePadding="8dp"android:gravity="start|center_vertical"android:text="@string/wallpaper_instructions"android:enabled="false" />

具体分析 如下 分析,AlphaDisableableButton 相关内容

AlphaDisableableButton

上面找到了AlphaDisableableButton , 其实就是一个自定义的View,看代码。


/*** A Button which becomes translucent when it is disabled*/
public class AlphaDisableableButton extends Button {public static float DISABLED_ALPHA_VALUE = 0.4f;public AlphaDisableableButton(Context context) {this(context, null);}public AlphaDisableableButton(Context context, AttributeSet attrs) {this(context, attrs, 0);}public AlphaDisableableButton(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);setLayerType(LAYER_TYPE_HARDWARE, null);}@Overridepublic void setEnabled(boolean enabled) {super.setEnabled(enabled);if(enabled) {setAlpha(1.0f);} else {setAlpha(DISABLED_ALPHA_VALUE);}}
}

备注:AlphaDisableableButton 类源码如上,就是一个自定义View,如上类说明:不可见的时候透明状态。

A Button which becomes translucent when it is disabled 
actionbar_set_wallpaper.xml

上面已经分析到了AlphaDisableableButton 源码和布局文件,那这个xml 又是哪里加载的。
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

这里说明WallpaperPickerActivity 、 WallpaperCropActivity 加载这个布局文件,不就是显示ActionBar 嘛,如 加载说明:

Show the custom action bar view

DialogUtils

承接上述分析 ,actionbar 点击后,也就是 设置壁纸按钮 点击,弹出选择框逻辑

actionBar.getCustomView().setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {actionBar.hide();// Never fade on finish because we return to the app that started us (e.g.// Photos), not the home screen.cropImageAndSetWallpaper(imageUri, null, false /* shouldFadeOutOnFinish */);}});cropImageAndSetWallpaper(imageUri, null, false /* shouldFadeOutOnFinish */);@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)public void cropImageAndSetWallpaper(Uri uri,CropAndSetWallpaperTask.OnBitmapCroppedHandler onBitmapCroppedHandler,boolean shouldFadeOutOnFinish) {。。。。。。。。。。。。。。DialogUtils.executeCropTaskAfterPrompt(this, cropTask, getOnDialogCancelListener());}
DialogUtils ->executeCropTaskAfterPrompt

接下来就是dialog 具体源码如下:


/*** Utility class used to show dialogs for things like picking which wallpaper to set.*/
public class DialogUtils {/*** Calls cropTask.execute(), once the user has selected which wallpaper to set. On pre-N* devices, the prompt is not displayed since there is no API to set the lockscreen wallpaper.** TODO: Don't use CropAndSetWallpaperTask on N+, because the new API will handle cropping instead.*/public static void executeCropTaskAfterPrompt(Context context, final AsyncTask<Integer, ?, ?> cropTask,DialogInterface.OnCancelListener onCancelListener) {if (Utilities.isAtLeastN()) {new AlertDialog.Builder(context).setTitle(R.string.wallpaper_instructions).setItems(R.array.which_wallpaper_options, new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int selectedItemIndex) {int whichWallpaper;if (selectedItemIndex == 0) {whichWallpaper = WallpaperManagerCompat.FLAG_SET_SYSTEM;} else if (selectedItemIndex == 1) {whichWallpaper = WallpaperManagerCompat.FLAG_SET_LOCK;} else {whichWallpaper = WallpaperManagerCompat.FLAG_SET_SYSTEM| WallpaperManagerCompat.FLAG_SET_LOCK;}cropTask.execute(whichWallpaper);}}).setOnCancelListener(onCancelListener).show();} else {cropTask.execute(WallpaperManagerCompat.FLAG_SET_SYSTEM);}}
}

其实这个类说得很明白了,就是设置壁纸用的。
这里 我们记住 我们选择的是第三个选项,也就是 桌面壁纸和锁屏壁纸,参数flag 不一样而已

   whichWallpaper = WallpaperManagerCompat.FLAG_SET_SYSTEM| WallpaperManagerCompat.FLAG_SET_LOCK;

WallpaperManagerCompat

DialogUtils 源码分析到了 源码 ,那就继续追踪到 WallpaperManagerCompat

 whichWallpaper = WallpaperManagerCompat.FLAG_SET_SYSTEM| WallpaperManagerCompat.FLAG_SET_LOCK;cropTask.execute(whichWallpaper);

public abstract class WallpaperManagerCompat {public static final int FLAG_SET_SYSTEM = 1 << 0; // TODO: use WallpaperManager.FLAG_SET_SYSTEMpublic static final int FLAG_SET_LOCK = 1 << 1; // TODO: use WallpaperManager.FLAG_SET_LOCKprivate static WallpaperManagerCompat sInstance;private static final Object sInstanceLock = new Object();public static WallpaperManagerCompat getInstance(Context context) {synchronized (sInstanceLock) {if (sInstance == null) {if (Utilities.isAtLeastN()) {sInstance = new WallpaperManagerCompatVN(context.getApplicationContext());} else {sInstance = new WallpaperManagerCompatV16(context.getApplicationContext());}}return sInstance;}}public abstract void setStream(InputStream stream, Rect visibleCropHint, boolean allowBackup,int whichWallpaper) throws IOException;public abstract void clear(int whichWallpaper) throws IOException;
}

发现这里 WallpaperManagerCompat 类还是一个抽象类,那么实际的控制其实是 WallpaperManagerCompatVN 、WallpaperManagerCompatV16, 继续看其中代码如下


public class WallpaperManagerCompatV16 extends WallpaperManagerCompat {protected WallpaperManager mWallpaperManager;public WallpaperManagerCompatV16(Context context) {mWallpaperManager = WallpaperManager.getInstance(context.getApplicationContext());}@Overridepublic void setStream(InputStream data, Rect visibleCropHint, boolean allowBackup,int whichWallpaper) throws IOException {mWallpaperManager.setStream(data);}@Overridepublic void clear(int whichWallpaper) throws IOException {mWallpaperManager.clear();}
}public class WallpaperManagerCompatVN extends WallpaperManagerCompatV16 {public WallpaperManagerCompatVN(Context context) {super(context);}@Overridepublic void setStream(final InputStream data, Rect visibleCropHint, boolean allowBackup,int whichWallpaper) throws IOException {try {// TODO: use mWallpaperManager.setStream(data, visibleCropHint, allowBackup, which)// without needing reflection.Method setStream = WallpaperManager.class.getMethod("setStream", InputStream.class,Rect.class, boolean.class, int.class);setStream.invoke(mWallpaperManager, data, visibleCropHint, allowBackup, whichWallpaper);} catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {// Fall back to previous implementation (set both)super.setStream(data, visibleCropHint, allowBackup, whichWallpaper);}}@Overridepublic void clear(int whichWallpaper) throws IOException {try {// TODO: use mWallpaperManager.clear(whichWallpaper) without needing reflection.Method clear = WallpaperManager.class.getMethod("clear", int.class);clear.invoke(mWallpaperManager, whichWallpaper);} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {// Fall back to previous implementation (set both)super.clear(whichWallpaper);}}
}哈哈,这里最终调用的其实是 WallpaperManagerCompatVNWallpaperManagerCompatV16  类的 setStream 方法。 再最终调用的就是 WallpaperManager 类的 setStream 方法。 

WallpaperPicker 源码小结

上面的代码流程分析,最终共调用到了Framework层的WallpaperManager类的 setStream 方法。

WallpaperManager

上面已经分析到了 最终调用到 WallpaperManager 服务,通过反射调用
如下 类说明

/*** Provides access to the system wallpaper. With WallpaperManager, you can* get the current wallpaper, get the desired dimensions for the wallpaper, set* the wallpaper, and more.** <p> An app can check whether wallpapers are supported for the current user, by calling* {@link #isWallpaperSupported()}, and whether setting of wallpapers is allowed, by calling* {@link #isSetWallpaperAllowed()}.*/
@SystemService(Context.WALLPAPER_SERVICE)
public class WallpaperManager {.....
}

提供了系统壁纸入口,可以获取当前壁纸、设置壁纸…, app 可以检查当前用户是否允许设置壁纸,是否有权限等。继续分析源码 ,查看部分方法如下
在这里插入图片描述

这里看到设置壁纸的三种类型方法,如上文开始的分析,

归根结底都是一下三种方法:

  • 使用WallpaperManager的setResource(int ResourceID)方法
  • 使用WallpaperManager的setBitmap(Bitmap bitmap)方法
  • 使用WallpaperManager的setStream(InputStream data)方法

尝试三种方案,设置静态壁纸就是很简单的逻辑了,直接调用api ,反射或者拿到framework.jar,调用API 直接调用的事情了。 如下,某个友商做出来的效果,实际效果大家可以自己随便做了。

在这里插入图片描述

拓展

如上通过WallerpaperPicker 包分析了壁纸设置的整体流程,如果只是需要定制壁纸选择需求可以显示图片并调用api 反射或者 api 调用实现需求;
如果需要添加壁纸选择怎么办呢? 那只需要在 app 里面配置资源包即可。
思路如下:

放置默认壁纸 供选择

在 资源包中添加壁纸图片
在这里插入图片描述

配置壁纸资源包

在这里插入图片描述

加载壁纸配置

在这里插入图片描述
在这里插入图片描述

总结

  • 这里实现了静态壁纸设置的方法,就是一个反射或者api 调用。 实际 逻辑比较简单的
  • 这里只是从系统app WallpaperPicker,通过界面,反推实现设置静态壁纸的逻辑和分析代码层面的流程和业务。 实际上 WallpaperPicker App有很多设计思想和架构设计,这里暂不深究。
  • 如果客户定制,需要动态壁纸功能。这里暂不分析,后续有机会实现下,暂不提供解决方案。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com