0%

前言

对于资讯阅读类app的来说,夜间模式是必不可少的。本文提供一种不重启Activity实现动态切换主题的方案。

阅读全文 »

分析

从Adapter.getView方法入手, 找到了 AbsListView.obtainView,

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
  /**
* Get a view and have it show the data associated with the specified
* position. This is called when we have already discovered that the view is
* not available for reuse in the recycle bin. The only choices left are
* converting an old view or making a new one.
*
* @param position The position to display
* @param isScrap Array of at least 1 boolean, the first entry will become true if
* the returned view was taken from the scrap heap, false if otherwise.
*
* @return A view displaying the data associated with the specified position
*/
View obtainView(int position, boolean[] isScrap) {
isScrap[0] = false;
// Check whether we have a transient state view. Attempt to re-bind the
// data and discard the view if we fail.
final View transientView = mRecycler.getTransientStateView(position);
if (transientView != null) {
final LayoutParams params = (LayoutParams) transientView.getLayoutParams();
// If the view type hasn't changed, attempt to re-bind the data.
if (params.viewType == mAdapter.getItemViewType(position)) {
final View updatedView = mAdapter.getView(position, transientView, this);
// If we failed to re-bind the data, scrap the obtained view.
if (updatedView != transientView) {
setItemViewLayoutParams(updatedView, position);
mRecycler.addScrapView(updatedView, position);
}
}
isScrap[0] = true;
// Finish the temporary detach started in addScrapView().
transientView.dispatchFinishTemporaryDetach();
return transientView;
}
final View scrapView = mRecycler.getScrapView(position);
final View child = mAdapter.getView(position, scrapView, this);
if (scrapView != null) {
if (child != scrapView) {
// Failed to re-bind the data, return scrap to the heap.
mRecycler.addScrapView(scrapView, position);
} else {
isScrap[0] = true;
// Finish the temporary detach started in addScrapView().
child.dispatchFinishTemporaryDetach();
}
}
...... // 省略部分代码

return child;
}

我们把目光放在mRecycler上,其实就是一个RecyclerBin对象,负责缓存View对象,这是ListView复用机制的精华所在,有必要好好刨析这个类. RecyclerBin中各个变量的定义如下:

//回收Listener,当View变为可回收,即ScrapView时,会通过mRecyclerListener通知注册者,listener可通过setRecyclerListener注册

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
private RecyclerListener mRecyclerListener;
/**
* The position of the first view stored in mActiveViews.
*/
// 第一个活动view的position,即第一个可视view的position
private int mFirstActivePosition;
/**
* Views that were on screen at the start of layout. This array is populated at the start of
* layout, and at the end of layout all view in mActiveViews are moved to mScrapViews.
* Views in mActiveViews represent a contiguous range of Views, with position of the first
* view store in mFirstActivePosition.
*/
// 活动view的集合
private View[] mActiveViews = new View[0];
/**
* Unsorted views that can be used by the adapter as a convert view.
*/
/**废弃的可修复view集合,复用时传递到Adapter#getView方法的convertView参数。
* 因为item type可能大于1,只有view type相同的view之间才能复用,所以是个二维数组
*/
private ArrayList<View>[] mScrapViews;
// ListView item type数量
private int mViewTypeCount;
// 当前的废弃view数组,定义这个成员是为了在mViewTypeCount为1时使用方便,不需要去取mScrapViews的第一个元素
private ArrayList<View> mCurrentScrap;
// 被跳过的,不能复用的view集合。view type小于0或者处理transient状态的view不能被复用。
private ArrayList<View> mSkippedScrap;
// 处于 transient状态的view集合,处于transient状态的view不能被复用,如view的动画正在播放,
// transient是瞬时、过渡的意思,关于transient状态详见android.view.View#PFLAG2_HAS_TRANSIENT_STATE
private SparseArray<View> mTransientStateViews;
// 如果adapter的hasStableIds方法返回true,处于过度状态的view保存到这里。因为需要保存view的position,而且处于过度状态的view一般很少,
// 这2个成员用了稀疏数组。具体不需要case,知道是保存转换状态view的集合就行。
private LongSparseArray<View> mTransientStateViewsById;

参考

前言

2016转眼就过去了,工作以后开始感叹时间飞逝。在2016的最后一天,总结一下这一年的得与失,也算是对自己有个交代吧。

阅读全文 »

前言

不知道大家用过网易新闻没?点击进入到专题中,就有可能出现如下图所示的导航栏,点击任意一个导航块,就会自动跳转到相应的地方,这是怎么实现的呢?

阅读全文 »

前言

周五和同事吃饭,聊着聊着就谈到了一个问题:是一个产品经理重要还是一个程序员重要?当时我的回答是两者都同样重要,理由是一个坏的产品经理会毁了一个好产品,一个坏的程序员会写低级bug,造成用户体验差,一个满是bug的app也不会有用户去使用。不过现在我倒觉得,产品经理的重要性要大过于程序员,如果招了一个不合格的产品经理,识别不出那些是用户真正的需求,那些是伪需求,任由其乱搞一通,被竞争对手干死。而如果招了一个不合格的程序员,在流程规范化的大公司中,程序员写的代码都会经过严格的测试,因此,程序的质量是有保证的。当然这个问题,仁者见仁,智者见智。

阅读全文 »

前言

关于RemoteViews,官方是这么定义的:

A class that describes a view hierarchy that can be displayed in
another process. The hierarchy is inflated from a layout resource
file, and this class provides some basic operations for modifying the
content of the inflated hierarchy.

简单来说就是一个可以提供在其他进程中的展示、修改View的类。从类的定义上看,RemoteViews是直接继承Object而不是View,因此它不能像普通View一样提供setOnClickListener(有替代方案)、setEnable()等操作。在实际开发中,主要用在展示notification和widget。

阅读全文 »