荏苒追寻个人博客

做一个有追求的青年


  • 首页

  • 关于

  • 标签

  • 分类

  • 归档

  • 日程表

小白学理财——股票仓位管理

发表于 2021-02-19 | 分类于 理财 , 股票

https://rainmonth.github.io/posts/F2102192.html

引子

当根据一些标准选定出心仪的股票后,常常会碰到一下几个问题:

  1. 我买的xx股票最近跌了10%,我该加仓吗?加多少?
  2. 我买的xx集团最近涨了20%,我该卖吗?卖多少?
  3. 我手上又来了一笔闲钱,该买点什么?

概念

仓位管理,

仓位管理的作用:

  1. 为本金保平安
  2. 让收益更高更持久
  3. 平和的应对市场波动

仓位管理的原则:

  1. 有钱烦恼多,没钱烦恼少
  2. 有钱也别太烦恼
  3. 吸引力优先法则

即我们要适度分散,但不能过度分散,便宜的多买点,啥时候便宜啥时候多买点

宏观仓位管理

根据市场的热度和贵贱程度,来管理整体仓位,即整体上要投多少钱在股市

微观仓位管理

根据市场情况变化,来管理某只股票的仓位,即具体在某只股票上要买多少钱,该如何一步步加仓。

小鹅投资者要避免尿频试加减仓。针对小鹅投资者,操作思路如下:

  1. 将仓位分为轻仓(小于总预算投资金额50%)和重仓(大于总预算投资金额50%)
  2. 只要股市不是太贵,你能找到一些便宜的股票,都重仓(如7至九成买入操作),如果股市贵了,就轻就轻三成如,对应卖出操作

3.将每个月的闲钱根据市场贵贱继续加仓或减仓

如果遇到大牛市或大熊市需要清仓或满仓

便宜的时候重仓,贵的时候轻仓

吸引力法则:

市场便宜的时候多买点,市场贵的时候少买一点,

由于股权投资长期看投资收益率是超过所有其他资产的,因此除非市场特别贵不然不要轻易将钱从股市撤出来!

判断市场贵贱的指标:

  1. 股市吸引力指数

简单来说就是沪深300股息率和国债收益率对比,吸引力只是越高,股市越有吸引力(越便宜)

吸引力指数越低,股市越没有吸引力(越贵)

  1. 看各大股市的PE和分位点信息

如分位点(有时候也叫温度)在30%以下时,往往是偏便宜的。

分位点在40%-60%时,往往是较合理的。

分位点在60%以上时,才是贵的。

计算各类关注股票的N

如果我们在股市中还能找到不少看得懂的股票,他们的N都比较好(如15%以上),

那股市还是便宜的

4、市场热度、成交量等信息。

单看一个指标,容易有盲点和误判,但综合以上各类信息,可以得到一个比较综合的意见。

这么设计仓位的理由:

1、不这么做的话,对于小鹅来说,如果过度轻仓,好不容易发现一只好的股票,涨了一大波,结果自己只买了一手……那就尴尬了。

2、更重要的,对于小鹅人,自己(以及自己的脑子)就是最重要的资产。

趁着鹅小,投身市场,多多积累经验,是性价比极高的。

重中之重

用闲钱投资!

小白学理财——股票基础知识

发表于 2021-02-19 | 分类于 理财 , 股票

https://rainmonth.github.io/posts/F202102191.html

股票基础知识

基础概念

基本类型

几种常用的图说明

均衡配置

将进攻型、攻守兼备型和防御型的股票按一定的比例进行配置已达到掌控全局且不用承担过大风险从而赚取收益的目的。

  • 攻守兼备型股票,牛市涨的多,熊市跌的少,俗称”大暖男;
  • 进攻型股票,牛市涨的多,但熊市跌的也多,俗称“凤凰男”;
  • 防御型股票,牛市涨得少,但熊市跌的也少,俗称“备胎男”。

三种类型目前对应的行业(只是参考):

  • 攻守兼备型,确定性高,前景好的行业,如白酒、医药、消费、先进制造业,建议配置比例35~50%;
    • 白酒,老茅
    • 医药,恒瑞
    • 消费,伊利
    • 先进制造,隆基
  • 防御型,前景一般,未来成长空间有限,缺乏想象力,估值低,典型代表如家电、三傻(银行、保险、地产)、传统制造业,建议配置比例20~40%
    • 家电,格力、美的;
    • 银行,招行,宁波银行;
    • 地产,万科、保利
    • 传统制造业,三一重工;
  • 进攻型,不确定性大,充满想象,典型行业如科技、疫苗、新能源等新兴产业建议配置比例10~15%
    • 科技,立讯精密;
    • 疫苗,智飞生物;
    • 新能源,宁德时代;

总结一下建议的资产均衡配置:

  • 攻守兼备的大暖男:35~50%
  • 防御型的备胎男:20~40%
  • 进攻型的凤凰男:10~15%

相关文章

  • [ ] 小白学理财——开篇

  • [ ] 小白学理财——基金基础知识

  • [ ] 小白学理财——股票基础知识

Android 通用功能封装7——广播管理

发表于 2021-02-08 | 分类于 Android , 通用功能

http://rainmonth.github.io/posts/A210208.html

简介

先了解一下广播的概念,然后从广播的类型、使用注意事项等几方面对广播做了简单的介绍,最后在对广播的使用做简单的封装;

阅读全文 »

Android 通用功能封装6——数据库封装

发表于 2021-02-07 | 分类于 Android , 通用功能

http://rainmonth.github.io/posts/A210207.html

简介

阅读全文 »

Android 通用功能封装5——网络库封装

发表于 2021-02-06 | 分类于 Android , 通用功能

http://rainmonth.github.io/posts/A210206.html

简介

阅读全文 »

Android 通用功能封装4——文件下载

发表于 2021-02-05 | 分类于 Android , 通用功能

http://rainmonth.github.io/posts/A210205.html

简介

阅读全文 »

Android 通用功能封装3——文件选择

发表于 2021-02-04 | 分类于 Android , 通用功能

http://rainmonth.github.io/posts/A21020r.html

简介

Android是一个系统,肯定会有类似于Windows的资源管理器,那么Android系统的文件资源管理器是什么呢?它就是MediaStore,MediaStore是Android系统提供的一个多媒体数据库,通过ContentResolver即可对数据库进行操作。

要实现的功能

  1. 采用链式调用,用Builder模式;
  2. 支持选择不同类型的文件(指定文件类型,即可显示所有对应的文件);
  3. 支持只提供数据不提供UI展示(UI可以让使用者自己定制)
  4. 友好的基础UI展示;
  5. 友好的权限请求提示;
  6. 良好的版本兼容性;
阅读全文 »

Android 通用功能封装2——图片加载

发表于 2021-02-03 | 分类于 Android , 通用功能

http://rainmonth.github.io/posts/A210203.html

  • [ ] Android通用功能封装0——开篇
  • [x] Android通用功能封装1——通用工具类封装
  • [ ] Android 通用功能封装2——图片加载
  • [ ] Android 通用功能封装3——文件选择
  • [ ] Android 通用功能封装4——文件下载
  • [ ] Android 通用功能封装5——网络库封装
  • [ ] Android 通用功能封装6——数据库封装
  • [ ] Android 通用功能封装7——广播管理

为什么要封装

现有的图片加载框架已经很好了,如Fresco、Glide等都有十分丰富的功能,但是会存在一个问题,如果没有在这个基础上进行封装,而是直接代码中使用的话,那么万一哪天我想把网络加载库从Fresco换成Glide的话,那么要替换的东西就很多,工作量就很大,所以封装时为了 控制反转,具体使用什么图片加载框架由使用者决定,不管用哪个加载库,对使用者而言,调用的API都是一样的,这就方便了 项目的移植,方便了功能的扩展,而且由于代码高内聚,低耦合,最终出问题的概率也会大大降低,这就是二次封装的意义。

封装方法

具体的封装策略就是提取各个加载框架的共性,同时支持某些加载框架的特性,共性是基础,指的是图片加载框架都具有的通用功能,特性值的是 只有某些加载框架才支持的特殊配制,这两个在封装的时候都需要考虑到,看下面这个类 ILoadStrategy。

图片加载常用功能

常用功能对应的接口 ILoadStrategy 的具体实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
/**
* 图片加载策略
*
* @author randy
* @date 2021/06/04 11:49 AM
*/
public interface ILoadStrategy {
/**
* 加载图片
*
* @param loadConfig 加载图片配置
* @param view 加载目标对象,ImageView or SimpleDraweeView
* @param callback 加载回调
* @param extendOption 额外配置接口
*/
void loadImage(LoadConfig loadConfig, View view, Callback callback,
ExtendedOptions extendOption);

/**
* 清除缓存
*
* @param type 清除类型
* {@link LoaderConst.CacheClearType#CLEAR_ALL_CACHE}
* {@link LoaderConst.CacheClearType#CLEAR_MEM_CACHE}
* {@link LoaderConst.CacheClearType#CLEAR_DISK_CACHE}
*/
void clearCache(int type);

/**
* 清除指定缓存
*
* @param type 清除类型
* {@link LoaderConst.CacheClearType#CLEAR_ALL_CACHE}
* {@link LoaderConst.CacheClearType#CLEAR_MEM_CACHE}
* {@link LoaderConst.CacheClearType#CLEAR_DISK_CACHE}
* @param loadConfig 加载图片配置
*/
void clearCacheKey(int type, LoadConfig loadConfig);

/**
* 是否已经缓存到本地
*
* @param loadConfig 加载图片配置
* @param extendedOption 额外配置接口
* @return Boolean 是否已经缓存到本地
*/
boolean isCache(LoadConfig loadConfig, ExtendedOptions extendedOption);

/**
* 获取本地缓存
*
* @param loadConfig 加载图片配置
* @param extendOption 额外配置接口
* @return File
*/
File getLocalCache(LoadConfig loadConfig, ExtendedOptions extendOption);

/**
* 获取本地缓存bitmap
*
* @param loadConfig 加载图片配置
* @param extendOption 额外配置接口
* @return Bitmap
*/
Bitmap getLocalCacheBitmap(LoadConfig loadConfig, ExtendedOptions extendOption);


/**
* 获取本地缓存大小
*
* @return Long
*/
long getCacheSize(LoadConfig loadConfig);


/**
* 下载图片
*
* @param loadConfig 加载图片配置
* @param callback 加载回调
* @param extendOption 额外配置接口
*/
void downloadOnly(LoadConfig loadConfig, Callback callback, ExtendedOptions extendOption);

/**
* 不同加载库可能支持的额外配置
*/
interface ExtendedOptions {
/**
* 不同的图片加载库 独有的一些配置
*
* @param option 配置对象
* Glide com.bumptech.glide.request.RequestOptions
* Picasso com.squareup.picasso.RequestCreator
* Fresco com.facebook.imagepipeline.request.ImageRequestBuilder
*/
void onOptionsInit(Object option);
}

/**
* 回调接口
*/
@UiThread
interface Callback {
void onStart();

void onSuccess(Object result);

void onFail(Exception error);
}
}

上面基本包含了每个图片加载框架都会有的常用功能,包括:

  • 图片加载,通过loadImage实现;

  • 缓存清除,通过clearCache实现;

  • 清除指定图片缓存,通过clearCacheKey实现;

  • 判断图片是否缓存,通过isCache实现;

  • 获取缓存文件,通过getLocalCache实现;

  • 获取缓存的Bitmap,通过getLocalCacheBitmap实现;

  • 获取缓存配置的大小,通过getCacheSize实现;

  • 图片下载,通过downloadOnly实现;

然后就是定义了一个接口 ExtendedOptions,它就是用来保留不通请求框架所独有的配置信息的,如果加载图片时,需要使用Glide特有的一些加载配置参数,就可将 Glide的请求配置对象RequestOptions 作为object参数传递到ExtendedOptions的onOptionsInit(Object object),然后在这个方法的实现中将具体的特殊加载配置设置进去。

LoadConfg 为通用配置参数类,可以将通用的加载配置写到这个LoadConfig中,然后各个框架分别取实现这个类,作为配置参数,这个类最好采用 建造者模式 来编写。

当然,上面只是定义了接口,具体的实现需要不通的图片加载框架具体实现,下面给出几个主流加载框架的 ILoadStrategy 实现。

Glide对应实现

Glide对应的ILoadStrategy 实现:GlideLoadStrategy

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
public class GlideLoadStrategy implements ILoadStrategy {

@Override
public void loadImage(LoadConfig loadConfig, View view, Callback callback, ExtendedOptions extendOption) {
if (!(view instanceof ImageView)) {
throw new IllegalArgumentException("view must be ImageView");
}

loadImage(loadConfig, extendOption)
.load(loadConfig.mUri)
.listener(new RequestListener<Drawable>() {
@Override
public boolean onLoadFailed(@Nullable GlideException e,
Object model,
Target<Drawable> target,
boolean isFirstResource) {
if (callback != null) {
callback.onFail(e);
}
return false;
}

@Override
public boolean onResourceReady(Drawable resource,
Object model,
Target<Drawable> target,
DataSource dataSource,
boolean isFirstResource) {
if (callback != null) {
callback.onSuccess(resource);
}
return false;
}
})
.into((ImageView) view);
}

@Override
public void clearCache(int type) {
if (type == LoaderConst.CacheClearType.CLEAR_DISK_CACHE) {
Glide.get(getContext()).clearDiskCache();
} else if (type == LoaderConst.CacheClearType.CLEAR_MEM_CACHE) {
Glide.get(getContext()).clearMemory();
} else {
Glide.get(getContext()).clearDiskCache();
Glide.get(getContext()).clearMemory();
}
}

@Override
public void clearCacheKey(int type, LoadConfig loadConfig) {
if (type == LoaderConst.CacheClearType.CLEAR_ALL_CACHE) {
clearDiskCacheKey(loadConfig);
clearMemCacheKey(loadConfig);
}
if (type == LoaderConst.CacheClearType.CLEAR_DISK_CACHE) {
clearDiskCacheKey(loadConfig);
}
if (type == LoaderConst.CacheClearType.CLEAR_MEM_CACHE) {
clearMemCacheKey(loadConfig);
}
}

/**
* 清除硬盘中的 key
*
* @param loadConfig 加载配置选项
*/
private void clearDiskCacheKey(LoadConfig loadConfig) {
DiskCache diskCache = DiskLruCacheWrapper.create(Glide.getPhotoCacheDir(getContext()),
loadConfig.mMaxDiskCacheSize);
GlideCacheKey key = new GlideCacheKey(loadConfig.mUri, EmptySignature.obtain());
diskCache.delete(key);
}

/**
* 清除内存中的 key
*/
private void clearMemCacheKey(LoadConfig loadConfig) {
GlideCacheKey memKey = new GlideCacheKey(loadConfig.mUri, EmptySignature.obtain());
MemoryCache cache = ReflectionHelper.INSTANCE.getField(Glide.get(getContext()), "memoryCache");
cache.remove(memKey);
}

@Override
public boolean isCache(LoadConfig loadConfig, ExtendedOptions extendedOption) {
return false;
}

@Override
public File getLocalCache(LoadConfig loadConfig, ExtendedOptions extendOption) {
return null;
}

@Override
public Bitmap getLocalCacheBitmap(LoadConfig loadConfig, ExtendedOptions extendOption) {
RequestBuilder<Bitmap> bitmapRequestBuilder = loadImage(loadConfig, extendOption).asBitmap().load(loadConfig.mUri);
try {
return bitmapRequestBuilder.submit().get();
} catch (ExecutionException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}

@Override
public long getCacheSize(LoadConfig loadConfig) {
DiskCache cache = DiskLruCacheWrapper.create(Glide.getPhotoCacheDir(getContext()),
loadConfig.mMaxDiskCacheSize);
DiskLruCache diskLruCache = ReflectionHelper.INSTANCE.getField(cache, "diskLruCache");
return diskLruCache.size();
}

@Override
public void downloadOnly(LoadConfig loadConfig, Callback callback, ExtendedOptions extendOption) {
loadImage(loadConfig, extendOption).downloadOnly().load(loadConfig.mUri).into(new GlideLoadTarget(callback));
}

/**
* 获取 Context
* todo 进行替换
*
* @return Context
*/
private Context getContext() {
return Utils.getApp();
}

private RequestManager loadImage(LoadConfig loadConfig, ExtendedOptions extendedOptions) {
return Glide.with(getContext().getApplicationContext())
.setDefaultRequestOptions(getRequestOptions(loadConfig, extendedOptions));
}

@SuppressLint("CheckResult")
private RequestOptions getRequestOptions(LoadConfig loadConfig, ExtendedOptions extendedOptions) {
RequestOptions requestOptions = new RequestOptions();
if (loadConfig.placeholderId > 0) {
requestOptions.placeholder(loadConfig.placeholderId);
}

if (loadConfig.errorId > 0) {
requestOptions.error(loadConfig.errorId);
}

if (loadConfig.isCircle) {
requestOptions.circleCrop();
}
if (loadConfig.mSize != null) {
requestOptions.override(loadConfig.mSize.x, loadConfig.mSize.y);
}
if (loadConfig.mTransformations != null && loadConfig.mTransformations.size() > 0) {
try {
requestOptions.transform((Transformation<Bitmap>) loadConfig.mTransformations);
} catch (Exception e) {
e.printStackTrace();
}
}
if (extendedOptions != null) {
extendedOptions.onOptionsInit(requestOptions);
}
return requestOptions;
}
}

Fresco对应实现

Fresco 对应的ILoadStrategy实现 FrescoLoadStrategy:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
public class FrescoLoadStrategy extends BaseFrescoLoadStrategy implements ILoadStrategy {

public FrescoLoadStrategy(ImagePipelineConfig config) {
if (config == null) {
config = ImagePipelineConfig.newBuilder(Utils.getApp())
.setDownsampleEnabled(true)
.build();
}
Fresco.initialize(Utils.getApp(), config);
}

@Override
public void loadImage(LoadConfig loadConfig, View view, Callback callback,
ExtendedOptions extendOption) {
if (!(view instanceof SimpleDraweeView)) {
throw new IllegalArgumentException("view must be SimpleDraweeView");
}

try {
SimpleDraweeView target = (SimpleDraweeView) view;
initFrescoView(target, loadConfig);
ImageRequest imageRequest = buildImageRequestWithResource(loadConfig, extendOption);
ImageRequest lowRequest = buildLowImageRequest(target, loadConfig, extendOption);
target.setController(buildDraweeController(target, loadConfig, callback, imageRequest,
lowRequest));
} catch (Exception e) {
e.printStackTrace();
}
}

@Override
public void clearCache(int type) {
if (type == LoaderConst.CacheClearType.CLEAR_ALL_CACHE) {
Fresco.getImagePipeline().clearCaches();
}
if (type == LoaderConst.CacheClearType.CLEAR_MEM_CACHE) {
Fresco.getImagePipeline().clearMemoryCaches();
}
if (type == LoaderConst.CacheClearType.CLEAR_DISK_CACHE) {
Fresco.getImagePipeline().clearDiskCaches();
}
}

@Override
public void clearCacheKey(int type, LoadConfig loadConfig) {
Uri loadUri = getUri(loadConfig.mUri);
if (type == LoaderConst.CacheClearType.CLEAR_ALL_CACHE) {
Fresco.getImagePipeline().evictFromCache(loadUri);
}
if (type == LoaderConst.CacheClearType.CLEAR_MEM_CACHE) {
Fresco.getImagePipeline().evictFromMemoryCache(loadUri);
}
if (type == LoaderConst.CacheClearType.CLEAR_DISK_CACHE) {
Fresco.getImagePipeline().evictFromDiskCache(loadUri);
}
}

@Override
public boolean isCache(LoadConfig loadConfig, ExtendedOptions extendedOption) {
return isCached(Utils.getApp(), loadConfig.mUri);
}

@Override
public File getLocalCache(LoadConfig loadConfig, ExtendedOptions extendOption) {
Uri loadUri = getUri(loadConfig.mUri);
if (!isCached(Utils.getApp(), loadUri)) {
return null;
}
ImageRequest imageRequest = ImageRequest.fromUri(loadUri);
CacheKey cacheKey = DefaultCacheKeyFactory.getInstance()
.getEncodedCacheKey(imageRequest, Utils.getApp());
BinaryResource resource = ImagePipelineFactory.getInstance()
.getMainFileCache().getResource(cacheKey);
if (resource instanceof FileBinaryResource) {
return ((FileBinaryResource) resource).getFile();
} else {
return null;
}
}

@Override
public Bitmap getLocalCacheBitmap(LoadConfig loadConfig, ExtendedOptions extendOption) {
Uri loadUri = getUri(loadConfig.mUri);
if (!isCached(Utils.getApp(), loadUri))
return null;
ImageRequest request = buildImageRequestWithResource(loadConfig, extendOption);
CacheKey cacheKey = DefaultCacheKeyFactory.getInstance()
.getBitmapCacheKey(request, Utils.getApp());
CloseableReference<CloseableImage> resource = ImagePipelineFactory.getInstance()
.getBitmapCountingMemoryCache().get(cacheKey);
if (resource != null && resource.get() instanceof CloseableBitmap) {
return ((CloseableBitmap) resource.get()).getUnderlyingBitmap();
} else {
return null;
}
}

@Override
public long getCacheSize(LoadConfig loadConfig) {
return ImagePipelineFactory.getInstance().getMainFileCache().getSize();
}

@Override
public void downloadOnly(LoadConfig loadConfig, Callback callback,
ExtendedOptions extendOption) {
ImageRequest imageRequest = buildImageRequestWithResource(loadConfig, extendOption);
ImagePipeline imagePipeline = Fresco.getImagePipeline();
DataSource<Void> dataSource = imagePipeline.prefetchToDiskCache(imageRequest,
Utils.getApp());
dataSource.subscribe(new BaseDataSubscriber<Void>() {

@Override
protected void onNewResultImpl(@NonNull DataSource<Void> dataSource) {
File file = getLocalCache(loadConfig, extendOption);
if (callback != null) {
callback.onSuccess(file);
}
}

@Override
protected void onFailureImpl(@NonNull DataSource<Void> dataSource) {
if (callback != null) {
callback.onFail(null);
}
}
}, CallerThreadExecutor.getInstance());
}

}

其中 BaseFrescoLoadStrategy 实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
public class BaseFrescoLoadStrategy {

boolean isCached(Context context, String uri) {
try {
return isCached(context, Uri.parse(uri));
} catch (Exception e) {
e.printStackTrace();
return false;
}
}

/**
* 是否缓存
*
* @param context caller context
* @param uri the load Uri
* @return true if had cached
*/
boolean isCached(Context context, Uri uri) {
ImagePipeline pipeline = Fresco.getImagePipeline();
DataSource<Boolean> dataSource = pipeline.isInDiskCache(uri);
if (dataSource == null) {
return false;
}
ImageRequest imageRequest = ImageRequest.fromUri(uri);
CacheKey cacheKey = DefaultCacheKeyFactory.getInstance()
.getEncodedCacheKey(imageRequest, context);
BinaryResource resource = ImagePipelineFactory.getInstance()
.getMainFileCache().getResource(cacheKey);
return resource != null && dataSource.getResult() != null && dataSource.getResult();
}

/**
* 获取要加载的 Uri
*
* @param targetUri 待加载的地址,可能是String,也可能是Uri
* @return 要加载的Uri
*/
Uri getUri(Object targetUri) {
Uri uri = null;
if (targetUri instanceof String) {
try {
uri = Uri.parse((String) targetUri);
} catch (Exception e) {
e.printStackTrace();
}
}
if (targetUri instanceof Uri) {
uri = (Uri) targetUri;
}

return uri;
}


/**
* 初始化要展示图像的View
*
* @param simpleDraweeView 展示图片的View
* @param loadConfig 加载配置
*/
void initFrescoView(SimpleDraweeView simpleDraweeView, LoadConfig loadConfig) {
if (loadConfig.placeholderId > 0) {
simpleDraweeView.getHierarchy().setPlaceholderImage(loadConfig.placeholderId);
}
if (loadConfig.errorId > 0) {
simpleDraweeView.getHierarchy().setFailureImage(loadConfig.errorId);
}
if (loadConfig.isCircle) {
setRoundingParams(simpleDraweeView, getRoundingParams(simpleDraweeView).setRoundAsCircle(true));
} else {
setRoundingParams(simpleDraweeView, getRoundingParams(simpleDraweeView).setRoundAsCircle(false));
}
}

ImageRequest buildImageRequestWithResource(LoadConfig loadConfig,
ILoadStrategy.ExtendedOptions extendedOptions) {
String remoteTarget = loadConfig.mUri;
ImageRequestBuilder builder;
// todo 增加不同显示方式的判断
Uri uri = Uri.parse(remoteTarget);
builder = ImageRequestBuilder.newBuilderWithSource(uri);

if (loadConfig.mSize != null && loadConfig.mSize.x > 0 && loadConfig.mSize.y > 0) {
ResizeOptions options = new ResizeOptions(loadConfig.mSize.x, loadConfig.mSize.y);
builder.setResizeOptions(options);
} else {
builder.setResizeOptions(null);
}
if (loadConfig.mTransformations != null && loadConfig.mTransformations.size() > 0) {
Object object = loadConfig.mTransformations.get(0);
if (object instanceof BasePostprocessor) {
builder.setPostprocessor((Postprocessor) object);
}
}
if (extendedOptions != null) {
extendedOptions.onOptionsInit(builder);
}
return builder.build();
}

ImageRequest buildLowImageRequest(SimpleDraweeView simpleDraweeView,
LoadConfig loadConfig,
ILoadStrategy.ExtendedOptions extendOption) {
/*String lowThumbnail = null
if (TextUtils.isEmpty(fresco.getLowThumbnailUrl())) {
return null
}
lowThumbnail = fresco.getLowThumbnailUrl()
val uri = Uri.parse(lowThumbnail)
return ImageRequest.fromUri(uri)*/
return null;
}

DraweeController buildDraweeController(SimpleDraweeView simpleDraweeView,
LoadConfig loadConfig,
ILoadStrategy.Callback callback,
ImageRequest imageRequest,
ImageRequest lowRequest) {
PipelineDraweeControllerBuilder builder = Fresco.newDraweeControllerBuilder();
builder.setImageRequest(imageRequest)
.setAutoPlayAnimations(loadConfig.isPlayGif)
//.setTapToRetryEnabled(fresco.getTapToRetryEnabled())
.setLowResImageRequest(lowRequest);
if (callback != null) {
builder.setControllerListener(new ControllerListener<ImageInfo>() {
@Override
public void onSubmit(String id, Object callerContext) {
callback.onStart();
}

@Override
public void onFinalImageSet(String id, @Nullable ImageInfo imageInfo,
@Nullable Animatable animatable) {
callback.onSuccess(new Exception(id));
}

@Override
public void onIntermediateImageSet(String id, @Nullable ImageInfo imageInfo) {
callback.onSuccess(new Exception(id));
}

@Override
public void onIntermediateImageFailed(String id, Throwable throwable) {
callback.onFail(new Exception(throwable));
}

@Override
public void onFailure(String id, Throwable throwable) {
callback.onFail(new Exception(throwable));
}

@Override
public void onRelease(String id) {

}
});
} else {
builder.setControllerListener(new BaseControllerListener<>());
}
builder.setOldController(simpleDraweeView.getController());
return builder.build();
}

RoundingParams getRoundingParams(SimpleDraweeView simpleDraweeView) {
RoundingParams roundingParams = simpleDraweeView.getHierarchy().getRoundingParams();
if (roundingParams == null) {
roundingParams = new RoundingParams();
}
return roundingParams;
}

void setRoundingParams(SimpleDraweeView simpleDraweeView, RoundingParams roundingParmas) {
simpleDraweeView.getHierarchy().setRoundingParams(roundingParmas);
}
}

Picasso对应实现

Picasso 对应的 ILoadStrategy 实现PicassoLoadStrategy:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
public class PicassoLoadStrategy implements ILoadStrategy {

private final Picasso mPicasso;

public PicassoLoadStrategy(Picasso.Builder builder) {
if (builder != null) {
mPicasso = builder.build();
} else {
mPicasso = Picasso.get();
}
}

@Override
public void loadImage(LoadConfig loadConfig, View view, Callback callback, ExtendedOptions extendOption) {
if (!(view instanceof ImageView)) {
throw new IllegalArgumentException("View must be ImageView");
}
RequestCreator requestCreator = getRequest(loadConfig, extendOption);
if (requestCreator != null) {
requestCreator.into((ImageView) view, new com.squareup.picasso.Callback() {
@Override
public void onSuccess() {
if (callback != null) {
callback.onSuccess(null);
}
}

@Override
public void onError(Exception e) {
if (callback != null) {
callback.onFail(e);
}
}
});
}

}

@Override
public void clearCache(int type) {
try {
Cache cache = ReflectionHelper.INSTANCE.getField(mPicasso, "cache");
cache.clear();
} catch (Exception e) {
e.printStackTrace();
}
}

@Override
public void clearCacheKey(int type, LoadConfig loadConfig) {
mPicasso.invalidate(loadConfig.mUri);
}

@Override
public boolean isCache(LoadConfig loadConfig, ExtendedOptions extendedOption) {
Log.e(getClass().getSimpleName(), "not support for picasso");
return false;
}

@Override
public File getLocalCache(LoadConfig loadConfig, ExtendedOptions extendOption) {
Log.e(getClass().getSimpleName(), "not support for picasso");
return null;
}

@Override
public Bitmap getLocalCacheBitmap(LoadConfig loadConfig, ExtendedOptions extendOption) {
Bitmap bitmap = null;
try {
bitmap = getRequest(loadConfig, extendOption) != null ? getRequest(loadConfig, extendOption).get() : null;
} catch (Exception e) {
e.printStackTrace();
}
return bitmap;
}

@Override
public long getCacheSize(LoadConfig loadConfig) {
return mPicasso.getSnapshot().size;
}

@Override
public void downloadOnly(LoadConfig loadConfig, Callback callback, ExtendedOptions extendOption) {
RequestCreator requestCreator = getRequest(loadConfig, extendOption);
if (requestCreator != null) {
requestCreator.into(new Target() {
@Override
public void onPrepareLoad(Drawable placeHolderDrawable) {
if (callback != null) {
callback.onStart();
}
}

@Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
if (callback != null) {
callback.onSuccess(bitmap);
}
}

@Override
public void onBitmapFailed(Exception e, Drawable errorDrawable) {
if (callback != null) {
callback.onFail(e);
}
}
});
}
}


private RequestCreator getRequest(LoadConfig loadConfig, ExtendedOptions extendedOptions) {
RequestCreator requestCreator = null;
requestCreator = mPicasso.load(loadConfig.mUri);

if (requestCreator != null) {
if (loadConfig.placeholderId > 0) {
requestCreator.placeholder(loadConfig.placeholderId);
}
if (loadConfig.errorId > 0) {
requestCreator.error(loadConfig.errorId);
}
if (loadConfig.isCircle) {
// todo
}
if (loadConfig.mSize != null) {
requestCreator.resize(loadConfig.mSize.x, loadConfig.mSize.y);
}
if (loadConfig.mTransformations != null && loadConfig.mTransformations.size() > 0) {
requestCreator.transform((Transformation) loadConfig.mTransformations);
}
if (extendedOptions != null) {
extendedOptions.onOptionsInit(requestCreator);
}
}

return requestCreator;
}
}

图片加载类

在不同图片加载对 ILoadStrategy的具体实现了之后,需要一个类来决定使用那个加载策略来进行图片的加载操作,这就是接下来这个ImageLoader的作用了,通过在构造这个 ImageLoader 实例时为其传递一个 ILoadStrategy 的具体实现类,或者通过调用setLoadStrategy方法来设置具体的 ILoadStrategy,简单的说,这个类知识 一个代理,具体的加载实现都是通过 其成员变量 ILoadStrategy 来决定的。类的具体实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
public class ImageLoader implements ILoadStrategy{
private final ILoadStrategy mLoadStrategy;

public ImageLoader(ILoadStrategy loadStrategy) {
mLoadStrategy = loadStrategy;
}

@Override
public void loadImage(LoadConfig loadConfig, View view, Callback callback, ExtendedOptions extendOption) {
mLoadStrategy.loadImage(loadConfig, view, callback, extendOption);
}

@Override
public void clearCache(int type) {
mLoadStrategy.clearCache(type);
}

@Override
public void clearCacheKey(int type, LoadConfig loadConfig) {
mLoadStrategy.clearCacheKey(type, loadConfig);
}

@Override
public boolean isCache(LoadConfig loadConfig, ExtendedOptions extendedOption) {
return mLoadStrategy.isCache(loadConfig, extendedOption);
}

@Override
public File getLocalCache(LoadConfig loadConfig, ExtendedOptions extendOption) {
return mLoadStrategy.getLocalCache(loadConfig, extendOption);
}

@Override
public Bitmap getLocalCacheBitmap(LoadConfig loadConfig, ExtendedOptions extendOption) {
return mLoadStrategy.getLocalCacheBitmap(loadConfig, extendOption);
}

@Override
public long getCacheSize(LoadConfig loadConfig) {
return mLoadStrategy.getCacheSize(loadConfig);
}

@Override
public void downloadOnly(LoadConfig loadConfig, Callback callback, ExtendedOptions extendOption) {
mLoadStrategy.downloadOnly(loadConfig, callback, extendOption);
}
}

到这,图片加载基本功能封装就完成了,调用者如果需要使用不通的图片加载框架,只需要在构造 ImageLoader 实例时传入不同的 ILoadStrategy 实现即可,但大多数情况下,一个App通常只需要使用一种 图片加载框架,所以最好创建一个管理类,用单例模式来进行管理,只创建一个 ImageLoader 实例,然后通过 setLoadStrategy 方法来设置具体的 ILoadStrategy 实现,这样,调用者只需要关心如何使用这个 ImageLoader 实例即可,而不需要关心具体的 ILoadStrategy 实现。

关于ILoadStrategy

由于最终干活的事 ILoadStrategy 的具体实现类,而这个类需要根据调用者传入的参数进行构造,这里利用简单工厂模式来构造,具体实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class LoaderStrategyFactory {
public static ILoadStrategy getLoadStrategy(@LoaderConst.LoaderType int type) {
switch (type) {
default:
case LoaderConst.LOADER_TYPE_FRESCO:
return new FrescoLoadStrategy(null);
case LoaderConst.LOADER_TYPE_PICASSO:
return new PicassoLoadStrategy(null);
case LoaderConst.LOADER_TYPE_GLIDE:
return new GlideLoadStrategy();
case LoaderConst.LOADER_TYPE_UIL:
return new UilLoadStrategy();
}
}
}

关于LoadConfig

这里的 LoadConfig值的是加载图片的配置,这个类分通用配置和不通框架的具体配置,通用配置在 Base里声明,不通加载库特有的配置在 具体的子类中说明,这样就在保持共性的同时,还兼顾了不通加载库的特性,关于类的具体实现这里就不贴代码了,由于配置项较多,就采用 建造者模式来完成具体 LoadConfig的构造了。

为了避免 每次都要创建 LoadConfig对象,可以创建几个常用的配置对象,缓存在内存中,如默认的配置,这样在 LoadConfig 为空时,可以直接采用 默认的。

总结

通过策略模式来完成具体加载策略的实现,通过建造者模式来完成不通加载配置的构建,通过单例模式来实现加载框架的管理和设置,通过工厂模式来完成 具体策略实例的创建,然后整个封装的基本思想就是 控制反转,尽量达到代码的高内聚低耦合,方便后续维护、扩展。

参考文章

Android 图片加载库如何封装

Android 通用功能封装1——通用工具类封装

发表于 2021-02-02 | 分类于 Android , 通用功能

http://rainmonth.github.io/posts/A210202.html

  • [ ] Android通用功能封装0——开篇
  • [ ] Android通用功能封装1——通用工具类封装
  • [ ] Android 通用功能封装2——图片加载
  • [ ] Android 通用功能封装3——文件选择
  • [ ] Android 通用功能封装4——文件下载
  • [ ] Android 通用功能封装5——网络库封装
  • [ ] Android 通用功能封装6——数据库封装
  • [ ] Android 通用功能封装7——广播管理

简介

主要完成Android开发过程中常用操作的封装,避免重复造轮子,达到便捷快速开发,提高开发效率的目的。

功能介绍

使用说明

总结

Android 通用功能封装——开篇

发表于 2021-02-01 | 分类于 Android , 通用功能

http://rainmonth.github.io/posts/A210201.html

简介

Android开发这么多年,总觉得要积累点什么,这不,不管是从网上搜到的,还是自己开发过程中积累的,讲开发一个Android App常用的功能都进行封装下,既能提升自己代码封装的功力,又能形成知识的沉淀,所以写写这些还是不错的。

阅读全文 »
<i class="fa fa-angle-left" aria-label="上一页"></i>1…111213…22<i class="fa fa-angle-right" aria-label="下一页"></i>

216 日志
43 分类
43 标签
GitHub
© 2025 Randy Zhang
由 Hexo 强力驱动
|
主题 — NexT.Gemini v6.1.0