如何通过SNTPClient的onTimeResponse回调正确获取字符串结果
问题说明
使用sntp-client-android库做网络时间获取时,两种写法表现不一致:
- 回调内直接弹出Toast可以正常展示
rawDate结果,代码如下:
SNTPClient.getDate(TimeZone.getTimeZone("Asia/Colombo"), new SNTPClient.Listener() { @Override public void onTimeResponse(String rawDate, Date date, Exception ex) { Toast.makeText(getApplicationContext(), rawDate, Toast.LENGTH_LONG).show(); } });
- 在回调外部定义成员变量
strdate接收返回值,在异步调用外直接弹Toast,结果strdate为null,代码如下:
private String strdate; ... SNTPClient.getDate(TimeZone.getTimeZone("Asia/Colombo"), new SNTPClient.Listener() { @Override public void onTimeResponse(String rawDate, Date date, Exception ex) { strdate = rawDate; } }); Toast.makeText(getApplicationContext(), strdate, Toast.LENGTH_LONG).show();
问题本质:
SNTPClient.getDate是异步方法,发起SNTP网络请求的过程不会阻塞当前执行线程,外层的Toast代码会在onTimeResponse回调触发前就执行完毕,此时strdate还未被赋值,取值自然为null。
正确获取返回值的方案
异步回调的核心原则是:所有依赖回调返回值的逻辑,必须在回调触发后再执行,不要尝试在异步方法的外层同步上下文里直接拿返回值。
常用的处理方式有3种:
1. 直接在回调内部处理后续逻辑(最推荐)
这是成本最低、逻辑最清晰的写法,拿到rawDate之后要做的赋值、UI更新、业务逻辑调用,全部写到onTimeResponse方法内即可,记得先做异常判断:
SNTPClient.getDate(TimeZone.getTimeZone("Asia/Colombo"), new SNTPClient.Listener() { @Override public void onTimeResponse(String rawDate, Date date, Exception ex) { // 先处理请求异常场景 if (ex != null) { ex.printStackTrace(); Toast.makeText(getApplicationContext(), "网络时间获取失败", Toast.LENGTH_SHORT).show(); return; } // 所有用到时间结果的逻辑全部放在这里 strdate = rawDate; Toast.makeText(getApplicationContext(), strdate, Toast.LENGTH_LONG).show(); // 比如更新文本、调用业务方法传参都写在这 // timeTv.setText(strdate); // initSchedule(strdate); } });
2. 自定义业务回调向外透传结果
如果获取时间的逻辑封装在工具类、Repository层,不想把UI逻辑耦合进SNTP的原始回调里,可以自定义一层业务接口,把结果向外抛到调用层再处理:
首先定义回调接口:
public interface NetTimeCallback { void onTimeLoaded(String dateResult); }
封装通用的时间获取方法:
public void fetchNetTime(NetTimeCallback callback) { SNTPClient.getDate(TimeZone.getTimeZone("Asia/Colombo"), new SNTPClient.Listener() { @Override public void onTimeResponse(String rawDate, Date date, Exception ex) { if (ex == null) { callback.onTimeLoaded(rawDate); } } }); }
在页面/业务层调用时,拿到结果再做后续处理:
fetchNetTime(new NetTimeCallback() { @Override public void onTimeLoaded(String dateResult) { strdate = dateResult; Toast.makeText(getApplicationContext(), strdate, Toast.LENGTH_LONG).show(); } });
3. 同步阻塞等待结果(极不推荐,容易引发ANR)
如果特殊场景下必须在同步代码流里拿值,可以用CountDownLatch等阻塞工具等待回调返回,但绝对不能在主线程执行这段逻辑,否则会阻塞主线程触发ANR:
// 以下代码必须放在子线程执行 CountDownLatch latch = new CountDownLatch(1); final String[] timeResult = new String[1]; SNTPClient.getDate(TimeZone.getTimeZone("Asia/Colombo"), new SNTPClient.Listener() { @Override public void onTimeResponse(String rawDate, Date date, Exception ex) { timeResult[0] = rawDate; latch.countDown(); } }); try { // 最多等待3秒,超时自动释放 latch.await(3, TimeUnit.SECONDS); } catch (InterruptedException e) { e.printStackTrace(); } // 等待结束后才能拿到值,需要切回主线程再做UI更新 strdate = timeResult[0];
注意:如果
onTimeResponse回调默认不在主线程,执行Toast、setText等UI操作前必须先切到主线程,否则会触发UI线程异常。
内容的提问来源于stack exchange,提问作者moorker
相关产品推荐
相关产品推荐

