android 静态工厂方法,Android 源码中的静态工厂方法
我们知道工厂模式有三兄弟,通常我们说的工厂模式指的是工厂方法模式,它的应用频率最高。本篇博客分享的简单工厂模式是工厂方法模式的“小弟”,确切的来讲它不属于设计模式,而是一种方法。此外,工厂方法模式还有一位“大哥”——抽象工厂模式。
今天我们来分享一下简单工厂模式的一些情况,以及它在Android源码中的应用。
定义
简单工厂模式是类的创建模式,又叫做静态工厂方法(Static Factory Method)模式。简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。
结构
简单工厂模式所涉及到的角色:
Product(抽象产品角色):产品的通用接口,定义产品的行为。
ConcreteProduct(具体产品角色):具体产品类,实现了Product接口。
Creator(工厂角色):工厂类,通过静态工厂方法factoryMethord来创建对象。
实现
抽象产品角色
abstract class Product {
//所有产品类的公共业务方法
public void methodSame() {
//公共方法的实现
}
//声明抽象业务方法
public abstract void methodDiff();
}
复制代码
具体产品角色
class ConcreteProduct extends Product {
//实现业务方法
public void methodDiff() {
//业务方法的实现
}
}
复制代码
工厂角色
class Creator {
//静态工厂方法
public static Product getProduct(String arg) {
Product product = null;
if (arg.equalsIgnoreCase("A")) {
product = new ConcreteProductA();
//初始化设置product
}
else if (arg.equalsIgnoreCase("B")) {
product = new ConcreteProductB();
//初始化设置product
}
return product;
}
}
复制代码
使用场景
在以下情况下可以考虑使用简单工厂模式:
工厂类负责创建的对象比较少,由于创建的对象较少,不会造成工厂方法中的业务逻辑太过复杂。
客户端只知道传入工厂类的参数,对于如何创建对象并不关心。
优点
工厂类包含必要的判断逻辑,可以决定在什么时候创建哪一个产品类的实例,客户端可以免除直接创建产品对象的职责,而仅仅“消费”产品,简单工厂模式实现了对象创建和使用的分离。
客户端无须知道所创建的具体产品类的类名,只需要知道具体产品类所对应的参数即可,对于一些复杂的类名,通过简单工厂模式可以在一定程度减少使用者的记忆量。
缺点
系统扩展困难,一旦添加新产品就不得不修改工厂逻辑,在产品类型较多时,有可能造成工厂逻辑过于复杂,不利于系统的扩展和维护。
简单工厂模式由于使用了静态工厂方法,造成工厂角色无法形成基于继承的等级结构。
Android中简单工厂模式的应用
在Android中我们了解的使用到了简单工厂方法的地方有Bitmap对象的获取、Fragment创建等。接下来我们分开看一下。
Bitmap源码分析
首先来说我们是不能通过new方法来创建Bitmap对象的,因为从源码中可以看到Bitmap的类名是通过final来修饰的。
接下来我们随便找个入口开始看,比如:
Bitmap bmp = BitmapFactory.decodeFile(String pathName);
复制代码
我们把源码中的调用关系找出来,如下
public static Bitmap decodeFile(String pathName) {
return decodeFile(pathName, null);
}
public static Bitmap decodeFile(String pathName, Options opts) {
Bitmap bm = null;
InputStream stream = null;
try {
stream = new FileInputStream(pathName);
bm = decodeStream(stream, null, opts);
} catch (Exception e) {
/* do nothing.
If the exception happened on open, bm will be null.
*/
Log.e("BitmapFactory", "Unable to decode stream: " + e);
} finally {
if (stream != null) {
try {
stream.close();
} catch (IOException e) {
// do nothing here
}
}
}
return bm;
}
public static Bitmap decodeStream(InputStream is, Rect outPadding, Options opts) {
// we don't throw in this case, thus allowing the caller to only check
// the cache, and not force the image to be decoded.
if (is == null) {
return null;
}
Bitmap bm = null;
Trace.traceBegin(Trace.TRACE_TAG_GRAPHICS, "decodeBitmap");
try {
if (is instanceof AssetManager.AssetInputStream) {
final long asset = ((AssetManager.AssetInputStream) is).getNativeAsset();
bm = nativeDecodeAsset(asset, outPadding, opts);
} else {
bm = decodeStreamInternal(is, outPadding, opts);
}
if (bm == null && opts != null && opts.inBitmap != null) {
throw new IllegalArgumentException("Problem decoding into existing bitmap");
}
setDensityFromOptions(bm, opts);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_GRAPHICS);
}
return bm;
}
private static native Bitmap nativeDecodeStream(InputStream is, byte[] storage,
Rect padding, Options opts);
/**
* Set the newly decoded bitmap's density based on the Options.
*/
private static void setDensityFromOptions(Bitmap outputBitmap, Options opts) {
if (outputBitmap == null || opts == null) return;
final int density = opts.inDensity;
if (density != 0) {
outputBitmap.setDensity(density);
final int targetDensity = opts.inTargetDensity;
if (targetDensity == 0 || density == targetDensity || density == opts.inScreenDensity) {
return;
}
byte[] np = outputBitmap.getNinePatchChunk();
final boolean isNinePatch = np != null && NinePatch.isNinePatchChunk(np);
if (opts.inScaled || isNinePatch) {
outputBitmap.setDensity(targetDensity);
}
} else if (opts.inBitmap != null) {
// bitmap was reused, ensure density is reset
outputBitmap.setDensity(Bitmap.getDefaultDensity());
}
}
复制代码
我们来分析一下调用过程,可以看到decodeFile(String pathName)调用的是decodeFile(String pathName, Options opts),在两个参数的decodeFile方法中又去调用了decodeStream(InputStream is, Rect outPadding, Options opts)方法,然后最终调用nativeDecodeAsset或者nativeDecodeStream来构建Bitmap对象,这两个都是native方法(Android中使用Skia库来解析图像 )。再经过setDensityFromOptions方法的一些设置解码密度之类的操作,返回我们要的Bitmap对象。
/**
* Creates Bitmap objects from various sources, including files, streams, and byte-arrays.
*/
看下BitmapFactory的注释我们可以看到,这个工厂支持从不同的资源创建Bitmap对象,包括files, streams, 和byte-arrays,但是调用关系都大同小异。
Fragment创建
有时候,为了简化简单工厂模式,我们可以将抽象产品类和工厂类合并,将静态工厂方法移至抽象产品类中。Fragment的创建使用简单工厂方法没有抽象产品类,所以工厂类放到了实现产品类中。
在AndroidStudio中输入newInstance会自动补全Fragment的简单工厂方法。
public static TasksFragment newInstance() {
Bundle args = new Bundle();
TasksFragment fragment = new TasksFragment();
fragment.setArguments(args);
return fragment;
}
复制代码
使用静态工厂方法,将外部传入的参数可以通过Fragment.setArgument保存在它自己身上,这样我们可以在Fragment.onCreate(…)调用的时候将这些参数取出来。
这样写有什么好处呢?
避免了在创建Fragment的时候无法在类外部知道所需参数的问题。
Fragment推荐使用setArguments来传递参数,避免在横竖屏切换的时候Fragment自动调用自己的无参构造函数,导致数据丢失。
android 静态工厂方法,Android 源码中的静态工厂方法相关推荐
- 设计模式 笔记4 | 简单工厂模式 在源码中的应用 | Calendar 日历 | 源码浅析 | 使用总结 | 建造者模式
文章目录 一.Calendar 日历类 1.1 内部属性 1.2 设置时间属性值 1.3 获取时间属性 1.4 使用 Calander 计算时间 二.Calender 类中的设计模式 2.1 简单工厂 ...
- Python:如何查看一个对象有哪些属性、方法以及查询源码中只有pass的方法的参数
Python:如何查看一个对象有哪些属性.方法以及查询源码中只有pass的方法的参数 1.问题背景 2.解决思路 2.1.查看对象有哪些属性或方法 2.1.1.dir()函数 2.1.2.help命令 ...
- Android 编译过程介绍,Android.mk 和 Android.bp 分析, 在源码中编译 AndroidStudio 构建的 App
目录 一.Android 编译 1. 编译流程 2. Soong 介绍 3. build.sh 二.Android.mk 解析 三.Android.bp 解析 1. 模块类型 2. 模块属性 四.An ...
- vue 拷贝 数组_vue源码中值得学习的方法
最近在深入研究vue源码,把学习过程中,看到的一些好玩的的函数方法收集起来做分享,希望对大家对深入学习js有所帮助.如果大家都能一眼看懂这些函数,说明技术还是不错的哦. 1. 数据类型判断 Objec ...
- WebRTC源码中turnserver的使用方法
WebRTC的源码中自带了一个turnserver,编译之后,会在out/Default下生成一个turnserver文件,可以充当STUN和TURN server.用法如下: ./turnserve ...
- 智慧工厂人员定位系统源码,实现对工厂内的人车、物、料等的精确定位
智慧工厂人员定位系统源码 技术架构:Java+ vue+ spring boot 系统概述: 采用UWB定位技术,通过在厂区内布设一定数量的定位基站,实时精确地定位员工.车辆.物品上微标签位置,零延时 ...
- android 单独编译lk,ASOP源码中单独编译preloader/lk/kernel/framework模块
单独编译preloader 主要步骤 cd bootable/bootloader/preloader ./build.sh 2>&1 TARGET_PRODUCT=${PROJECT} ...
- 工厂设计模式(java版本、spring源码中使用的工厂模式)
最近在学习spring源码,发现在IoC容器初始化的时候创建各种bean,然后在代码中看到各种beanFactory和factoryBean,很显然spring容器在创建bean的过程是使用了工厂设计 ...
- Google 源码中电池百分比获取方法和格式转换
Google 源码的电池百分比获取和转换 package com.android.settingslib;public class Utils {/** Formats a double from 0 ...
最新文章
- gpu浮点计算能力floaps_聊聊 GPU 峰值计算能力
- 使用.Net图表开发工具JDash.Net添加组件
- 控制SAP Spartacus shipping address页面spinner显示的逻辑
- asp.net如何隐藏服务器控件TEXTBOX
- 【JavaScript】查漏补缺 —数组中filter()方法
- torch的使用笔记
- layout components pages及基本操作
- 基于 Token 的身份验证
- 数学建模的论文格式以及visio画图
- 成就:优秀的管理者成就自己,卓越的管理者成就他人(读后感)
- springboot毕业设计题目课题参考
- 北京集训队2016 Day4 超级跳
- 文字转语音合成器哪个好?这些文字转语音软件值得收藏
- Python入门——一个沙雕的表情包
- android模仿ios滚动,模仿iOS版微信的滑动View效果
- HTML5期末大作业:女装服装商城网站设计——女装服装商城(11页) HTML+CSS+JavaScript 学生DW网页设计作业成品 web课程设计网页
- qt设置背景图片注意事项
- html游戏让目标人物移动,如何用html5编写鼠标事件与游戏人物移动
- 第二章--图形图像处理技术——基础理论和基本工具的使用
- 中国科学院大学-模式识别与机器学习-复习、往年真题整理(含解答)【硬干货,博主本课程90+】