android简单的轮询与计数功能
在android项目中经常会遇到要编写一个普通的计数器或者一个网络请求轮询功能,实在是不想重复的去造轮子, 今天我将这两个功能做一个归集。
首先需要准备一个网络请求框架,我选择的是OKGo,因为它比较轻量,还简单易懂,大家也可以选择其他的网络请求框架。 代码直接copy可用。
引入 implementation ‘com.lzy.net:okgo:2.1.4’
好, 我们先来编写一个请求接口GetDataListener
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
26package com.example.poll.model; import org.json.JSONException; /** * Created by gongjiebin on 2018/11/14. */ public interface GetDataListener { void success(Object data) throws JSONException; void fail(String error); /** * 进度条 * @param currentSize * @param totalSize * @param progress * @param networkSpeed */ void upProgress(long currentSize, long totalSize, float progress, long networkSpeed); }
请求接口INetWork定义
一般就定义几个请求的关键方法与存放请求的地址。如果你需要用到别的请求框架, 或者是自己编写的网络请求,请继承INetWork接口,实现其中的方法。 在应用-Test,test3()方法中有使用实例,文章的最后有讲。
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
32package com.example.poll.model; import java.util.Map; /** * Created by gongjiebin on 2018/11/14. */ public interface INetWork { /** * 绑定设备 */ String poll = "/proxy/pos/open/binding"; // 网络请求(非文件) void getNewWorkData(Map<String, String> kv, GetDataListener listener, String path); /** * 轮询的接口 * @param kv * @param listener * @param path */ void pollNewWorkData(Map<String, String> kv, GetDataListener listener, String path); void setTimeOut(long time); }
进入请求实现类NetWork
对了, 这个就是利用okgo实现网络请求的类,不多做解释,大家可以去某度某歌找找看。
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
91package com.example.poll.model; import android.util.Log; import com.lzy.okgo.OkGo; import com.lzy.okgo.callback.StringCallback; import com.lzy.okgo.request.BaseRequest; import org.json.JSONException; import java.util.Iterator; import java.util.Map; import java.util.Set; import okhttp3.Call; import okhttp3.Response; /** * Created by gongjiebin on 2018/11/14. */ public class NetWork implements INetWork { private boolean isDebug = true; // false 正式环境 //public static String API_BASE_URL = "https://app.yeekaa.com"; private long timeOut; public void setTimeOut(long timeOut) { this.timeOut = timeOut; } @Override public void getNewWorkData(Map<String, String> map, final GetDataListener listener, String path) { //this.getNetWorkInfo(map, listener, path); } @Override public void pollNewWorkData(final Map<String, String> map, final GetDataListener listener, final String path) { BaseRequest go = OkGo.post(path).tag(this);//.isMultipart(true);// // 强制使用 multipart/form-data 表单上传(只是演示,不需要的话不要设置。默认就是false) Set set = map.entrySet();/// 返回此映射所包含的映射关系的 Set 视图。 Iterator iterator = set.iterator(); while (iterator.hasNext()) { Map.Entry mapentry = (Map.Entry) iterator.next(); /Map.Entry--Map的内部类,描述Map中的按键/数值对。 Log.e("Post" + path, mapentry.getKey() + "----" + mapentry.getValue()); go.params((String) mapentry.getKey(), (String) mapentry.getValue()); // } if(timeOut==0)timeOut = 15000l; // 不设置,默认15s超时时间 go.connTimeOut(timeOut).readTimeOut(timeOut).execute(new StringCallback() { @Override public void onSuccess(String s, Call call, Response response) { //上传成功 Log.e("TAG", s); try { if(listener!= null)listener.success(s); } catch (JSONException e) { e.printStackTrace(); } } @Override public void upProgress(long currentSize, long totalSize, float progress, long networkSpeed) { //这里回调上传进度(该回调在主线程,可以直接更新ui) Log.e("TAG", "currentSizet" + currentSize + "totalSizet" + totalSize + "progresst" + progress + "networkSpeedt" + networkSpeed); //(100 * currentSize) / totalSize if (listener != null)listener.upProgress(currentSize, totalSize, progress, networkSpeed); } @Override public void onAfter(String s, Exception e) { super.onAfter(s, e); } @Override public void onError(Call call, Response response, Exception e) { super.onError(call, response, e); if (listener != null) listener.fail(e.toString()); } }); } }
接下来实现轮询的方法。 代码中都有详细的解释,请看PollingDataNumber类
PollingDataNumber封装了网络请求返回的数据,记录了轮询的次数,大家也可以对其进行相应的扩展,来看代码。
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
31package com.example.poll.model; public class PollingDataNumber<T> { /** * 计数器 */ private long number; /* 需要传递的参数 */ private T o; public void setNumber(long number) { this.number = number; } public long getNumber() { return number; } public void setO(T o) { this.o = o; } public Object getO() { return o; } }
最主要的功能实现类Polling类。
Polling类主要实现了计数器和轮询的功能,我们采用链式调用的方式来设定参数,我们在调用的时候就一句代码,只要参数设置正确,就能跑起来。看代码
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
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353package com.example.poll.model; import android.os.Handler; import android.os.HandlerThread; import android.os.Looper; import android.os.Message; import java.util.Map; /** * @author gongjiebin * 轮询 -- 在线程中执行, 不影响UI操作 * <p> * 也可以当一个计数器, 只要isNumber 为true 就会以设置的时间间隔心跳回复, */ public class Polling<T extends PollingDataNumber, K extends INetWork> implements GetDataListener { private OnPollingInterfase onPollingInterfase; /** * 结束此线程的标识 */ private boolean isStart; /** * 地址。 */ private String path; /** * 需要向后台服务器传递的值 */ private Map<String, String> values; /** * 是否只是当一个计数器使用 true是, * <p> * 需要前提需要设定time 、设置回调监听 */ private boolean isNumber; /** * 间隔多长时间轮询一次(ms) */ private long time; // 开始时间(当这个) private long startTime; public Polling setStartTime(long startTime) { this.startTime = startTime; return this; } /** * 计数器(isNumber = true) * <p> * 如果当前执行的是计数功能,会以用户设定的时间累加1 */ private long counter; /** * */ private MyHandler handler; // private Timer timer; // private TexTimerTask task; /** * 网络请求帮助类 */ private K netWork; private T pollingts; public Polling setNetWork(K netWork) { this.netWork = netWork; return this; } public Polling() { HandlerThread thread = new HandlerThread("sms-thread"); thread.start(); handler = new MyHandler(thread.getLooper()); } /** * 重置计数器 */ public Polling resetCounter() { counter = 0; return this; } /** * 提供初始化调用 * * @param onPollingInterfase * @param time * @param path * @param mapValues */ public Polling(OnPollingInterfase onPollingInterfase, long time, String path, Map<String, String> mapValues) { //handler = new Handler(); this.values = mapValues; this.onPollingInterfase = onPollingInterfase; this.time = time; this.path = path; } /** * @param values * @return */ public Polling setValues(Map<String, String> values) { this.values = values; return this; } public Map<String, String> getValues() { return values; } /** * 当此参数为true , 本类就是一个计数器。 * * @param isNumber * @return */ public Polling setIsNumber(boolean isNumber) { this.isNumber = isNumber; return this; } /** * 获取循环间隔时间 * * @return */ public long getTime() { return time; } /** * 采用链式调用。 * * @param onPollingInterfase * @return */ public Polling setOnPollingInterfase(OnPollingInterfase onPollingInterfase) { this.onPollingInterfase = onPollingInterfase; return this; } /** * 设置IP与端口 * * @param ip * @param port * @return */ @Deprecated public Polling setIpPort(String ip, int port) { //setPaht(ip+":"+port+NetWork.heartbeat); return this; } /** * 间隔时长 * * @param time * @return */ public Polling setTime(long time) { this.time = time; return this; } /** * 设置请求路径 * * @param paht * @return */ public Polling setPath(String paht) { this.path = paht; return this; } /* 停止线程,不在向外抛数据 */ public Polling setStop() { this.isStart = false; // 移除心跳循环 // handler.removeCallbacks(runnable);; cancel(); return this; } /** * 清除定时器 */ public void cancel() { // handler.removeCallbacks(); // handler.removeCallbacks(); // if (task != null && timer != null) { // // 清除定时 // task.cancel(); //取消当前任务,并将其从队列中移出 // timer.purge(); //从队列中移出已被取消的Task,使他们能被当做垃圾被回收掉 // timer.cancel(); // timer = null; // task = null; // } } public Polling setStart() { this.isStart = true; return this; } /** * 得到当前线程运行状态 * * @return */ public boolean isStart() { return isStart; } /** * 开启计时器 */ public void run() { // 规定一段时间运行一次 // if(timer == null || task == null){ // timer = new Timer(false); // task = new TexTimerTask(); // } // // // 未设置开始时间时, // if(startTime == 0)startTime = time; // timer.schedule(task,startTime,time); handler.sendEmptyMessageDelayed(1, time); } public class MyHandler extends Handler { public MyHandler(Looper looper) { super(looper); } @Override public void handleMessage(Message msg) { switch (msg.what) { case 1: if (Polling.this.isStart) { if (!isNumber) { if (time >= 5000) { getNData(); } else { setStop(); // 访问被拒绝 onPollingInterfase.error("请求时间间隔不能低于5秒"); } } else { pollingts = (T) new PollingDataNumber(); pollingts.setNumber(counter++); onPollingInterfase.onData(pollingts, Polling.this); } handler.sendEmptyMessageDelayed(1, time); } break; } super.handleMessage(msg); } } /** * 获取网络数据 */ private void getNData() { netWork.pollNewWorkData(values, this, path); } @Override public void success(Object data) { if (onPollingInterfase != null) { counter++; pollingts = (T) new PollingDataNumber(); pollingts.setNumber(counter); pollingts.setO(data); onPollingInterfase.onData(pollingts, this); } } // // public class TexTimerTask extends TimerTask { // @Override // public void run() { // // } // } @Override public void fail(String error) { // 停止轮询 if (onPollingInterfase != null) { onPollingInterfase.error(error); } } @Override public void upProgress(long currentSize, long totalSize, float progress, long networkSpeed) { } /** * 得到的数据将通过此接口传递给调用类 */ public interface OnPollingInterfase<T extends PollingDataNumber> extends Ifather { /** * 发送数据 */ void onData(T t, Polling polling); } public interface Ifather{ void error(String error); } }
应用-Test
好啦, 基本上主要功能都实现了, 接下来看整么调用, 请看代码。
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
126package com.example.poll; import androidx.appcompat.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import com.example.poll.model.INetWork; import com.example.poll.model.NetWork; import com.example.poll.model.Polling; import com.example.poll.model.PollingDataNumber; import java.util.HashMap; import java.util.Map; public class MainActivity extends AppCompatActivity implements Polling.OnPollingInterfase { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); test3(); } /** * 第一种使用方式, polling只是一个简单的计数器, 不会去请求网络做轮询 */ public void test1() { new Polling<>().setIsNumber(true).setTime(5000).setOnPollingInterfase(this).setStart().run(); } /** * 第二种方式,计数器变成了轮询接口。 */ public void test2() { Map<String, String> valueMap = new HashMap<>(); valueMap.put("serialNumber", "35694508004311660800004203"); // 在主线程创建 Polling polling = new Polling<>() // 设置轮询时间, 不能低于5s,不能高于网络超时时间 .setTime(6000) // 设置网络自己的网络请求类 实现于INetWork接口 .setNetWork(new NetWork()) // 设置请求地址, 设置成自己的地址 .setPath("https://app.yeekaa.com/proxy/pos/heartbeat") // 如果请求有携带参数,请调用setValues方法。 .setValues(valueMap) // 设置轮询监听器, 网路请求会在PollingDataNumber 的 T中携带返回。 .setOnPollingInterfase(this) .setStart(); polling.run(); } /** * 第二种方式,计数器变成了轮询接口。 */ public void test3() { Map<String, String> valueMap = new HashMap<>(); valueMap.put("serialNumber", "35694508004311660800004203"); INetWork iNetWork = new NetWork(); // 在主线程创建 new Polling<>() // 设置轮询时间, 不能低于5s,不能高于网络超时时间 .setTime(6000) // 设置网络自己的网络请求类 实现于INetWork接口 .setNetWork(new NetWork()) // 设置请求地址, 设置成自己的请求地址 .setPath("https://app.yeekaa.com/proxy/pos/heartbeat") // 如果请求有携带参数,请调用setValues方法。 .setValues(valueMap) // 设置轮询监听器, 网路请求会在PollingDataNumber 的 泛型T 中携带返回。 .setOnPollingInterfase(this) // 打开轮询开关 .setStart() // 开始轮询 .run(); } @Override public void onData(PollingDataNumber pollingDataNumber, Polling polling) { Log.e("Post", "轮询被调用" + pollingDataNumber.getNumber() + "次"); /** * 请求携带回来的参数 */ Object o = pollingDataNumber.getO(); if (o != null) { Log.e("Post参数", o.toString()); } if (pollingDataNumber.getNumber() == 3) { Log.e("Post", "轮询停止啦"); polling.setStop(); //调用这句代码, 停止轮询 // 判断轮询是否停止的方法。 boolean isStop = polling.isStart(); } // 如果需要中途更换请求参数, 请这样做 //Map<String,String> map = polling.getValues(); // map.clear(); // 可清除原来的参数 // map.put("参数1","000004"); // map.put("参数2","000005"); } @Override public void error(String error) { } }
好了, 代码是原创的,都应用在项目里面了。 如果有用的着的同学们可以copy下来试试看。 这些都是小功能,只是我不想每个项目都去写一遍,为难。 android中有自带Timer计时器,也可以实现计时功能,这里我选择了Handler + HandlerThread的方式来实现。 网络请求权限
最后
以上就是漂亮小鸭子最近收集整理的关于android Handler + HandlerThread 简单实现网络轮询与计数器功能的全部内容,更多相关android内容请搜索靠谱客的其他文章。
发表评论 取消回复