0%

最近通过网课,了解到一种十分巧妙的fragment的封装以及调度方式。遂记录下理解

Fragment的封装

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
public abstract class Fragment extends android.support.v4.app.Fragment {
//便于复用
protected View mRoot;
protected Unbinder mRootUnBinder;
/**
* 当一个fragment被添加到一个acitvity中,最首先被调用的方法
* context即为activity
*/
@Override
public void onAttach(Context context) {
super.onAttach(context);
//初始化参数
initArgs(getArguments());
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {

if(mRoot == null) {
int layId = getContentLayoutId();
// 初始化当前根布局,但不在创建时就添加到container中去(return root后方法内部调度自动添加到container中去)
View root = inflater.inflate(layId, container, false);
initWidget(root);
mRoot = root;
}else{
// 父布局不等于空,则把当前root从其父控件中移除
if(mRoot.getParent() != null){
((ViewGroup)mRoot.getParent()).removeView(mRoot);
}
}
return mRoot;
}
/**
* 判断是否获取到数据
*/
protected void initArgs(Bundle bundle){}

// 当view界面初始化创建完成以后
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
initData();
}
/**
* 获取当前界面的资源文件id
* @return 资源文件id
*/
protected abstract int getContentLayoutId();

protected void initWidget(View root){
mRootUnBinder = ButterKnife.bind(this, root);
}

protected void initData(){}

/**
* 返回按键触发时调用
* @return 返回true代表我已处理返回逻辑,activity不用自己finish
* 返回flase代表未处理逻辑(不拦截),activity自己处理逻辑
*/
public boolean onBackPressed(){
return false;
}
}
阅读全文 »

解决linux文件系统变成只读

背景

今天进入Deepin,如往常一般打开Android Studio。突然弹出提示框,说是log而文件夹有问题。还以为是as的问题,后来才发现,是文件夹变成只读的了无法操作。

解析

Google后发现原来是挂载分区出了问题。这种问题有时候可以用重启解决。但我重启无果,另寻他法。
运行mount,查看分区结构

阅读全文 »

JAVA WEB网络编程

Socket套接字

  • socket使用TCP实现计算机间的通信机制。client创建一个socket,并尝试连接服务器的socket。
  • 客户与服务端可以使用对Socket的读写来实现通信。

    ServerSocket类为服务器提供一种监听客户端并建立连接的机制。
    具体实现:

    1. Server端实例化一个ServerSocket,表示通过服务器上的端口通信。
    2. ServerSocket.accept()方法将一直等待直到客户端连接上服务器的端口
    3. Client端实例化Socket,指定服务器地址与端口号请求连接。
    4. Socket的构造函数尝试连接。通信被建立后,则可通过Socket通信,否则抛出IOException
    5. Server端accept()返回一个scoket引用,该socket连接到Client的Socket
      阅读全文 »

RecyclerView常用的一种封装方式

本文介绍一种RecyclerView的常用封装形式,最后效果是调用时只需定义回调方法getItemViewType()与onCreateViewHolder(View, int)
因为在使用时一般会有特殊的item填充的需求,以及不同使用场景会使用不同的ViewHolder进行填充的需求。
先上代码…

具体代码

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
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
public abstract class RecyclerAdapter<T> extends RecyclerView.Adapter<RecyclerAdapter.ViewHolder<T>> implements View.OnClickListener, AdapterCallBack<T> {
private final List<T> list;

private AdapterListener<T> mListener;

/**
* 构造模块
* ------------------------------------------------------------------
*
* @param dataList
* @param listener
*/
public RecyclerAdapter(List<T> dataList, AdapterListener<T> listener) {
this.mListener = listener;
this.list = dataList;
}

public RecyclerAdapter() {
this(null);
}

public RecyclerAdapter(AdapterListener<T> listener) {
this(new ArrayList<T>(), listener);
}

/**
* ViewId获取模块
* ------------------------------------------------------------------
* 复写默认布局返回
*
* @param position 坐标
* @return 返回布局id
*/
@Override
public int getItemViewType(int position) {
return getItemViewType(position, list.get(position));
}

/**
* 获取布局类型(id)
*
* @param position 坐标
* @param data 当前数据
* @return 布局id,用于创建ViewHolder
*/
protected abstract int getItemViewType(int position, T data);

/**
* ViewHolder创建模块
* ------------------------------------------------------------------
* 创建一个ViewHolder
*
* @param parent
* @param viewType Item的类型,约定为XML的id(简化操作)
* @return ViewHolder
*/
@Override
public ViewHolder<T> onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());

// 将一个xml id为ViewType的文件初始化为一个root View
View root = inflater.inflate(viewType, parent, false);
// 通过子类必须实现的方法得到一个ViewHolder
ViewHolder<T> holder = onCreateViewHolder(root, viewType);
// 对Holder的事件操作实际上是对view进行操作。对一个ViewHolder设置事件实际上还是对其根布局设置

//设置View的Tag为Holder进行双向绑定
root.setTag(R.id.tag_recycler_holder, holder);
// 设置事件点击
root.setOnClickListener(this);

// 进行界面注解绑定
holder.unBinder = ButterKnife.bind(holder, root);

// 绑定callback
holder.callBack = this;
return holder;
}

/**
* 当得到一个新的ViewHolder
*
* @param parent 根布局
* @param viewType 布局类型,即xml的id
* @return ViewHolder
*/
public abstract ViewHolder<T> onCreateViewHolder(View parent, int viewType);

/**
* Holder数据绑定模块
* ------------------------------------------------------------------
* @param holder
* @param position
*/
@Override
public void onBindViewHolder(ViewHolder<T> holder, int position) {
// 得到需要绑定的方法
T data = list.get(position);
// 触发Holder的绑定方法
holder.bind(data);
}

@Override
public int getItemCount() {
return list.size();
}


/**
* 操作数据列表模块
* ------------------------------------------------------------------
*/
private void add(T data) {
list.add(data);
notifyItemInserted(list.size() - 1);
}

/**
* 插入一堆数据并通知这段集合更新
*
* @param datalist data
*/
public void add(T... datalist) {
if (datalist != null && datalist.length > 0) {
int startPos = list.size();
Collections.addAll(list, datalist);
notifyItemRangeInserted(startPos, datalist.length);
}
}

/**
* 插入一堆数据并通知这段集合更新
*
* @param datalist data
*/
public void add(Collection<T> datalist) {
if (datalist != null && datalist.size() > 0) {
int startPos = list.size();
list.addAll(datalist);
notifyItemRangeInserted(startPos, datalist.size());
}
}

/**
* 删除操作
*/
public void clear() {
list.clear();
notifyDataSetChanged();
}

/**
* 替换为一个新的集合
*
* @param dataList 新集合
*/
public void replace(Collection<T> dataList) {
list.clear();
if (dataList == null || dataList.size() == 0)
return;
list.addAll(dataList);
// 全部更新
notifyDataSetChanged();
}


/**
* 点击设置及监听模块
* ------------------------------------------------------------------
*/
@Override
public void onClick(View v) {
ViewHolder holder = (ViewHolder) v.getTag(R.id.tag_recycler_holder);
if (this.mListener != null) {
// 得到ViewHolder当前对应适配器中的坐标
int pos = holder.getAdapterPosition();
// 回调
this.mListener.onItemClick(holder, list.get(pos));
}
}

/**
* 设置适配器点击监听
*
* @param adapterListener
*/
public void setListener(AdapterListener<T> adapterListener) {
this.mListener = adapterListener;
}

public interface AdapterListener<T> {
// 当cell点击时触发
void onItemClick(RecyclerAdapter.ViewHolder holder, T data);

void onItemLongClick(RecyclerAdapter.ViewHolder holder, T data);
}

/**
* 加上abstract使子类实现时至少实现其中一个方法
* 抽象方法不需要子类实现所有抽象方法,而接口要求实现所有方法
*/
public abstract static class AdapterListenerImpl<T> implements AdapterListener<T> {
@Override
public void onItemClick(ViewHolder holder, T data) {}

@Override
public void onItemLongClick(ViewHolder holder, T data) {}
}

/**
* ViewHolder的封装类
* 使用时需继承该类并实现onBind()方法完成控件与数据的绑定
* ------------------------------------------------------------------
*/
public static abstract class ViewHolder<T> extends RecyclerView.ViewHolder {
private Unbinder unBinder;

private AdapterCallBack<T> callBack;
protected T data;

public ViewHolder(View v) {
super(v);
}

/**
* 用于绑定数据的触发
* @param data 数据
*/
void bind(T data) {
this.data = data;
onBind(data);
}

/**
* 通知整个列表更新的消息
* 通过ViewHolder反向调用此方法进行更新
* Holder自己对自己对应的data进行更新的
*
* @param data
*/
public void updataData(T data) {
if (this.callBack != null) {
this.callBack.updata(data, this);
}
}

/**
* 触发帮顶数据时的回调。必须复写
* 界面刷新赋值
* @param data 绑定的数据
*/
protected abstract void onBind(T data);
}
}

以上代码看着有点多,因此分为几个模块,分开理解就都很简单了。

代码分析

其实注释已经写得很清楚了但还是具体分析一下。

构造模块

  • 传入AdapterListener监听器实例

ViewType模块

  • getItemViewType() 复写默认布局返回,布局id用于创建ViewHolder,返回调用同名抽象方法(不同参)

创建ViewHolder模块

  • onCreateViewHolder 创建一个ViewHolder
    • 调用类内定义的同名抽象方法onCreateViewHolder()获取holder,参数为View而不是ViewGroup
    • View与Holder进行双向绑定(两种实现方式)
      • view.setTag()实现(key为一个特定id)
      • Butterknife.bind()实现,并将返回的UnBinder保存在Holder中备用

数据绑定模块

  • onBindViewHolder
    • 触发 Holder.bind() 方法(有点会回调的意思)

点击响应以及监听模块

  • AdapterListener 点击监听接口
    • 由onClick()方法回调接口方法
    • 增加一个接口实现类,就可以只实现接口中的其中一个方法,而不需要全部实现

ViewHolder抽象类模块

  • ViewHolder 内部类定义
    • 以前的写法是在构造方法中绑定控件,但是这里是定义了一个bind(T)进行绑定
      • bind()中调用abstract onBind()方法
    • 需要通知整个列表更新的消息,定义方法updataData()
      • updataData方法回调了AdapterCallBack(外部定义)。

数据操作模块

  • add() & clear() & replace() & 以及必须实现的 getItemCount()
    • 对数据源进行修改,注意刷新列表更新

对RecyclerView使用的一种常用封装,为了开发是能够便捷简明的调用而又不影响其复用。

以上是对这种封装形式的学习理解和分析,理解有所偏差或其他看法欢迎大佬交流,共同进步~

相信对于不少像我这样的“强迫症”一样的安卓开发者来说,面对安装Android Studio之后日渐臃肿的C盘肯定无法接受。下面给出这些天重装AS以后,查阅总结的C盘瘦身大法(只针对Android Studio)。

阅读全文 »

好像很是奇怪,学了半年多的Java,到今天还写这么一篇关于安装Java的博客。因为最近重装系统,从头开始配置Java,所以发现了一些问题和收获。。
开始学习Java的时候,遇到的第一个拦路虎就是Java的环境变量配置,因为Java的一次编写,到处运行的特性,它需要在虚拟机上运行,为了在任意文件处可以使用Java,就有了环境变量配置的问题。但我当时安装的时候一切顺畅,并没有遇到麻烦,但后来总是在帮小伙伴安装的时候出现差错。当我重装完系统时安装java,竟也遇到问题。查阅博客得以解决以后,决定自己写一篇指南纪念(祭奠)一下。

阅读全文 »

引入:

其实这是前几天一直困扰我的问题,design中只有一个界面而没有任何控件,连标题栏都没有。
csdn上有人说把systle里边改为Base.Theme,改完控件可以显示了,但是仍然没有标题栏,我知道这一定不是问题根源。本来已经放弃了。
design问题描述但是今天有了些转机。

阅读全文 »

今天又是写了一个下午的bug。
这一次是要用Fragment实现如下界面,并且还要同时兼容手机和平板。抽象逻辑实在复杂(其实还好,只是我发现自己写的和书里的不同然后被吓回去了),我这样的菜狗挣扎了一会,还是得照着书敲了,确实有很多需要我学习的东西,所以这回就直接放代码,学习一下大佬的代码和逻辑。

阅读全文 »