精华内容
下载资源
问答
  • 干货 | 携程酒店安卓地图开发实践

    千次阅读 2020-03-19 17:00:00
    作者简介 亦枫,携程资深软件工程师,负责酒店业务 Android 客户端的相关研发工作。当前大多数移动互联网 App 都会存在地图相关功能,尤其是 LB...

    作者简介

    亦枫,携程资深软件工程师,负责酒店业务 Android 客户端的相关研发工作。

    当前大多数移动互联网 App 都会存在地图相关功能,尤其是 LBS(基于位置服务)相关的业务,依赖性更强,携程 App 的酒店业务更是如此。这篇文章将围绕携程酒店 App 安卓地图功能,分别从产品业务背景、代码开发模块架构和遇到的典型产品技术问题等方面,描述我们这一路的开发实践经验,希望能够帮助到正在从事相关业务开发的同行们,大家相互交流,共同探讨。

     

    一、携程酒店地图业务介绍

     

    可视化的地图交互界面能够给到用户最直观的地理位置信息感受,根据用户主观心理选择的价格高低、距离远近、交通方式、生活购物等多个因素,帮助用户迅速找到目的地区域最适合自己的酒店。无论是直观体验上,还是用户习惯上,地图功能都是携程酒店整体业务不可或缺的一部分。

     

    携程酒店业务涉及地图开发的地方目前主要有三个模块,酒店列表页小地图、酒店列表大地图和酒店详情页地图。

    1)列表页小地图

     

    提供与主列表数据联动的地图打点功能,方便用户浏览酒店列表时能够实时查看当前选中酒店的地图位置信息。

     

    地图 Marker 覆盖物与列表数据一致,同时根据当前列表分页,展示当前页与上一页的酒店数据,并突出选中当前酒店。

     

    2)列表页大地图

     

    包括顶部标题栏筛选项等辅助信息,中间地图背景信息和底部选中酒店卡片信息三部分,用户可通过筛选项、拖动地图自动加载当前地图屏幕内酒店等功能,实现通过地图订酒店的功能。

     

    之所以称之为列表页大地图,是因为当前页面与酒店列表页(包括小地图)自由切换,并记住当前用户行为,保存酒店数据信息。

     

    3)详情页的地图

     

    酒店详情地图主要提供导航路线、酒店周边相关 POI 内容,帮助用户了解所在酒店的具体地图信息。

     

    相比而言,酒店详情页的地图业务相对比较简单,这里的简单更多是针对开发层面,因为该页面的数据较为独立,不存在与其他页面有太多联动相关的业务。

     

    二、酒店地图相关架构设计

     

    大家知道,提供地图工具的第三方服务不止一家,常见如国内有百度、高德、腾讯地图,国外有谷歌、苹果地图服务。

     

    为了保证携程 App 内地图统一性和更换地图的高效可维护性,携程各业务部门所用到的地图由携程公共无线部门收口,进行封装对接。各业务部门可根据自己的实际业务需要再进行自定义处理,酒店部门也是如此。

     

    为了方便酒店三大模块的地图业务统一性,酒店安卓这边自定义一个HotelMapView继承自公共提供的CtripMapView 来共具体业务使用,并将 Marker 打点、地图围栏、生命周期处理等通过接口形式抽象进来。

     

    1)详情页地图架构设计

     

    前面说到,详情页由于自身的数据独立性和业务功能的简介,相对而言,开发层面的代码逻辑还是简单清晰的,我们使用Android 开发传统的MVC 架构加上适当的抽象封装就能轻松应对。

     

    稍微复杂一些的逻辑可能在于ABTest 上面,通用逻辑还是在Activity 层面提供的Controller 控制层,类似底部周边POI 的处理逻辑抽取到独立的Holder 辅助类中。

     

    相比而言,详情页由于业务的界面独立性也不会有太多的技术性坑存在,唯一可能需要注意的是就是各种经纬度坐标系类型的转换处理,这个在导航至第三方地图时尤其需要引起重视。

     

    目前市场上常见的经纬度坐标系,以及主流第三方地图服务商的对应使用关系为:

     

    WGS84:国际通用标准经纬度坐标系,GPS坐标,也称地球坐标系。谷歌地图目前使用的就是 WGS84 坐标系(中国区除外);

     

    GCJ02:中国国家测绘局制订的坐标系,有WGS84 坐标系加密而成,也称火星坐标系,谷歌中国区地图、高德地图的使用者;

     

    BD09:即百度坐标系,由GCJ02坐标系进一步加密而成,百度地图独家使用的经纬度坐标系。

     

    2)列表页地图架构设计

     

    列表页大小地图业务逻辑错综复杂,不可能把所有的业务都集中在Activity 或Fragment 中处理,无论是多人开发的效率还是后续的可维护性,都比较差,传统的MVC 架构显然已经不太适合。这里我们间接采用Android 系统推荐的MVP 架构和页面模块化来分离实现。

    根据列表页大地图业务业务分类,大致分为上图这些核心模块,以及其他诸如动画、遮罩浮层Tips 等其他附加模块。

     

    这样,原本臃肿耦合的 Fragment 和 Activity 控制层就没有那么多耦合性强的代码,只是提供各个具象 Presenter 的注册业务,具体逻辑和生命周期均交到业务模块 Presenter 中间层,Presenter 持有View 和Model 的引用,以及Context 生命周期的回调,可独立实现自己的功能,高内聚、低耦合的特点更加利于扩展维护。

     

    事实上,列表页大小地图在产品业务不停迭代的过程中,大小地图位于两个 Activity 内独立维护已经不能满足产品需求,譬如大小地图来回切换时,两个页面的 MapView 很难做到动画的无缝过渡,交互体验难有充分自由的发挥;再譬如,顶部 ToolBar 和筛选项部分,无法共用,维护起来也非常费劲。经过讨论,进行技改,代码重构,合并列表大小地图。

    可以看到,这种架构下,不用再单独开发与酒店住列表相同的模块内容,只需要定义大小地图相关的 onShow、onHide等生命周期方法,实现 IHotelListMapView 接口,相关模块依然是低耦合的。同时,由于共用的是同一个 MapView,也在同一个Activity 当中,切换动画、处理 CacheBean 数据、以及共享 Hotel Service 都是非常方便的。

     

    三、遇到问题以及解决方案

     

    酒店列表页大小地图由于数据依赖和同步联动的关系,开发过程中会存在线程同步等各种各样的问题。

     

    1)酒店数据与地图数据模型转换

     

    列表页酒店数据的 JSON 结构是非常复杂的,而且不能直接用于地图打点使用,需要转换为地图不同覆盖物需要的 Model 数据结构。同时,这个转换过程相对 UI 线程而言,算是一个耗时操作,所以所有地图打点渲染前的数据转换都需要放置到子线程中单独处理,否则就会造成 UI 卡顿。

     

    解决方案有很多,这里我们选择 Android 系统提供的 AsyncTask 类,来实现 UI 线程与子线程的切换与数据通信问题。

     

    2)酒店 List 的线程同步问题

     

    地图数据来源于 HotelListCacheBean 共享内存中的酒店主列表,由于转换过程放置在子线程中,而且不能通过加锁阻断主列表的用户操作,那么必然存在同一进程不同线程的数据同步问题。

     

    对于小地图来说,用户滑动列表或修改筛选项的操作是随意而为的,短时间内可以不停操作,如果在子线程中多次对CacheBean 中的可变数据产生依赖,就会造成前后不一致问题,引发多线程并发造成的List 集合异常,如:

     

    - ConcurrentModificationException

     

    - ArrayIndexOutOfBoundsException

     

    为了规避这种问题,应减少线程处理过程中的多次依赖,而是在线程开始执行前,复制目标数据源,供子线程处理。

     

    3)酒店地图数据的一致性问题

     

    前面说到,借助 AsyncTask 实现在子线程中转换数据模型,然后切换到 UI 线程中渲染地图,理想状态下,是没有什么问题的。当多线程并发执行,CacheBean 中的酒店数据可能与地图 Marker 数据不同步,实际渲染地图的数据可能与酒店列表的数据对应关系错乱,导致用户操作发生异常。比如用户选择某个 Marker 点联动的酒店列表或底部酒店卡片不是实际想要的酒店信息。这就需要开发这边保证数据转换与地图渲染单次流程的完整性,类似多线程中的原子性问题。

     

    这里我们采取的解决方案是,使用Java Atomic 包提供的线程安全类AtomicBoolean 创建一个 Flag 标识位,根据标识位来控制不同批次数据处理的完整性,类似这样:

     

    private val isMapTaskDoing : AtomicBoolean =AtomicBoolean(false)
     
    override fun doInBackground(vararg params: String):Void? {
        if(isMapTaskDoing.compareAndSet(false, true)) {
            //converse data
        }
        return null
    }
     
    override fun onPostExecute(result: Void?) {
        // render ui
       isMapTaskDoing.set(false)
    }
    

    4)小地图Marker 分页问题

     

    列表页小地图的酒店等数据来源有很多,比如用户在大地图过滤的酒店数据也可能转换到小地图来展示。这些不同场景CacheBean 中保存的酒店数据分页Size 标准是不一样的。

     

    根据产品需求,小地图展示的是当前页与上一页的酒店数据,为了保证 Marker 数据分页的统一性与连贯性,可将CacheBean 中的多页酒店数据视为一个整体,再根据 Marker 自身定义的分页标准进行分页。对于用户而言,当有多页数据出现时,用户是不知道当前选中酒店位于哪一页,这也不是用户关心的问题,技术能做的就是确保用户体验是一致的。

     

    5)列表页地图屏幕半径问题

     

    列表页大地图拥有一个搜索屏幕内酒店的功能,这里需要获取当前屏幕内最小展示区域。一开始的时候,计算使用的是地图矩形展示区域内的最小圆经纬度坐标(由地图边界距离屏幕中心点最短半径决定),传递给 service 端,获取圆内酒店list 数据。

     

    事实上,圆形在业务上覆盖区域比矩形区域要小(少了四个角落的数据),在技术上,也比矩形区域计算效率低(涉及弧度等数学公式),改为矩形区域计算更具优势。

    四、酒店地图业务开发总结

      

    业务上,携程酒店借助地图给用户带来更优的使用体验,未来能够探索的功能创新点也非常多。开发上,Map 架构也会随着业务不断迭代变化,而遇到的问题也是各种各样,甚至那种实现代码与产品功能冲突类的问题也会存在,希望这些内容或经验能够帮助到大家。我们也在不断优化,持续升级的前进过程中。

    【推荐阅读】

     “携程技术”公众号

      分享,交流,成长

    展开全文
  • 这篇文章将围绕携程酒店 App 安卓地图功能,分别从产品业务背景、代码开发模块架构和遇到的典型产品技术问题等方面,描述我们这一路的开发实践经验,希望能够帮助到正在从事相关业务开发的同行们,大家相互交流,...

    当前大多数移动互联网 App 都会存在地图相关功能,尤其是 LBS(基于位置服务)相关的业务,依赖性更强,携程 App 的酒店业务更是如此。这篇文章将围绕携程酒店 App 安卓地图功能,分别从产品业务背景、代码开发模块架构和遇到的典型产品技术问题等方面,描述我们这一路的开发实践经验,希望能够帮助到正在从事相关业务开发的同行们,大家相互交流,共同探讨。

    一、携程酒店地图业务介绍

    可视化的地图交互界面能够给到用户最直观的地理位置信息感受,根据用户主观心理选择的价格高低、距离远近、交通方式、生活购物等多个因素,帮助用户迅速找到目的地区域最适合自己的酒店。无论是直观体验上,还是用户习惯上,地图功能都是携程酒店整体业务不可或缺的一部分。

    携程酒店业务涉及地图开发的地方目前主要有三个模块,酒店列表页小地图、酒店列表大地图和酒店详情页地图。

    396e9d08faf890d32abdda50656541b6.png

    1)列表页小地图

    提供与主列表数据联动的地图打点功能,方便用户浏览酒店列表时能够实时查看当前选中酒店的地图位置信息。

    地图 Marker 覆盖物与列表数据一致,同时根据当前列表分页,展示当前页与上一页的酒店数据,并突出选中当前酒店。

    2)列表页大地图

    包括顶部标题栏筛选项等辅助信息,中间地图背景信息和底部选中酒店卡片信息三部分,用户可通过筛选项、拖动地图自动加载当前地图屏幕内酒店等功能,实现通过地图订酒店的功能。

    之所以称之为列表页大地图,是因为当前页面与酒店列表页(包括小地图)自由切换,并记住当前用户行为,保存酒店数据信息。

    3)详情页的地图

    酒店详情地图主要提供导航路线、酒店周边相关 POI 内容,帮助用户了解所在酒店的具体地图信息。

    相比而言,酒店详情页的地图业务相对比较简单,这里的简单更多是针对开发层面,因为该页面的数据较为独立,不存在与其他页面有太多联动相关的业务。

    二、酒店地图相关架构设计

    大家知道,提供地图工具的第三方服务不止一家,常见如国内有百度、高德、腾讯地图,国外有谷歌、苹果地图服务。

    为了保证携程 App 内地图统一性和更换地图的高效可维护性,携程各业务部门所用到的地图由携程公共无线部门收口,进行封装对接。各业务部门可根据自己的实际业务需要再进行自定义处理,酒店部门也是如此。

    为了方便酒店三大模块的地图业务统一性,酒店安卓这边自定义一个HotelMapView继承自公共提供的CtripMapView 来共具体业务使用,并将 Marker 打点、地图围栏、生命周期处理等通过接口形式抽象进来。

    89eeb7b6019e761a5e7e0e7f52f35cfe.png

    1)详情页地图架构设计

    前面说到,详情页由于自身的数据独立性和业务功能的简介,相对而言,开发层面的代码逻辑还是简单清晰的,我们使用Android 开发传统的MVC 架构加上适当的抽象封装就能轻松应对。

    稍微复杂一些的逻辑可能在于ABTest 上面,通用逻辑还是在Activity 层面提供的Controller 控制层,类似底部周边POI 的处理逻辑抽取到独立的Holder 辅助类中。

    相比而言,详情页由于业务的界面独立性也不会有太多的技术性坑存在,唯一可能需要注意的是就是各种经纬度坐标系类型的转换处理,这个在导航至第三方地图时尤其需要引起重视。

    目前市场上常见的经纬度坐标系,以及主流第三方地图服务商的对应使用关系为:

    WGS84:国际通用标准经纬度坐标系,GPS坐标,也称地球坐标系。谷歌地图目前使用的就是 WGS84 坐标系(中国区除外);

    GCJ02:中国国家测绘局制订的坐标系,有WGS84 坐标系加密而成,也称火星坐标系,谷歌中国区地图、高德地图的使用者;

    BD09:即百度坐标系,由GCJ02坐标系进一步加密而成,百度地图独家使用的经纬度坐标系。

    2)列表页地图架构设计

    列表页大小地图业务逻辑错综复杂,不可能把所有的业务都集中在Activity 或Fragment 中处理,无论是多人开发的效率还是后续的可维护性,都比较差,传统的MVC 架构显然已经不太适合。这里我们间接采用Android 系统推荐的MVP 架构和页面模块化来分离实现。

    893ba33a7bf392cf5708565323418fa1.png

    根据列表页大地图业务业务分类,大致分为上图这些核心模块,以及其他诸如动画、遮罩浮层Tips 等其他附加模块。

    这样,原本臃肿耦合的 Fragment 和 Activity 控制层就没有那么多耦合性强的代码,只是提供各个具象 Presenter 的注册业务,具体逻辑和生命周期均交到业务模块 Presenter 中间层,Presenter 持有View 和Model 的引用,以及Context 生命周期的回调,可独立实现自己的功能,高内聚、低耦合的特点更加利于扩展维护。

    事实上,列表页大小地图在产品业务不停迭代的过程中,大小地图位于两个 Activity 内独立维护已经不能满足产品需求,譬如大小地图来回切换时,两个页面的 MapView 很难做到动画的无缝过渡,交互体验难有充分自由的发挥;再譬如,顶部 ToolBar 和筛选项部分,无法共用,维护起来也非常费劲。经过讨论,进行技改,代码重构,合并列表大小地图。

    fe99bd798908fef5e3c7e6eb9373d902.png

    可以看到,这种架构下,不用再单独开发与酒店住列表相同的模块内容,只需要定义大小地图相关的 onShow、onHide等生命周期方法,实现 IHotelListMapView 接口,相关模块依然是低耦合的。同时,由于共用的是同一个 MapView,也在同一个Activity 当中,切换动画、处理 CacheBean 数据、以及共享 Hotel Service 都是非常方便的。

    三、遇到问题以及解决方案

    酒店列表页大小地图由于数据依赖和同步联动的关系,开发过程中会存在线程同步等各种各样的问题。

    1)酒店数据与地图数据模型转换

    列表页酒店数据的 JSON 结构是非常复杂的,而且不能直接用于地图打点使用,需要转换为地图不同覆盖物需要的 Model 数据结构。同时,这个转换过程相对 UI 线程而言,算是一个耗时操作,所以所有地图打点渲染前的数据转换都需要放置到子线程中单独处理,否则就会造成 UI 卡顿。

    解决方案有很多,这里我们选择 Android 系统提供的 AsyncTask 类,来实现 UI 线程与子线程的切换与数据通信问题。

    2)酒店 List 的线程同步问题

    地图数据来源于 HotelListCacheBean 共享内存中的酒店主列表,由于转换过程放置在子线程中,而且不能通过加锁阻断主列表的用户操作,那么必然存在同一进程不同线程的数据同步问题。

    对于小地图来说,用户滑动列表或修改筛选项的操作是随意而为的,短时间内可以不停操作,如果在子线程中多次对CacheBean 中的可变数据产生依赖,就会造成前后不一致问题,引发多线程并发造成的List 集合异常,如:

    - ConcurrentModificationException

    - ArrayIndexOutOfBoundsException

    为了规避这种问题,应减少线程处理过程中的多次依赖,而是在线程开始执行前,复制目标数据源,供子线程处理。

    3)酒店地图数据的一致性问题

    前面说到,借助 AsyncTask 实现在子线程中转换数据模型,然后切换到 UI 线程中渲染地图,理想状态下,是没有什么问题的。当多线程并发执行,CacheBean 中的酒店数据可能与地图 Marker 数据不同步,实际渲染地图的数据可能与酒店列表的数据对应关系错乱,导致用户操作发生异常。比如用户选择某个 Marker 点联动的酒店列表或底部酒店卡片不是实际想要的酒店信息。这就需要开发这边保证数据转换与地图渲染单次流程的完整性,类似多线程中的原子性问题。

    这里我们采取的解决方案是,使用Java Atomic 包提供的线程安全类AtomicBoolean 创建一个 Flag 标识位,根据标识位来控制不同批次数据处理的完整性,类似这样:

    private val isMapTaskDoing : AtomicBoolean =AtomicBoolean(false)
     
    override fun doInBackground(vararg params: String):Void? {
        if(isMapTaskDoing.compareAndSet(false, true)) {
            //converse data
        }
        return null
    }
     
    override fun onPostExecute(result: Void?) {
        // render ui
       isMapTaskDoing.set(false)
    }

    4)小地图Marker 分页问题

    列表页小地图的酒店等数据来源有很多,比如用户在大地图过滤的酒店数据也可能转换到小地图来展示。这些不同场景CacheBean 中保存的酒店数据分页Size 标准是不一样的。

    根据产品需求,小地图展示的是当前页与上一页的酒店数据,为了保证 Marker 数据分页的统一性与连贯性,可将CacheBean 中的多页酒店数据视为一个整体,再根据 Marker 自身定义的分页标准进行分页。对于用户而言,当有多页数据出现时,用户是不知道当前选中酒店位于哪一页,这也不是用户关心的问题,技术能做的就是确保用户体验是一致的。

    5)列表页地图屏幕半径问题

    列表页大地图拥有一个搜索屏幕内酒店的功能,这里需要获取当前屏幕内最小展示区域。一开始的时候,计算使用的是地图矩形展示区域内的最小圆经纬度坐标(由地图边界距离屏幕中心点最短半径决定),传递给 service 端,获取圆内酒店list 数据。

    事实上,圆形在业务上覆盖区域比矩形区域要小(少了四个角落的数据),在技术上,也比矩形区域计算效率低(涉及弧度等数学公式),改为矩形区域计算更具优势。

    c161b9bb1dcf69c0fb46dbf6b7db6fb3.png

    四、酒店地图业务开发总结

    业务上,携程酒店借助地图给用户带来更优的使用体验,未来能够探索的功能创新点也非常多。开发上,Map 架构也会随着业务不断迭代变化,而遇到的问题也是各种各样,甚至那种实现代码与产品功能冲突类的问题也会存在,希望这些内容或经验能够帮助到大家。我们也在不断优化,持续升级的前进过程中。

    【作者简介】亦枫,携程资深软件工程师,负责酒店业务 Android 客户端的相关研发工作。

    更多携程技术人一手干货文章,请关注“携程技术”微信公众号。

    展开全文
  • 携程、去哪儿日历源码.rar,太多无法一一验证是否可用,程序如果跑不起来需要自调,部分代码功能进行参考学习。
  • 携程、去哪儿日历源码分享.rar,太多无法一一验证是否可用,程序如果跑不起来需要自调,部分代码功能进行参考学习。
  • 携程阿里旅行,日历选择,实现来回日历的选择.zip,太多无法一一验证是否可用,程序如果跑不起来需要自调,部分代码功能进行参考学习。
  • 如图:我们可以想到先做三个View 这三个View使用FlexBox平分,flex都为1,这里的flex其实就相当于安卓里面的weight权重的概念。 class hello extends Component{ render(){ return( ,height:80,...

    这里讲一下RN中的View组件:
    先看一下效果
    这里写图片描述

    下面是代码,可以直接copy:

    后面会给大家一步一步讲解过程,与大家共同成长

    import React, { Component } from 'react';
     import {
      AppRegistry,
      StyleSheet,
      Text,
      View,
      TextInput,
      ScrollView,
      ListView,
      PixelRatio
    } from 'react-native';
    
    class hello extends Component{
      render(){
        return(
          <View style = {styles.flex}>
            <View style = {styles.container}>
                <View style = {[styles.item,styles.center]}>
                  <Text style={styles.font}>酒店</Text>
                </View>
                <View style = {[styles.item,styles.lineLeft]}>
                 
                  <View style = {[styles.item_inner,styles.center,styles.lineBottom]}>
                    <Text style={styles.font}>机票</Text>
                  </View>
                  <View style = {[styles.item_inner,styles.center]}>
                    <Text style={styles.font}>火车票</Text>
                  </View>
    
                </View>
                <View style = {[styles.item,styles.lineLeft]}>
                  <View style = {[styles.item_inner,styles.center,styles.lineBottom]}>
                    <Text style={styles.font}>旅游</Text>
                  </View>
                  <View style = {[styles.item_inner,styles.center]}>
                    <Text style={styles.font}>攻略</Text>
                  </View>
                </View>
            </View>
          </View>
        );
      }
    };
    
    const styles = StyleSheet.create({
      container:{
        marginTop:200,
        marginLeft:5,
        marginRight:5,
        flexDirection:'row',
        padding:2,
        borderRadius:5,
        height:84,
        backgroundColor : '#ff0067'
      },
      item:{
        flex:1,
        height:80,
      },
      item_inner:{
        flex:1,
        height:40,
        
      },
      center:{
        justifyContent:'center',
        alignItems:'center'
      },
      flex:{
        flex :1
      },
      font:{
        color:'#ffffff',
        fontSize:16,
        fontWeight:'bold'
      },
      lineBottom:{
        borderBottomWidth:1/PixelRatio.get(),
        borderColor:'#ffffff'
      },
      lineLeft:{
        borderLeftWidth:1/PixelRatio.get(),
        borderColor:'#ffffff'
      }
    });
    AppRegistry.registerComponent('hello', () => hello);
    

    下面让我们一步一步来分解:
    #第一步
    如图:我们可以想到先做三个View 这三个View使用FlexBox平分,flex都为1,这里的flex其实就相当于安卓里面的weight权重的概念。

    这里写图片描述

    class hello extends Component{
      render(){
        return(
          <View style = {{backgroundColor : '#ffffff'}}>
            <View style = {{backgroundColor : '#ff0067',height:80,flexDirection:'row'}}>
                <View style = {{flex:1,backgroundColor : '#ff00ff'}}>  
                </View>
    
                <View style = {{flex:1,backgroundColor : '#ffff00'}}>  
                </View>
    
                <View style = {{flex:1,backgroundColor : '#00ffff'}}>  
                </View>
            </View>
          </View>
        );
      }
    };
    

    #第二步
    我们可以考虑到后面两个View里面也是flexBox,flexDirection为默认column.
    这里写图片描述

    class hello extends Component{
      render(){
        return(
          <View style = {{backgroundColor : '#ffffff'}}>
            <View style = {{backgroundColor : '#ff0067',height:80,flexDirection:'row'}}>
                <View style = {{flex:1,backgroundColor : '#ff00ff'}}>  
                </View>
    
                <View style = {{flex:1,backgroundColor : '#ffff00'}}>  
                  <View style = {{flex:1,backgroundColor : '#0f11ff'}}>  
                  </View>
                  <View style = {{flex:1,backgroundColor : '#02f3ff'}}>  
                  </View>
                </View>
    
                <View style = {{flex:1,backgroundColor : '#00ffff'}}>  
                  <View style = {{flex:1,backgroundColor : '#ff110f'}}>  
                  </View>
                  <View style = {{flex:1,backgroundColor : '#f2f300'}}>  
                  </View>
                </View>
            </View>
          </View>
        );
      }
    };
    

    #第三步
    添加文字进去
    这里写图片描述

    class hello extends Component{
      render(){
        return(
          <View style = {{backgroundColor : '#ffffff'}}>
            <View style = {{backgroundColor : '#ff0067',height:80,flexDirection:'row'}}>
                <View style = {{flex:1,backgroundColor : '#ff00ff',justifyContent:'center',alignItems:'center'}}>  
                  <Text style ={{color:'#ffffff',fontSize:16,fontWeight:'bold'}}>11111</Text>
                </View>
    
                <View style = {{flex:1,backgroundColor : '#ffff00'}}>  
                  <View style = {{flex:1,backgroundColor : '#0f11ff',justifyContent:'center',alignItems:'center'}}> 
                    <Text style ={{color:'#ffffff',fontSize:16,fontWeight:'bold'}}>22222</Text> 
                  </View>
                  <View style = {{flex:1,backgroundColor : '#02f3ff',justifyContent:'center',alignItems:'center',justifyContent:'center',alignItems:'center'}}>  
                    <Text style ={{color:'#ffffff',fontSize:16,fontWeight:'bold'}}>33333</Text> 
                  </View>
                </View>
    
                <View style = {{flex:1,backgroundColor : '#00ffff'}}>  
                  <View style = {{flex:1,backgroundColor : '#ff110f',justifyContent:'center',alignItems:'center'}}>  
                    <Text style ={{color:'#ffffff',fontSize:16,fontWeight:'bold'}}>44444</Text> 
                  </View>
                  <View style = {{flex:1,backgroundColor : '#f2f300',justifyContent:'center',alignItems:'center'}}>  
                    <Text style ={{color:'#ffffff',fontSize:16,fontWeight:'bold'}}>55555</Text> 
                  </View>
                </View>
            </View>
          </View>
        );
      }
    };
    

    现在代码看起来有点乱 不过基本效果有了 ,接下来我们把style提取出来,然后再加上一些处理就可以得到我们文章开头看到的效果了。是不是很酷炫。

    这里在样式中用到了PixelRatio。
    这个就是获取屏幕的设备像素比。window.devicePixelRatio是设备上物理像素和设备独立像素(device-independent pixels (dips))的比例。
    公式表示就是:window.devicePixelRatio = 物理像素 / dips

    dip或dp,(device independent pixels,设备独立像素)与屏幕密度有关。dip可以用来辅助区分视网膜设备还是非视网膜设备。

    说道dp,安卓同学都应该很熟悉才对,这里就不过多介绍了。

    扫码关注公众号“伟大程序猿的诞生“,更多干货新鲜文章等着你~

    公众号回复“资料获取”,获取更多干货哦~

    有问题添加本人微信号“fenghuokeji996” 或扫描博客导航栏本人二维码

    展开全文
  • 关于Android的近况 大家都知道,今年移动开发不那么火热了,完全没有了前两年Android开发那种火热的势头,如此同时,AI热火朝天,很多言论都说Android不行了。其实不光是Android,iOS也有类似的言论。...

    关于Android的近况

    大家都知道,今年移动开发不那么火热了,完全没有了前两年Android开发那种火热的势头,如此同时,AI热火朝天,很多言论都说Android不行了。其实不光是Android,iOS也有类似的言论。

    那么到底如何看待这一现象呢?

    我的答案是:Android还行,只是回归平淡了,没有了前些年的火热。

    下面分享一下我在爱奇艺的面经

    面试前的话:在面试时一定不要受前面没有过的面试的影响,一定要有一个好的心态,不要面试还没开始就自己把自己思绪搞乱了

    一共进行了4轮面试

    爱奇艺一面 50min

    项目

    • 主要介绍了以前做过的项目,分析了内存泄漏,线程同步的问题

    计算机网络

    • HTTP/HTTPS区别

    Android

    • OkHttp框架(里面有那些设计模式)
    • 如何终止一个线程

    爱奇艺二面 50min

    介绍项目

    • 内存泄漏的来源
    • 有没有做过优化

    Android

    • Service的两种启动方式?区别在哪?
    • 性能优化有没有做过?

    Java

    • 手写单例模式

    算法

    • 删除链表中一个节点

    爱奇艺三面 40min

    自我介绍

    • 项目
    • 有没有特别擅长的

    Java

    • public作用?
    • .java文件名怎么确定?
    • 外部类最多有几个?
    • 内部类最多有几个?
    • 内部类支持嵌套么?
    • 线程池怎么给新建的线程设置名字?
    • 线程池种类?
    • 注解的使用?

    Android

    • Activity的启动模式下生命周期
    • Activity A->B的生命周期
    • Handler中怎么实现Looper和线程绑定?
    • 一个线程最多有几个Looper?
    • 多个Looper报的异常?
    • 消息阻塞再次唤醒是什么机制?
    • ThreadLocal是什么?

    爱奇艺四面(HR面)

    • 自我介绍下吧
    • 你对公司有什么评价
    • 做了哪些项目
    • 你身边同事和朋友如何评价你呢
    • 如果与同事发生了意见的不一致,你会如何解决呢

    关于HR面试

    其实早就听说HR面试的最终的录取结果具有一票否决权,在面完前面的技术面试之后,还是很担心的。大概得到以下结论:

    • 诚信至上,所以在简历中不要存在任何虚假信息,企图通过虚假信息得到面试机会的后果得不偿失
    • HR更关注你的表达能力、与同事相处的能力以及对工作的态度
    • 对自己的是否一个明确的职业规划

    最后

    针对Android程序员,我这边给大家整理了一些资料,包括不限于高级UI、性能优化、架构师课程、NDK、混合式开发(ReactNative+Weex)微信小程序、Flutter等全方面的Android进阶实践技术;希望能帮助到大家,也节省大家在网上搜索资料的时间来学习,也可以分享动态给身边好友一起学习!

    • Android前沿技术大纲

    • 全套体系化高级架构视频

    资料领取:点赞+点击GitHub免费获取

    往期Android高级架构资料、源码、笔记、视频。高级UI、性能优化、架构师课程、混合式开发(ReactNative+Weex)全方面的Android进阶实践技术,群内还有技术大牛一起讨论交流解决问题。

    往期Android高级架构资料、源码、笔记、视频。高级UI、性能优化、架构师课程、混合式开发(ReactNative+Weex)全方面的Android进阶实践技术,群内还有技术大牛一起讨论交流解决问题。

    展开全文
  • 这就出现了安卓已死的论调。所以说,并不是Android已死,是门槛高了而已。 现在培训公司喜欢培训H5,学会保就业的承诺永久不变。这就是因为RN\Weex\Flutter的语法与H5相似,学了H5,除了能做原有的WEB开发以后,跨...
  • 前言 现实就是,99%的职业,年龄增大后都没前途。没前途是绝大多数普通人的宿命,有前途的人也用不着等到老。有没有前途已然不重要,无论做哪一行,健康的心态永远是首位。 从我个人的角度写写30多岁码工的感受:...
  • 菜鸟窝是国内专业靠谱的安卓开发技能在线教育平台。为每一位Android开发者提供高质量的 “就业培训”,“技能提升”,“求职”等服务 技术干货全在菜鸟窝,是干货就要分享 携程Android App的插件化和...
  • 携程技术类2018届春招笔试编程

    千次阅读 2017-04-11 20:25:23
    携程技术类2018届春招 安卓开发工程师 在线考试 编程题|20分1/1 有序字符串搜索 时间限制:C/C++语言 1000MS;其他语言 3000MS 内存限制:C/C++语言 204800KB;其他语言 729088KB 题目描述: 给定一些...
  • 作者简介新友,携程前端工程师,主要负责机票主流程和机酒预订流程相关开发工作,对安卓和React Native有浓厚兴趣。Heter Li ,负责携程GitLab代码平台研发,致力于高效...
  • 今日科技快讯 ...近日,苹果公司宣布,自7月18日至24日,凡在有银联云闪付标识的指定商铺,使用ApplePay来支付,即可...此次活动,除了数十家线下实体门店外,还有京东、携程等电商参与。不过专家认为
  • 安卓解决打包超出65535方法

    千次阅读 2016-01-24 15:22:07
    最近一直忙的跟狗一样,终于有一两天时间去研究方法超出的问题了,解决方案有两大种,  第一种:将大工程分成若干个小工程由一个主工程采用反射机制...如果像支付宝和携程一样,每个模块功能独立性很强的话采用这个方案
  • 比如就像 携程旅行网 和elong 途牛这些。旅行网上酒店里面的日期选择。他们那个日历是怎么做得
  • 2018年5月31日,安卓绿色联盟第七次执行组会议在上海携程总部隆重举行,联盟创始企业及金牌会员代表出席本次会议。会议对联盟前一阶段进展进行回顾,同时对联盟后续工作的开展进行了充分交流与讨论。 会议开始,...
  • 2018安卓绿色联盟开发者大会致力于为广大开发者打造一场顶级技术盛宴,为保证议题质量,我们邀请了来自阿里巴巴、百度、华为、腾讯、网易以及360、美团、微博、新浪、携程旅行等行业顶级专家作为我们大会议题出品人...
  • 安卓者得天下,当牛顿的“苹果”遇到了安卓,世界的变革开始了.....  移动互联网的时代,胜利者是随时随地普及用户需求,随着用户的体验要求精益求精。  移动互联网包罗万象,就像机器猫的口袋,大熊要...
  • 问题:为什么京东、携程放弃了c#&amp;.net而转型java,这其中的原因究竟有哪些呢?我想到的原因有以下几点:1. 开源语言,免费,相关产品不用花钱,微软的产品一年会花费多少?2. 开源插件会很多,可替代性强3. ...
  • 目前情况:10届某民办大学本科生,实际接触Android年限6年多了,工作年限五年半(注意,我说的是工作年限,不是工作经验),...从之前大量小创公司因疫情原因倒闭破产,360、滴滴、携程等大厂实施裁员的新闻其实也能.
  • 本次的主角是http://ctrip.com携程。以它为例子介绍一下非HTTP的通信协议逆向分析及协议仿真。本文你将了解到Google Protobuf的逆向分析及协议还原等知识。二、目标机票价格接口三、逆向过程按照正常的过程,我们...
  • 安卓开发大军浩浩荡荡,经过近十年的发展,Android技术优化日异月新,如今Android 11.0 已经发布,Android系统性能也已经非常流畅,可以在体验上完全媲美iOS。 但是,到了各大厂商手里,改源码、自定义系统,使得...
  • 为了体现张小龙对未来程序形态的理解,小程序有四个特定:无需安装、触手可及、用完即走、无需卸载。今天,36氪刚好有机会体验了一下携程、36氪和“小程序示例”三枚小程序,在这里跟大家分享一下。
  • 作者简介Eric,携程资深开发工程师,关注应用安全、渗透测试方面的技术和相关开源产品的二次开发。一、前言携程信息安全部门目前在研究百度OpenRASP技术,让它在携程落地进行服务漏洞扫描防护。做安全漏洞测试的同学...
  • learndemo.zip

    2020-04-07 18:47:15
    安卓仿携程筛选框,双向联动RecycleView,
  • 引言 随着应用版本的不断迭代,App变得非常...携程开源了其插件化开发框架(携程插件化开发框架),接下来我会学习并从本文开始介绍携程开源的这套插件化开发框架,让更多的人了解安卓的插件化开发。这里感谢携程

空空如也

空空如也

1 2 3
收藏数 44
精华内容 17
关键字:

安卓携程