Android App 技术框架选型及第三方框架原理(github) (!!!)

ButterKnife+RxJava+Rxtrofit+OkHttp+Dagger2+aFinal。

> 第三方框架(原理)分析
 -- Gson使用了注解和反射
 -- Okhttp使用了DiskLruCache(DiskLruCache->LinkedHashMap)
 -- RxJava的原理是一个高度解耦的观察者模式。

Android App整体架构设计的思考(一)- http://blog.csdn.net/luyi325xyz/article/details/43085409    
从零开始开发一款Android app,代码规划工作- http://www.zhihu.com/question/27645587/answer/37579829  
Android App整体架构设计的思考(二)- http://blog.csdn.net/luyi325xyz/article/details/43482123
Android通用流行框架大全- http://www.techug.com/15-android-framework?ref=myread
Android通用流行框架大全- http://www.kuqin.com/shuoit/20160509/351926.html
一个千万量级的APP使用的一些第三方库- http://blog.csdn.net/android_technology/article/details/52248197
构建 Android 应用程序一定要绕过的 30 个坑-https://github.com/xitu/gold-miner/blob/master/TODO/building-android-apps-30-things-that-experience-made-me-learn-the-hard-way.md

-- Android开发常用开源框架推荐- https://www.jianshu.com/p/deb55cf2f0c1
  首先是如何选择开源项目?建议优先选择github上比较活跃的开源项目,尽量避免从网页上零散的拷贝代码。选择开源项目的原则有下面这些:Stars, Issues, Pull Requests;文档和Demo,典型用户;弄清楚原理;结合实际业务场景;
--常用的框架分为下面几类:
1.UI框架和自定义控件;2.网络请求框架;3.图片缓存框架;4.数据存储框架;5.事件总线框架;6.插件化和热部署;

> 1.UI框架和自定义控件
  View注入框架:Butter Knife专注于Android 系统View 的注入框架,结合Android Studio插件使用
  下拉刷新和加载更多:Android-PullToRefresh,android-Ultra-Pull-to-Refresh,Android-PullToRefreshRecyclerView
  侧边栏菜单:推荐官方Design支持库自带的;SlidingMenu,通过拖动屏幕边缘滑出菜单,支持屏幕左右划出,支持菜单 Zoom、Scale、Slide Up 三种动画样式出现;base-adapter-helper,对传统的BaseAdapter ViewHolder 模式的一个封装,主要功能就是简化书写 AbsListView 的 Adapter 的代码,如 ListView,GridView

> 2.日志
日志记录能力:Bugly,Logger(https://github.com/orhanobut/logger);当然Logger也不是完备的,它虽然支持格式化输出JSON、XML,但并不支持诸如List、Set、Map和数组等常见Java集合类的格式化输出。如何解决呢?可以看下LogUtils (https://github.com/pengwei1024/LogUtils)这个开源库,它实现了Logger缺失的上述特性。再者,Logger只支持输出日志到Logcat,但项目开发中往往还存在将日志保存到磁盘上的需求,如何将两者结合起来呢?这是可用timber(https://github.com/JakeWharton/timber) 。日志记录模块将由timber+Logger+LogUtils组成。
Hugo,在调试版本上注解的触发方法进行日志记录。
 Thread.currentThread().getStackTrace()[5];为什么用5?我们可以知道0,1是vm,和thread调用的方法,从2开始才是我们调用的方法。Thread.currentThread().getStackTrace()[5]所在的getCallerStackTraceElement方法是在logger()中调用的,而logger是在public static void d/i/e/w 中调用。
  vm->thread->getCallerStackTraceElement->logger->i/e/w/d->目标层
  0      1                            2                                   3           4            5

> 3.数据解析,JSON解析
gson:232KB;
jackson:259+47+1229 = 1.5M;
Fastjson:417KB;
Fastjson.android:256KB;
LoganSquare:48+259 = 307KB;
HtmlPaser   一种用来解析单个独立html或嵌套html的方式;
Jsoup   一个以最好的DOM,CSS和jQuery解析html的库;

> 4.数据库,ORM框架
ORM对象关系映射之使用GreenDAO进行CRUD操作-http://blog.csdn.net/u010687392/article/details/48444417
 数据库操作能力:GreenDao,比较好的有ActiveAndroid,ormlite和greenDAO。greenDAO的运行效率最高,内存消耗最少,性能最佳。

  ORM就是把数据库表的行与相应的对象建立关联,互相转换。
activeandroid:40KB;
greendao:100KB;
ormlite-android:57KB;
realm-android:4.2M;
Sugar ,用超级简单的方法处理Android数据库;
SQLBrite ,SQLiteOpenHelper 和ContentResolver的轻量级包装;

-- GreenDao,为GreenDao建立一个Java的Module
  对象关系映射(Object Relation Mapping),是一种程序设计技术,用于实现面向对象编程语言里不同类型系统的数据之间的转换。从效果上说,它其实是创建了一个可在编程语言里使用的“虚拟对象数据库”。
  面向对象是从软件工程基本原则(如耦合、聚合、封装)的基础上发展起来的,而关系数据库则是从数学理论发展而来的.  两者之间是不匹配的.而ORM作为项目中间件形式实现数据在不同场景下数据关系映射. 对象关系映射是一种为了解决面向对象与关系数据库存在的互不匹配的现象的技术.ORM就是这样而来的。
greendao的使用- https://www.jianshu.com/p/b268264bf305
GreenDao简单使用- https://www.jianshu.com/p/b1775de60f69
GreenDaoDemo- https://github.com/gnehsuy/GreenDaoDemo

-- ORM技术中Property类,根据Key获得Value。JDK 中的 Properties 类 Properties 类存在于胞 Java.util 中,该类继承自 Hashtable ,它提供了几个主要的方法: 
   1.getProperty ( String key) ,用指定的键在此属性列表中搜索属性。也就是通过参数 key ,得到 key 所对应的 value。
  2.load ( InputStream inStream) ,从输入流中读取属性列表(键和元素对)。通过对指定的文件(比如说上面的 test.properties 文件)进行装载来获取该文件中的所有键 - 值对。以供 getProperty ( String key) 来搜索。
  3.setProperty ( String key, String value) ,调用 Hashtable 的方法 put 。他通过调用基类的put方法来设置 键 - 值对。
  4.store ( OutputStream out, String comments) ,以适合使用 load 方法加载到 Properties 表中的格式,将此 Properties 表中的属性列表(键和元素对)写入输出流。与 load 方法相反,该方法将键 - 值对写入到指定的文件中去。
  5.clear () ,清除所有装载的 键 - 值对。该方法在基类中提供。

> 5.网络通信,网络请求
网络请求:Volley,okhttp,retrofit;AsyncTask ,android-async-http
网络通信能力:Okhttp,使用Okhttp需要引入Jar包,包的大小为:326+66 = 392KB

Android面试题-OkHttp3源码分析- https://blog.csdn.net/mwq384807683/article/details/71173442?locationNum=8&fps=1
OKHttp3源码解析- https://www.jianshu.com/p/dd412b8ba43f
OKHttp 完整的封装类的地址见:https://github.com/hongyangAndroid/okhttp-utils
OkHttp拦截器的实现原理- https://www.cnblogs.com/LuLei1990/p/5534791.html
OkHttp3简单使用教程(一):请求和响应- https://www.jianshu.com/p/f3f228d3598c
OkHttp3实现原理分析(二)- https://www.jianshu.com/p/9f2c982cd500
  Interceptor 是 OkHttp 最核心的一个东西,不要误以为它只负责拦截请求进行一些额外的处理(例如 cookie),实际上它把实际的网络请求、缓存、透明压缩等功能都统一了起来,每一个功能都只是一个 Interceptor,它们再连接成一个 Interceptor.Chain,环环相扣,最终圆满完成一次网络请求。
 责任链拦截器Interceptor:

RetryAndFollowUpInterceptor:负责失败重试以及重定向;
BridgeInterceptor:负责把用户构造的请求转换为发送到服务器的请求、把服务器返回的响应转换为用户友好的响应的;
ConnectInterceptor:建立连接;
NetworkInterceptors:配置OkHttpClient时设置的 NetworkInterceptors;
CallServerInterceptor:发送和接收数据;
 Http请求行:由请求方法,URL,协议版本三部分构成,之间用空格隔开;请求方法包括:POST、GET、HEAD、PUT、POST、TRACE、OPTIONS、DELETE等;

> 6.图片下载,图片处理
图片框架:Picasso、Fresco、Glide、Android-Universal-Image-Loader
  图片缓存和显示能力:Glide,Glide和Picasso有90%的相似度,只是在细节上还是存在不少区别。Glide为包含图片的滚动列表做了尽可能流畅的优化。除了静态图片,Glide也支持GIF格式图片的显示。Glide提供了灵活的API可以让开发者方便地替换下载图片所用的网络函数库,默认情况下,它使用HttpUrlConnection作为网络请求模块,开发者也可以根据自己项目的实际需求灵活使用Google的Volley或者Square的OkHttp等函数库进行替换。
BitmapFun:71KB;
Picasso:120KB;
Glide:475KB;
Fresco:47KB+93KB+93KB+10KB+3MB+62KB+8KB+111KB = 3.4MB;
Android-Universal-Image-Loader:162KB;
  图片函数库的选择需要根据APP的具体情况而定,对于严重依赖图片缓存的APP,例如壁纸类,图片社交类APP来说,可以选择最专业的Fresco。对于一般的APP,选择Fresco会显得比较重,毕竟Fresco 3.4MB的体量摆在这。
  根据APP对图片显示和缓存的需求从低到高我们可以对以上函数库做一个排序:
BitmapFun < Picasso < Android-Universal-Image-Loader < Glide < Fresco

-- glide(底层使用了LruCache/DiskLruCache->LinkedHashMap)
图片框架glide- https://github.com/bumptech/glide
对图片进行裁剪、模糊、滤镜等处理- https://github.com/wasabeef/glide-transformations
Glide 集成 OkHttp2.x 、OkHttp3.x 和 Volley- http://blog.csdn.net/wxy318/article/details/52095913

-- Glide库图片池:
 4.4以前是Bitmap复用必须长宽相等才可以复用;4.4及以后是Size>=所需就可以复用,只不过需要调用reconfigure来调整尺寸;
 Glide用AttributeStategy和SizeStrategy来实现两种策略;图片池在收到传来的Bitmap之后,通过长宽或者Size来从KeyPool中获取Key(对象复用到了极致,连Key都用到了Pool),然后再每个Key对应一个双向链表结构来存储。每个Key下可能有很多个待用Bitmap;
 取出后要减少图片池中记录的当前Size等,并对Bitmap进行eraseColor(Color.TRANSPAENT)操作确保可用;
 - Glide加载资源:
 GlideBuilder在初始化Glide时,会生成一个执行机Engine
 Engine中包含LruCache缓存及一个当前正在使用的active资源Cache(弱引用)
 activeCache辅助LruCache,当Resource从LruCache中取出使用时,会从LruCache中remove并进入acticeCache当中
 Cache优先级LruCache>activeCache
 Engine在初始化时要传入两个ExecutorService,即会有两个线程池,一个用来从DiskCache获取resource,另一个用来从Source中获取(通常是下载)
 线程的封装单位是EngineJob,有两个顺序状态,先是CacheState,在此状态先进入DiskCacheService中执行获取,如果没找到则进入SourceState,进到SourceService中执行下载。

-- LrhCache算法的算法核心 = LRU 算法 + LinkedHashMap数据结构,LinkedHashMap数据结构 = 数组 +单链表 + 双向链表
 采用 LRU 算法的缓存类型:内存缓存(LrhCache) 、 硬盘缓存(DisLruCache)
public static void main(String[] args){
    LinkedHashMap<String, String> linkedHashMap =
            new LinkedHashMap<String, String>(16, 0.75f, true);
    linkedHashMap.put("111", "111");
    linkedHashMap.put("222", "222");
    linkedHashMap.put("333", "333");
    linkedHashMap.put("444", "444");
    loopLinkedHashMap(linkedHashMap);
    linkedHashMap.get("111");
    loopLinkedHashMap(linkedHashMap);
    linkedHashMap.put("222", "2222");
    loopLinkedHashMap(linkedHashMap);
}  
public static void loopLinkedHashMap(LinkedHashMap<String, String> linkedHashMap){
    Set<Map.Entry<String, String>> set = inkedHashMap.entrySet();
    Iterator<Map.Entry<String, String>> iterator = set.iterator();
    
    while (iterator.hasNext())
    {
        System.out.print(iterator.next() + "\t");
    }
    System.out.println();
}
代码运行结果:
111=111    222=222    333=333    444=444    
222=222    333=333    444=444    111=111    
333=333    444=444    111=111    222=2222   

总结:1、LinkedList是有序的
      2、每次访问一个元素(get或put),被访问的元素都被提到最后面去了;

-- 图片缓存的原理:实现图片缓存也不难,需要有相应的cache策略。这里采用 内存(memory)-本地(local)-网络(Internet) 三层cache机制,其中内存缓存包括强引用缓存和软引用缓存(SoftReference),其实网络不算cache,这里姑且也把它划到缓存的层次结 构中。当根据url向网络拉取图片的时候,先从内存中找,如果内存中没有,再从本地缓存文件中查找,如果缓存文件中也没有,再从网络上通过http请求拉取图 片。在键值对(key-value)中,这个图片缓存的key是图片url的hash值,value就是bitmap。所以,按照这个逻辑,只要一个 url被下载过,其图片就被缓存起来了。

-- 图片处理
Picasso-transformations 一个为Picasso提供多种图片变换的库;
Glide-transformations   一个为Glide提供多种图片变换的库;
Android-gpuimage,基于OpenGL的Android过滤器;

> 7.图表
WilliamChart,创建图表的Android库;
HelloCharts,兼容到API8的Android图表库;
MPAndroidChart,一个强大的Android图表视图/图形库;

> 8.后台处理
Tape,一个轻快的,事务性的,基于文件的FIFO的库;
Android Priority Job Queue,一个专门为Android轻松调度任务的工作队列。

> 9.事件总线
EventBus,安卓优化的事件总线,简化了活动、片段、线程、服务等的通信;
Otto,一个基于Guava的增强的事件总线;
  消息传递:EventBus.在Android开发中,组件间的通信或者前后端线程之间的通信都是通过持有引用的回调或者Handler来实现的。EventBus是近年来在Android开发中非常常用的一个通信框架,利用它可以很轻易地实现组件与组件之间的各种通信,无论跨线程与否。
 EventBus比较适合仅仅当做组件间的通讯工具使用,主要用来传递消息。使用EventBus可以避免搞出一大推的interface,仅仅是为了实现组件间的通讯,而不得不去实现那一推的接口。
  RxJava和EventBus一样也是基于观察者模式,但是使用的场景确实异步数据流的处理。
Android EventBus实战 没听过你就out了-- http://blog.csdn.net/lmj623565791/article/details/40794879
Android EventBus源码解析 带你深入理解EventBus-- http://blog.csdn.net/lmj623565791/article/details/40920453
  EventBus定义:是一个发布 / 订阅的事件总线。这么说应该包含4个成分:发布者,订阅者,事件,总线,作用是发布/订阅事件总线,因为项目中用到RxJava、RxAndroid,所以完全可以使用RxJava、RxAndroid来实现EventBus。

主线程向副线程传值和EventBus的初步使用- https://blog.csdn.net/u014265363/article/details/50775462
EventBus四种线程交付模式- https://blog.csdn.net/qq_34723470/article/details/53044100
Android开源项目EventBus3.0的使用- https://blog.csdn.net/ydxlt/article/details/50729679

> 10.响应式编程,Rxjava Rxbus
RxJava  JVM上的响应式扩展;
RxJavaJoins 为RxJava提供Joins操作;
RxAndroid   Android上的响应式扩展,在RxJava基础上添加了Android线程调度;
RxBinding   提供用RxJava绑定Android UI的API;
Agera   Android上的响应式编程;
 
  Reactive Extensions for the JVM- https://github.com/ReactiveX/RxJava
这可能是从 RxJava1 跳到 RxJava2(学习 RxJava2 )Demo- https://github.com/nanchen2251/RxJava2Examples
https://github.com/akarnokd/RxJava2Interop , https://github.com/luxiaoming/RxBusDemo
Rxbus-https://github.com/lightofrain/RxBusTest , https://github.com/luxiaoming/RxBus 

  1、RxJava有大量丰富强大的operator,可以满足用户的大部分数据处理需求。RxJava另一个强大的地方就是scheduler,用户可以为Observable和Subscriber指定不同的执行线程,在Android中可以方便的将Observable指定在IO线程中运行,Subscriber在UI线程中运行。
  2、RxJava和EventBus一样也是基于观察者模式,但是使用的场景确实异步数据流的处理。

  RxJava 有四个基本概念:Observable (可观察者,即被观察者)、 Observer (观察者)、 subscribe (订阅)、事件。Observable 和 Observer 通过 subscribe() 方法实现订阅关系,从而 Observable 可以在需要的时候发出事件来通知 Observer。
  Rx是响应式编程的意思, 本质是观察者模式, 是以观察者(Observer)和订阅者(Subscriber)为基础的异步响应方式. 在Android编程时, 经常会使用后台线程, 那么就可以使用这种方式. 

-- RxJava
 1.Observable和Subscriber可以做任何事情
Observable可以是一个数据库查询,Subscriber用来显示查询结果;Observable可以是屏幕上的点击事件,Subscriber用来响应点击事件;Observable可以是一个网络请求,Subscriber用来显示请求结果。
 2.Observable和Subscriber是独立于中间的变换过程的。
在Observable和Subscriber中间可以增减任何数量的map。整个系统是高度可组合的,操作数据是一个很简单的过程。

> 11.注解框架,依赖注入
1.bufferknife,是注解中相对简单易懂的很不错的开源框架;
2.Dragger2 依赖注入框架,注解,Dragger2解决问题的基本思想是:利用生成和写的代码混合达到看似所有的产生和提供依赖的代码都是手写的样子。
AndroidAnotations ,快速安卓开发。易于维护;
RoboGuice,Android平台的Google Guice;

> 12.缓存LRU, LruCache, DiskLruCache RobospiceJson
 LRU 是 Least Recently Used 最近最少使用算法。缓存使用DBFlow ORM框架。
曾经,在各大缓存图片的框架没流行的时候。有一种很常用的内存缓存技术:SoftReference 和 WeakReference(软引用和弱引用)。但是走到了 Android 2.3(Level 9)时代,垃圾回收机制更倾向于回收 SoftReference 或 WeakReference 的对象。后来,又来到了 Android3.0,图片缓存在内容中,因为不知道要在是什么时候释放内存,没有策略,没用一种可以预见的场合去将其释放。这就造成了内存溢出。
  LruCache 就是 利用 LinkedHashMap 的一个特性( accessOrder=true 基于访问顺序 )再加上对 LinkedHashMap 的数据操作上锁实现的缓存策略。DiskLruCache底层也使用了LinkedHashMap实现。
LruCache-https://github.com/CaMnter/AndroidLife/blob/master/app/src/main/java/com/camnter/newlife/utils/cache/LruCache.java

> 13.崩溃统计分析
Fabric 是一个先进的移动平台平台。 Crashlytics 是Fabric提供的一个崩溃统计分析平台,允许你监控你的应用的状态。

> 14.监控 推送 

 

> 15.插件化和热部署
插件化推荐DroidPlugin;
热部署推荐androidFix;

> 16.测试框架
Mockito Java编写的Mocking单元测试框架
Robotium    Android UI 测试
Robolectric Android单元测试框架
Android自带很多测试工具:JUnit,Monkeyrunner,UiAutomator,Espresso等

> 17.调试框架
Stetho  调试Android应用的桥梁,使得可以利用Chrome开发者工具进行调试

> 18.性能优化
LeakCanary  内存泄漏检测工具;
ACRA  Android应用程序崩溃报告。

------------------------------------------------------------------

> 个人开发者,接私活
码说MapReduce: http://geek.csdn.net/news/detail/92889

赚钱必看:独立开发者必知的一些总结: http://mp.weixin.qq.com/s?__biz=MjM5NDkxMTgyNw==&mid=405078751&idx=1&sn=9a0c821128ca19f67e53ddf3a4a0847b#wechat_redirect

科普技术贴:个人开发者的那些赚钱方式: http://mp.weixin.qq.com/s?__biz=MjM5NDkxMTgyNw==&mid=209744558&idx=1&sn=b88ff6edce3256e7dee2d788bd143219&scene=21#wechat_redirect

强烈推荐:程序员接私活那点事: http://mp.weixin.qq.com/s?__biz=MjM5NDkxMTgyNw==&mid=400669680&idx=1&sn=b15d90cb22f0bc715436224b9301ca61&scene=21#wechat_redirect 

绝对干货:供个人开发者赚钱免费使用的一些好的API接口: http://mp.weixin.qq.com/s?__biz=MjM5NDkxMTgyNw==&mid=400044525&idx=1&sn=04d1b413c90d0cac43788be033b2e420&scene=21#wechat_redirect

超值干货:个人开发者如何使用免费又简单的开发后台: http://mp.weixin.qq.com/s?__biz=MjM5NDkxMTgyNw==&mid=400109669&idx=1&sn=01aecde92d128623c664fdcd5335651b&scene=21#wechat_redirect

夹缝中生存的个人开发者:http://mp.weixin.qq.com/s?__biz=MjM5NDkxMTgyNw==&mid=404944969&idx=1&sn=385e9165e7355db0a25841673897a16a&scene=21#wechat_redirect

20多个可以提高你安卓开发技能的开源app- http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2017/0214/7114.html
Android 流行框架(架构App的第三方框架)- https://blog.csdn.net/feiyu_073/article/details/80043448
Android中常用的框架(从GitHub开源库中代码量来排名)- https://blog.csdn.net/ccccsky/article/details/79672586

 [墙裂推荐]Android搭建属于自己的技术堆栈和App架构- https://mp.weixin.qq.com/s?__biz=MzI0MjE3OTYwMg==&mid=2649550530&idx=1&sn=fcf00db3ec87704fa5ddbc3319687cb4&chksm=f11805bfc66f8ca95d0ded31919a18c61501903ce9aede538b5157030feeb07a50b766a8f3f9&scene=21#wechat_redirect

 Android经久不衰最受欢迎的开源库整理,你一定用过10个以上,架构师必备- https://mp.weixin.qq.com/s?__biz=MzI0MjE3OTYwMg==&mid=2649549163&idx=1&sn=d1aceb81639f77d926e1f54ec23502a1&chksm=f1180216c66f8b005ddd6c4073015bf14ad9e62dc579482af6d9858e428b221604bf922300ba&scene=21#wechat_redirect

 一种最新Android客户端架构设计分享,Android架构师必看- https://mp.weixin.qq.com/s?__biz=MzI0MjE3OTYwMg==&mid=2649548999&idx=1&sn=4486e011b3720c8e4c2ecd1503546213&chksm=f11803bac66f8aac8a23c098b594835ae71e51e48331268110bf1cbd6825c1dcf169cf2c0afc&scene=21#wechat_redirect

 20 多个可以提高你Android开发技能的国外优秀开源 app- https://mp.weixin.qq.com/s?__biz=MzI0MjE3OTYwMg==&mid=2649548906&idx=1&sn=8b23dd284bc7c9b9df52df3999159a51&chksm=f1180317c66f8a01c5fbc6cb0bc1f631e87183c8ea0661149f946c047ecf331948b8853a73a2&scene=21#wechat_redirect

 2017年,身为Android开发的你必须要掌握的热门开源框架- https://mp.weixin.qq.com/s?__biz=MzI0MjE3OTYwMg==&mid=2649548737&idx=1&sn=07e77f55fc2cbd575322b151e0a0b648&chksm=f1180cbcc66f85aa8244c17b67d9fc16388c0eb36e9c0ec6c8fcd259ced220ca0fb142a31876&scene=21#wechat_redirect

 2017年,你一定需要的25个Android第三方库- https://mp.weixin.qq.com/s?__biz=MzI0MjE3OTYwMg==&mid=2649548774&idx=1&sn=6796a60af2d480359b055dea0cdd4f20&chksm=f1180c9bc66f858db798e1ae0de3ad7cb1193a74d32a3bd8df7915584c2f9b9f91ecde8f8384&scene=21#wechat_redirect

APK魔鬼瘦身: http://mp.weixin.qq.com/s?__biz=MzA4MjU5NTY0NA==&mid=402168736&idx=1&sn=723e9fddacfecdfbeee3d3365f6d1a2f&scene=21#wechat_redirect

现在大家主流的比较喜欢用的tinypng其实是有损压缩:https://tinypng.com/

因为实现里用了Log.isLoggable(TAG, Log.VERBOSE)做了判断,在LessCode的LogLess中也参考了这种机制:https://github.com/openproject/LessCode/blob/master/lesscode-core/src/main/java/com/jayfeng/lesscode/core/LogLess.java

你应该知道的那些Android小经验- http://mp.weixin.qq.com/s?__biz=MzA4MjU5NTY0NA==&mid=404388098&idx=1&sn=8bbbba7692dca68cdda2212dec4d86c0&scene=1&srcid=0320gXPloap70ixGeYnNUaAW#wechat_redirect

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值