前言

我们知道,地址选择器是一个通用组件,网上的开源项目也有很多。那么为什么还会有这篇文章呢?因为我在调研过程中发现,虽然都是地址选择器,但是实现的方式却各不相同。以下是调研地址选择器的一些总结和思考实践。希望对大家有帮助,大家有什么更好的想法,也要告知我哦~

地址选择器实现方式介绍

  • 本地存放area.db文件
    大多数App都是此种实现

    • 优点:启动快,不受网络影响
    • 缺点:
      • 不能实时更新,数据更新依赖发布新版本。(或则自己实现一套更新机制,文件从后端下载,实现较为复杂)
      • 各端(服务器、前端、移动端)需要维护一份相同的地址信息表,维护成本高。
      • 地址信息表本地保存,增大安装包体积
  • 一次性从服务端拉取所有地址信息
    在App启动时候,一次性拉取所有地址信息。

    • 优点:数据可配置、请求少
    • 缺点:
      • 每次启动都请求服务器,大部分是无用请求,浪费了服务器资源。
      • 请求数据量大
    • 优化方案:更换请求时机,点击选择地址的时候才去一次性请求所有数据。但是还是不能避免请求数据量过大问题。
  • 实时获取省、市、区信息,选中上一级才去获取对应的下一级数据
    如:京东

    • 优点:数据可配置,请求数据量小
    • 缺点:请求较多,需要处理的异常case较多
    • 思考优化方案:每次唤起地址选择器时,缓存获取的地址信息历史数据。显示地址信息的时候,只有本地缓存没有当前数据,才向服务端发送请求。(其实这种场景很少出现,但是再小的苍蝇也是肉,能优化就优化了吧……)

因为用户基本是在有网络的情况下才会使用,所以选择联网获取地址信息也是合理的。又考虑到网络请求的大小,服务端性能影响,安装包大小以及地址信息可配置性等因素,实时获取地址信息是一个不错的方式。下面介绍地址选择器实现一些关键点。

实时获取信息的地址选择器设计

先来看效果,如下图所示。唤起地址选择器会有一次省份的网络请求,之后每一级数据都是实时去获取。在当前地址选择器唤起状态,获取之后就将历史数据保存在本地,下一次就不再发送网络请求了。

整体的框架设计类图如下所示:

数据结构设计

当前的地址信息按照省、市、区/县、街道四级划分,后一级总是和前一级相关联。

  • Province
public class Province {public long id;public String name;
}
复制代码
  • City
public class City  {public long id;public long province_id;public String name;
}
复制代码
  • County
public class County {public long id;public long city_id;public String name;
}
复制代码
  • Street
public class Street {public long id;public long county_id;public String name;
}
复制代码

回调接口设计

主要提供了4个回调方法:

public interface OnAddressSelectedListener {// 获取地址完成回调void onAddressSelected(Province province, City city, County county, Street street);// 选取省份完成回调void onProvinceSelected(Province province);// 选取城市完成回调void onCitySelected(City city);// 选取区/县完成回调void onCountySelected(County county);
}
复制代码

这里着重说一下onAddressSelected回调方法,其是在地址选择完成的时候调用。那么是如何判断地址选择已经完成呢。这个在AddressSelector中有如下一个机制。
每次一个级别选择完成后,会获取下一个级别的数据(网络请求或者缓存获取)进行显示。显示的时候有这么一个逻辑,当前级别有数据,则正常显示;若没有,则说明地址选择已经完成,此时调用onAddressSelected方法。

缓存设计

我们这里默认服务端每个地址的id都是唯一的。一次点击选择地址的缓存操作,可以看下如下的流程图。

  1. 建立三个缓存map,分别缓存省-市市-区区-街道
/** 缓存数据:省-市 */
private ArrayMap<Long, List<City>> province2city = new ArrayMap<>();
/** 缓存数据:市-区 */
private ArrayMap<Long, List<County>> city2county = new ArrayMap<>();
/** 缓存数据:区-街道 */
private ArrayMap<Long, List<Street>> county2street = new ArrayMap<>();
复制代码
  1. 选择省、市、区某一级时,先查看是否有缓存数据,若有则使用缓存数据;若没有,则向服务端发送网络请求。
// 有缓存则直接使用缓存,否则去重新请求
if(province2city.containsKey(province.id)){setCities(province2city.get(province.id));
} else {progressBar.setVisibility(View.VISIBLE); listener.onProvinceSelected(province);
}
复制代码

3、每次获取的历史数据,存储在相应的缓存map中。

province2city.put(provinceId, cities);
复制代码

Tab切换动画实现

不知道大家有没有发现,当我们选择地址时,顶部tab下有一个小横条,它会跟着我们选择进行平滑切换的。横条的动画主要包含两个部分:

  • 平滑移动到所选tab的文字下面
  • 根据选择tab内容的长度,在横条移动过程中,动态变化横条长度。当移动结束时,刚好变化为与tab内容长度一致。

具体思路是通过ObjectAnimator来设置横条移动的动画效果,ValueAnimator实现横条长度的动态变化,最后通过AnimatorSet来设置两个动画一起运行。控件中,封装了一个方法实现此动画效果。

private AnimatorSet buildIndicatorAnimatorTowards(TextView tab) {ObjectAnimator xAnimator = ObjectAnimator.ofFloat(indicator, "X", indicator.getX(), tab.getX() + tab.getPaddingLeft() * 2);final ViewGroup.LayoutParams params = indicator.getLayoutParams();ValueAnimator widthAnimator = ValueAnimator.ofInt(params.width, tab.getMeasuredWidth() - tab.getPaddingLeft() * 2);widthAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator animation) {params.width = (int) animation.getAnimatedValue();indicator.setLayoutParams(params);}});AnimatorSet set = new AnimatorSet();set.setInterpolator(new FastOutSlowInInterpolator());set.playTogether(xAnimator, widthAnimator);return set;
}
复制代码

控件使用

  1. gradle导入控件
compile 'com.zr.addressselector:library:1.0.1'
复制代码
  1. Activity实现OnAddressSelectedListener接口
public class MainActivity extends AppCompatActivity implements OnAddressSelectedListener
复制代码
  1. 展现地址选择器
dialog = new BottomSelectorDialog(MainActivity.this);
dialog.setOnAddressSelectedListener(MainActivity.this);
dialog.show();
复制代码
  1. 根据网络返回,设置数据
dialog.getSelector().setProvinces(Collections.singletonList(province));
复制代码
  1. 控件提供的几个设置方法
/*** 设置回调接口* @param listener*/public void setOnAddressSelectedListener(OnAddressSelectedListener listener) {this.listener = listener;}/*** 设置省列表* @param provinces 省份列表*/public void setProvinces(List<Province> provinces){handler.sendMessage(Message.obtain(handler, WHAT_PROVINCES_PROVIDED, provinces));}/*** 设置市列表* @param cities 城市列表*/public void setCities(List<City> cities){handler.sendMessage(Message.obtain(handler, WHAT_CITIES_PROVIDED, cities));}/*** 设置区列表* @param countries 区/县列表*/public void setCountries(List<County> countries){handler.sendMessage(Message.obtain(handler, WHAT_COUNTIES_PROVIDED, countries));}/*** 设置街道列表* @param streets 街道列表*/public void setStreets(List<Street> streets){handler.sendMessage(Message.obtain(handler, WHAT_STREETS_PROVIDED, streets));}
复制代码

写在最后

虽然提供了gradle compile导入的方式,但是整个控件的源码其实是很简单的。如果有定制需求,可以到这里下载源码。

项目源码下载:ZRAddressSelector

特别感谢

JDAddressSelector,本组件设计也是受此开源项目启发,非常感谢作者开源~

一次地址选择器的实践相关推荐

  1. android开发地址选择器,Android地址选择器 类似于京东的地址选择

    简介 最近东西写的挺多的,这不又要弄一个类似于京东的地址选择器,然后刚开始我是不愿意自己去写的,这东西真的是浪费时间.但是下班后回到家找了一圈没找到一个合适的,好吧,那我就自己来封装一个呗,反正生命在 ...

  2. MUI 地址选择器 - picker使用

    MUI 地址选择器 - picker使用 很多安卓原生的地址选择器中,选择器基本是实时滚动的. 就像腾讯QQ应用的地址选择器一样! 效果截图如下: 代码如下: <!DOCTYPE html> ...

  3. 支付宝小程序组件库开发之省市区三级地址选择器组件

    支付宝小程序开发文档中并没有提供明确的省市区选择器,不少项目还是有地址的填写需求,根据支付宝小程序现有提供的组件以及api,完全是可以实现填写地址的需求,比如分别获取省市区,通过地图来获取地址等,但是 ...

  4. php地址选择插件,微信小程序中关于三级联动地址选择器的实例分享

    本文介绍了微信小程序三级联动地址选择器的实例代码,分享给大家,有需要的可以一起了解一下 在一些电商类的小程序中,地址选择这个功能一般是必备的,一般的收货信息都需要有一个能选择省市县的控件,当然也有些人 ...

  5. Android地址选择器的实现

    最近在做地址管理的功能,新建地址的时候,需要根据后台提供的省市区的数据,让用户进行地址的选择,最近项目比较赶,本来想网上找一个的,可是找了很久都没找到我想要的效果,所以就根据后台提供的数据,弄了一个. ...

  6. Android进阶之路 - 仿京东地址选择器使用指南

    因为现在项目的地址选择器比较low,自己又比较懒,所以就找到了仿京东的地址选择器,观赏几篇博文之后,发现总是被半路卡死,很难一路走到底,所以在github找到了项目地址,但是作者的功能简介又介绍的不是 ...

  7. 这是用原声js编写的地址选择器,使用select编写的三联选择器

    这是用原声js编写的地址选择器,使用select编写的三联选择器 <!DOCTYPE html> <html lang="en"> <head> ...

  8. Android 选择器 PickerView实例,时间选择器、地址选择器、单项选择器、多项选择器自定义布局

    是采用的github开源库PickerView,省时省力.最终效果图见最后 首先添加依赖: //PickerView 选择器 implementation 'com.contrarywind:Andr ...

  9. jq-weui滚动刷新,日历,和地址选择器

    最近工作方面的原因,接触到了微信公众号.然后网上找资料发现了jq-weui这个框架,觉得特别不错,分享一下 下载jq-weui点击这里下载jquery-weui,这里一定要注意下载的版本.因为有些功能 ...

最新文章

  1. 基于mpi的奇偶排序_并行程序设计(第2版)pdf
  2. 由神经网络的迭代次数计算输出值并评价网络性能
  3. Xcode8打包上传后构建版本消失问题
  4. oracle 数据操作的相关参数
  5. C语言scanf:获取输入的内容
  6. easyui crud java_Easyui 创建 CRUD 应用_EasyUI 插件
  7. 【零基础学Java】—对象数组(十三)
  8. java递归删除文件夹_如何使用递归删除Java中的目录/文件夹
  9. mysql与oracle存储过程_MySQL与Oracle差异比较之五存储过程Function
  10. 步进电机基础(6.4)-步进电机的特性测量方法-暂态(阻尼)特性的测量和噪音和振动的测量
  11. PRINCE2 项目管理方法论框架介绍
  12. arcgis engine 打开shp文件
  13. oracle linux 环境变量
  14. java 简单考试系统 ——java程序设计
  15. 手机不显示网络信号连接到服务器是怎么回事,手机连接不上网络怎么办
  16. JQuery入门(1) - 选择器
  17. MIMIC-III数据集介绍
  18. Android 配置引入arr报错解决
  19. SV function
  20. c++矩阵转置_线性代数中的向量矩阵

热门文章

  1. 不再受限于数据集和硬件,下一代 ML 软件如何构建?
  2. 微软发布通用型AI框架Avatar Framework
  3. 嵌入式视觉领域的机器学习
  4. pandas中dataframe的构造(csv等结构化文件读取,字典读取)以及保存
  5. 四位专家谈:数字医学中的因果关系
  6. 重磅!三星宣布3nm成功流片!
  7. 脑神经计算建模揭示前额叶皮层不同类型中间神经元在信息维持中的作用
  8. 【赠书】21世纪科技竞争的核心是超级智能的控制权
  9. 5 年提速 500 倍,英伟达 GPU 创纪录突破与技术有哪些?
  10. 一文尽揽2018 Google I/O:谷歌让你感受到AI科技的魅力