diff --git a/_posts/2013-08-01-android-use-sparsearray-for-performance-optimization.markdown b/_posts/2013-08-01-android-use-sparsearray-for-performance-optimization.markdown deleted file mode 100644 index 3e613f2..0000000 --- a/_posts/2013-08-01-android-use-sparsearray-for-performance-optimization.markdown +++ /dev/null @@ -1,332 +0,0 @@ ---- -layout: post -title: "Android性能优化之使用SparseArray代替HashMap" -tags: [SparseArray] -categories: [Android] ---- - -最近在重构one的项目,其中用HashMap来缓存ActivityGroup加载过的View,Eclipse给出了一个警告,之前考虑项目进度没怎么在意,这次仔细看了下提示,如下: - -{% highlight ruby %} - -Use new SparseArray (...) instead for better performance - -{% endhighlight %} - -

-意思就是说用SparseArray来替代,以获取更好的性能。对SparseArray根本不熟悉,甚至都没听过,第一感觉应该是Android提供的类,于是F3进入SparseArray的源码,果不其然,确实是Android提供的一个工具类,部分源码如下: -

- -{% highlight ruby %} - - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.util; - -import com.android.internal.util.ArrayUtils; - -/** - * SparseArrays map integers to Objects. Unlike a normal array of Objects, - * there can be gaps in the indices. It is intended to be more efficient - * than using a HashMap to map Integers to Objects. - */ -public class SparseArray implements Cloneable { - private static final Object DELETED = new Object(); - private boolean mGarbage = false; - - private int[] mKeys; - private Object[] mValues; - private int mSize; - - /** - * Creates a new SparseArray containing no mappings. - */ - public SparseArray() { - this(10); - } - - /** - * Creates a new SparseArray containing no mappings that will not - * require any additional memory allocation to store the specified - * number of mappings. - */ - public SparseArray(int initialCapacity) { - initialCapacity = ArrayUtils.idealIntArraySize(initialCapacity); - - mKeys = new int[initialCapacity]; - mValues = new Object[initialCapacity]; - mSize = 0; - } - - @Override - @SuppressWarnings("unchecked") - public SparseArray clone() { - SparseArray clone = null; - try { - clone = (SparseArray) super.clone(); - clone.mKeys = mKeys.clone(); - clone.mValues = mValues.clone(); - } catch (CloneNotSupportedException cnse) { - /* ignore */ - } - return clone; - } - - /** - * Gets the Object mapped from the specified key, or null - * if no such mapping has been made. - */ - public E get(int key) { - return get(key, null); - } - - /** - * Gets the Object mapped from the specified key, or the specified Object - * if no such mapping has been made. - */ - @SuppressWarnings("unchecked") - public E get(int key, E valueIfKeyNotFound) { - int i = binarySearch(mKeys, 0, mSize, key); - - if (i < 0 || mValues[i] == DELETED) { - return valueIfKeyNotFound; - } else { - return (E) mValues[i]; - } - } - - /** - * Removes the mapping from the specified key, if there was any. - */ - public void delete(int key) { - int i = binarySearch(mKeys, 0, mSize, key); - - if (i >= 0) { - if (mValues[i] != DELETED) { - mValues[i] = DELETED; - mGarbage = true; - } - } - } - - /** - * Alias for {@link #delete(int)}. - */ - public void remove(int key) { - delete(key); - } - - /** - * Removes the mapping at the specified index. - */ - public void removeAt(int index) { - if (mValues[index] != DELETED) { - mValues[index] = DELETED; - mGarbage = true; - } - } - ... - -{% endhighlight %} - - mSize++;单纯从字面上来理解,SparseArray指的是稀疏数组(Sparse array),所谓稀疏数组就是数组中大部分的内容值都未被使用(或都为零),在数组中仅有少部分的空间使用。因此造成内存空间的浪费,为了节省内存空间,并且不影响数组中原有的内容值,我们可以采用一种压缩的方式来表示稀疏数组的内容。 - -继续阅读SparseArray的源码,从构造方法我们可以看出,它和一般的List一样,可以预先设置容器大小,默认的大小是10: - -{% highlight ruby %} - -public SparseArray() { - this(10); -} - -public SparseArray(int initialCapacity) { - initialCapacity = ArrayUtils.idealIntArraySize(initialCapacity); - - mKeys = new int[initialCapacity]; - mValues = new Object[initialCapacity]; - mSize = 0; -} - -{% endhighlight %} - -再来看看它对数据的“增删改查”。 - -{% highlight ruby %} - -public void put(int key, E value) {} -public void append(int key, E value){} - -{% endhighlight %} - -修改数据起初以为只有setValueAt(int index, E value)可以修改数据,但后来发现put(int key, E value)也可以修改数据,我们查看put(int key, E value)的源码可知,在put数据之前,会先查找要put的数据是否已经存在,如果存在就是修改,不存在就添加。 - -{% highlight ruby %} - -public void put(int key, E value) { - int i = binarySearch(mKeys, 0, mSize, key); - - if (i >= 0) { - mValues[i] = value; - } else { - i = ~i; - - if (i < mSize && mValues[i] == DELETED) { - mKeys[i] = key; - mValues[i] = value; - return; - } - - if (mGarbage && mSize >= mKeys.length) { - gc(); - - // Search again because indices may have changed. - i = ~binarySearch(mKeys, 0, mSize, key); - } - - if (mSize >= mKeys.length) { - int n = ArrayUtils.idealIntArraySize(mSize + 1); - - int[] nkeys = new int[n]; - Object[] nvalues = new Object[n]; - - // Log.e("SparseArray", "grow " + mKeys.length + " to " + n); - System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length); - System.arraycopy(mValues, 0, nvalues, 0, mValues.length); - - mKeys = nkeys; - mValues = nvalues; - } - - if (mSize - i != 0) { - // Log.e("SparseArray", "move " + (mSize - i)); - System.arraycopy(mKeys, i, mKeys, i + 1, mSize - i); - System.arraycopy(mValues, i, mValues, i + 1, mSize - i); - } - - mKeys[i] = key; - mValues[i] = value; - - } -} - -{% endhighlight %} - -所以,修改数据实际也有两种方法: - -{% highlight ruby %} -public void put(int key, E value) -public void setValueAt(int index, E value) -{% endhighlight %} - -最后再来看看如何查找数据。有两个方法可以查询取值: - -{% highlight ruby %} -public E get(int key) -public E get(int key, E valueIfKeyNotFound) -{% endhighlight %} - -其中get(int key)也只是调用了 get(int key,E valueIfKeyNotFound),最后一个从传参的变量名就能看出,传入的是找不到的时候返回的值.get(int key)当找不到的时候,默认返回null。 - -查看第几个位置的键: - -{% highlight ruby %} -public int keyAt(int index) -{% endhighlight %} - -有一点需要注意的是,查看键所在位置,由于是采用二分法查找键的位置,所以找不到时返回小于0的数值,而不是返回-1。返回的负值是表示它在找不到时所在的位置。 - -查看第几个位置的值: - -{% highlight ruby %} -public E valueAt(int index) -{% endhighlight %} - -查看值所在位置,没有的话返回-1: - -{% highlight ruby %} -public int indexOfValue(E value) -{% endhighlight %} - -最后,发现其核心就是折半查找函数(binarySearch),算法设计的很不错。 - -{% highlight ruby %} -private static int binarySearch(int[] a, int start, int len, int key) { - int high = start + len, low = start - 1, guess; - - while (high - low > 1) { - guess = (high + low) / 2; - - if (a[guess] < key) - low = guess; - else - high = guess; - } - - if (high == start + len) - return ~(start + len); - else if (a[high] == key) - return high; - else - return ~high; -} - -相应的也有SparseBooleanArray,用来取代HashMap,SparseIntArray用来取代HashMap,大家有兴趣的可以研究。 - -{% endhighlight %} - -## 总结 - -{% highlight ruby %} - -SparseArray是android里为这样的Hashmap而专门写的类,目的是提高效率,其核心是折半查找函数(binarySearch)。在Android中,当我们需要定义 - HashMap hashMap = new HashMap(); -时,我们可以使用如下的方式来取得更好的性能. - SparseArray sparseArray = new SparseArray(); - -{% endhighlight %} - -最后,看看重构后的ActivityGroupManager: - -{% highlight ruby %} - -public class ActivityGroupManager { - static final String TAG = ActivityGroupManager.class.getName(); - - private SparseArray array; - private ViewGroup container; - - public ActivityGroupManager() { - array = new SparseArray(); - } - - public void setContainer(ViewGroup container) { - this.container = container; - } - - public void showContainer(int num, View view) { - if (array.get(num) == null) { - array.put(num, view); - container.addView(view); - } - for (int i = 0; i < array.size(); i++) { - View v = array.valueAt(i); - v.setVisibility(View.GONE); - } - view.setVisibility(View.VISIBLE); - } -} - -{% endhighlight %} \ No newline at end of file diff --git a/_posts/2016-07-31-android-developer-weekly-no-3.md b/_posts/2016-07-31-android-developer-weekly-no-3.md new file mode 100644 index 0000000..64c174c --- /dev/null +++ b/_posts/2016-07-31-android-developer-weekly-no-3.md @@ -0,0 +1,88 @@ +--- +layout: post +keywords: blog +description: blog +title: "AndroidDeveloper Weekly No.3" +categories: [Weekly] +tags: [AndroidDeveloper] +--- +{% include codepiano/setup %} + +## 好文 + +- [如何发现优秀的开源项目?](http://stormzhang.com/github/2016/07/28/learn-github-from-zero7/) + +- [PathMeasure之谜径追踪](http://blog.csdn.net/eclipsexys/article/details/51992473) + +- [Google I/O 2016 笔记之图像压缩](http://hlong.xyz/2016/07/11/Google%20IO%202016%20%E7%AC%94%E8%AE%B0%E4%B9%8B%E5%9B%BE%E5%83%8F%E5%8E%8B%E7%BC%A9/) + +- [Android消息处理机制:Handler、Message](http://shaohui.me/2016/07/15/Android%E6%B6%88%E6%81%AF%E5%A4%84%E7%90%86%E6%9C%BA%E5%88%B6%EF%BC%9AHandler-Message/) + +- [Android Activity 生命周期是如何实现的](http://www.woaitqs.cc/android/2016/07/19/how-activity-lifecircle-work.html) + +## 优秀开源项目 + +- [ticker](https://github.com/robinhood/ticker) + +一个动画效果酷炫的 TextView + +![](https://github.com/robinhood/ticker/raw/master/assets/ticker_main.gif) + +- [circular-music-progressbar](https://github.com/aliab/circular-music-progressbar) + +一个漂亮的 CD 唱片进度条 + +![](https://raw.githubusercontent.com/aliab/circular-music-progressbar/master/art/splash.jpg) + +- [CNode-Material-Design](https://github.com/TakWolf/CNode-Material-Design) + +CNode社区第三方Android客户端,原生App,Material Design风格,支持夜间模式 + +![](https://github.com/TakWolf/CNode-Material-Design/raw/develop/art/banner-1024-500.png) + +- [Tinker_imitator](https://github.com/zzz40500/Tinker_imitator) + +微信热更新方案实践 + +![](https://raw.githubusercontent.com/zzz40500/Tinker_imitator/master/screenshot/img.png) + +- [SeatTable](https://github.com/qifengdeqingchen/SeatTable) + +电影票在线选座 + +![](https://github.com/qifengdeqingchen/SeatTable/raw/master/demo.gif) + +- [DecentBanner](https://github.com/chengdazhi/DecentBanner) + +Flipboard 的轮播组件 + +![](https://github.com/chengdazhi/DecentBanner/raw/master/images/decent_sample.gif) + +- [android_scratchoff](https://github.com/jackpocket/android_scratchoff) + +刮刮卡效果 + +![](https://github.com/jackpocket/android_scratchoff/raw/master/scratchoff.gif) + +- [jetbrains-wakatime](https://github.com/wakatime/jetbrains-wakatime) + +一款 IDE 的插件,可以记录你使用 IDE 的时长。 + +![](https://camo.githubusercontent.com/0263e365a2efdb5dc0adb4b7aba6a783bc17a92e/68747470733a2f2f77616b6174696d652e636f6d2f7374617469632f696d672f53637265656e53686f74732f53637265656e2d53686f742d323031362d30332d32312e706e67) + +## 大事件 + +- AndroidDeveloper 公众号被人投诉 + +本周最大的事件莫过于全球知名微信公众号 AndroidDeveloper 被小人投诉,致使被取消原创功能一周,本周内不能赞赏与留言,据悉该事件已耽误作者上千万的收入,作者身价已从几十亿一落千丈,最重要的是作者的精神状态感觉身体被掏空,寝食难安,严重影响了世界和平,目前作者已向微信发起申诉。好在今天赞赏、留言已全面恢复,请大家多多赞赏与留言夸作者帅,帮助作者 stormzhang 从抑郁中走出来,为维护世界和平出点力! + +- 冠希哥手撕志玲姐 + +这事闹的沸沸扬扬,但是跟上面那件事比不值一提,就不多说了! + +
+ +> 本文原创发布于微信公众号 **AndroidDeveloper「googdev」**,转载请务必注明出处! + +![图片描述](/image/weixinpublic.jpg) + diff --git a/_posts/2016-08-05-android-open-source-project-recommend2.md b/_posts/2016-08-05-android-open-source-project-recommend2.md new file mode 100644 index 0000000..ffcc465 --- /dev/null +++ b/_posts/2016-08-05-android-open-source-project-recommend2.md @@ -0,0 +1,129 @@ +--- +layout: post +keywords: blog +description: blog +title: "Android开源项目推荐之「网络请求哪家强」" +categories: [OpenSource] +tags: [Http] +--- +{% include codepiano/setup %} + + +不少人老催这个系列,好吧,今天就更新一篇干货给你们。网络请求这个话题基本是所有 App 开发都会遇到的,这也难怪之前很多人留言让我写写网络请求到底该怎么选择,今天就来说说网络请求到底哪家强! + + +## 1. 原则 + + +本篇说的网络请求专指 http 请求,在选择一个框架之前,我个人有个习惯,就是我喜欢选择专注的库,其实在软件设计领域有一个原则叫做 「单一职责原则」,跟我所说的「专注」不谋而合,一个库能把一件事做好就很不错了。现如今有很多大而全的库,比如这个库可以网络请求,同时又可以图片加载,又可以数据存储,又可以 View 注解等等,我们使用这种库当然方便了,但是你有没有想过?这样会使得你整个项目对它依赖性太强,万一以后这个库不维护了,或者中间某个模块出问题了,这个影响非常大,而且我一直认为大而全的框架可能某一块都做的不够好,所以我在选择的时候更喜欢专注某一领域的框架。 + + +在上面原则的基础上,所以目前来说单纯的网络请求库就锁定在了 Volley、OkHttp、Retrofit 三个,android-async-http 的作者已经不维护,所以这里就不多说了,下面我们分别来说说这三个库的区别。 + + + +## 2. OkHttp + + +我们知道在 Android 开发中是可以直接使用现成的 api 进行网络请求的,就是使用 HttpClient、HttpUrlConnection 进行操作,目前 HttpClient 已经被废弃,而 android-async-http 是基于 HttpClient 的,我想可能也是因为这个原因作者放弃维护。 + + +而 OkHttp 是 Square 公司开源的针对 Java 和 Android 程序,封装的一个高性能 http 请求库,所以它的职责跟 HttpUrlConnection 是一样的,支持 spdy、http 2.0、websocket ,支持同步、异步,而且 OkHttp 又封装了线程池,封装了数据转换,封装了参数使用、错误处理等,api 使用起来更加方便。可以把它理解成是一个封装之后的类似 HttpUrlConnection 的一个东西,但是你在使用的时候仍然需要自己再做一层封装,这样才能像使用一个框架一样更加顺手。 + + +OkHttp 的具体使用方法这里就不赘述,地址在这里: + + +[http://square.github.io/okhttp/](http://square.github.io/okhttp/) + + + +## 3. Volley + + +Volley 是 Google 官方出的一套小而巧的异步请求库,该框架封装的扩展性很强,支持 HttpClient、HttpUrlConnection,甚至支持 OkHttp,具体方法可以看 Jake 大神的这个 Gist 文件: + + +[https://gist.github.com/JakeWharton/5616899](https://gist.github.com/JakeWharton/5616899) + + +而且 Volley 里面也封装了 ImageLoader ,所以如果你愿意你甚至不需要使用图片加载框架,不过这块功能没有一些专门的图片加载框架强大,对于简单的需求可以使用,对于稍复杂点的需求还是需要用到专门的图片加载框架。 + + +Volley 也有缺陷,比如不支持 post 大数据,所以不适合上传文件。不过 Volley 设计的初衷本身也就是为频繁的、数据量小的网络请求而生! +关于 Volley 的具体用法可以见我很早在 GitHub 的一个 demo : + + +[https://github.com/stormzhang/AndroidVolley](https://github.com/stormzhang/AndroidVolley ) + + + +## 4. Retrofit + + +Retrofit 是 Square 公司出品的默认基于 OkHttp 封装的一套 RESTful 网络请求框架,不了解 RESTful 概念的不妨去搜索学习下,RESTful 可以说是目前流行的一套 api 设计的风格,并不是标准。Retrofit 的封装可以说是很强大,里面涉及到一堆的设计模式,你可以通过注解直接配置请求,你可以使用不同的 http 客户端,虽然默认是用 http ,可以使用不同 Json Converter 来序列化数据,同时提供对 RxJava 的支持,使用 Retrofit + OkHttp + RxJava + Dagger2 可以说是目前比较潮的一套框架,但是需要有比较高的门槛。 + +Retrofit 的具体使用方法与地址在这里: + + +[http://square.github.io/retrofit/](http://square.github.io/retrofit/) + + + +## 5. Volley VS OkHttp + + +毫无疑问 Volley 的优势在于封装的更好,而使用 OkHttp 你需要有足够的能力再进行一次封装。而 OkHttp 的优势在于性能更高,因为 OkHttp 基于 NIO 和 Okio ,所以性能上要比 Volley更快。 + + +估计有些读者不理解 IO 和 NIO 的概念,这里姑且简单提下,这两个都是 Java 中的概念,如果我从硬盘读取数据,第一种方式就是程序一直等,数据读完后才能继续操作,这种是最简单的也叫阻塞式 IO,还有一种就是你读你的,我程序接着往下执行,等数据处理完你再来通知我,然后再处理回调。而第二种就是 NIO 的方式,非阻塞式。 + + +所以 NIO 当然要比 IO 的性能要好了, 而 Okio 是 Square 公司基于 IO 和 NIO 基础上做的一个更简单、高效处理数据流的一个库。 + + +理论上如果 Volley 和 OkHttp 对比的话,我更倾向于使用 Volley,因为 Volley 内部同样支持使用 OkHttp ,这点 OkHttp 的性能优势就没了,而且 Volley 本身封装的也更易用,扩展性更好些。 + + + +## 6. OkHttp VS Retrofit + + +毫无疑问,Retrofit 默认是基于 OkHttp 而做的封装,这点来说没有可比性,肯定首选 Retrofit。 + + + +## 7. Volley VS Retrofit + + +这两个库都做了非常不错的封装,但是 Retrofit 解耦的更彻底,尤其 Retrofit 2.0 出来,Jake 对之前 1.0 设计不合理的地方做了大量重构,职责更细分,而且 Retrofit 默认使用 OkHttp ,性能上也要比 Volley 占优势,再有如果你的项目如果采用了 RxJava ,那更该使用 Retrofit 。 + + +所以说这两个库相比,Retrofit 毫无疑问更有优势,你在能掌握两个框架的前提下该优先使用 Retrofit。但是个人认为 Retrofit 门槛要比 Volley 稍高些,你要理解他的原理,各种用法,想彻底搞明白还是需要花些功夫的,如果你对它一知半解,那还是建议在商业项目使用 Volley 吧。 + + + +## 8. 总结 + + +所以综上,如果以上三种网络库你都能熟练掌握,那么优先推荐使用 Retrofit ,前提是最好你们的后台 api 也能遵循 RESTful 的风格,其次如果你不想使用或者没能力掌握 Retrofit ,那么推荐使用 Volley ,毕竟 Volley 你不需要做过多的封装,当然如果你们需要上传大数据,那么不建议使用 Volley,否则你该采用 OkHttp 。 + + +最后,我知道可能有些人会纠结 Volley 与 OkHttp 的选择,那是因为我认为 OkHttp 还是需要一定的能力做一层封装的,如果你有能力封装的话那不如直接用 Retrofit 了,如果没能力封装还是乖乖的用 Volley 吧,如果你能有一些不错的基于 OkHttp 封装好的开源库,那么另说了,Volley 与 OkHttp 怎么选择随你便呗。 + + +最最后,以上只是我一家之言,如有误导,概不负责!欢迎讨论与交流。 + +#### 相关文章 + +[Android开源项目推荐之「图片加载到底哪家强」](http://stormzhang.com/opensource/2016/06/26/android-open-source-project-recommend1/) + + +
+ +> 本文原创发布于微信公众号 **AndroidDeveloper「googdev」**,转载请务必注明出处! + +![图片描述](/image/weixinpublic.jpg) + + + \ No newline at end of file diff --git a/_posts/2016-08-08-android-developer-weekly-no-4.md b/_posts/2016-08-08-android-developer-weekly-no-4.md new file mode 100644 index 0000000..18aae00 --- /dev/null +++ b/_posts/2016-08-08-android-developer-weekly-no-4.md @@ -0,0 +1,82 @@ +--- +layout: post +keywords: blog +description: blog +title: "AndroidDeveloper Weekly No.4" +categories: [Weekly] +tags: [AndroidDeveloper] +--- +{% include codepiano/setup %} + +## 好文 + +- [Android开发人员不得不收集的代码(持续更新中)](http://www.jianshu.com/p/72494773aace) + +- [Android开源项目推荐之「网络请求哪家强」](http://stormzhang.com/opensource/2016/08/05/android-open-source-project-recommend2/) + +- [一个五年Android 开发者百度、阿里、聚美、映客的面试心经](http://www.diycode.cc/topics/165) + +- [Android开发各类常见错误解决方案](http://www.jianshu.com/p/c5db81cbc438) + +- [打造最强RecyclerView Item侧滑菜单 长按拖拽Item 滑动删除Item](http://blog.csdn.net/yanzhenjie1003/article/details/52115566) + +## 优秀开源项目 + +- [Luban](https://github.com/Curzibn/Luban) + +可能是最接近微信朋友圈的图片压缩算法 + + + +- [MaterialLogin](https://github.com/fanrunqi/MaterialLogin) + +Amazing Material Login effect + +![](https://raw.githubusercontent.com/fanrunqi/MaterialLogin/master/screenshots/this.gif) + +- [FunGameRefresh](https://github.com/Hitomis/FunGameRefresh) + +有趣好玩的下拉刷新库, 你还记得小时候打的黑白掌上游戏机么? + +![](https://github.com/Hitomis/FunGameRefresh/raw/master/preview/HitBlock.gif) +![](https://github.com/Hitomis/FunGameRefresh/raw/master/preview/BattleCity.gif) + +- [ThumbUp](https://github.com/ldoublem/ThumbUp) + +点赞还能这么玩! + +![](https://github.com/ldoublem/ThumbUp/raw/master/screenShot/shot.gif) + +- [TastyToast](https://github.com/yadav-rahul/TastyToast) + +Make your native android Toasts Tasty + +![](https://github.com/yadav-rahul/TastyToast/raw/lib/static/success.gif) +![](https://github.com/yadav-rahul/TastyToast/raw/lib/static/warning.gif) +![](https://github.com/yadav-rahul/TastyToast/raw/lib/static/error.gif) + +- [ExpandableRecyclerview](https://github.com/zaihuishou/ExpandableRecyclerview) + +An ExpandableRecycleradapter with Recyclerview + +![](https://github.com/zaihuishou/ExpandableRecyclerview/raw/master/sample-screen.gif) + +- [PullToRefresh](https://github.com/lubeast/PullToRefresh) + +一款有意思的下拉刷新 + +![](https://camo.githubusercontent.com/f390437ba548be66a9e4c91389e5587000533c24/68747470733a2f2f7261772e6769746875622e636f6d2f6c7562656173742f50756c6c4c61756e6368526f636b65742f6d61737465722f73637265656e73686f74732f726f636b65742e676966) + +## 大事件 + +- 2016 巴西里约奥运会 + +本周最大的事件莫过于四年一次的 2016 巴西里约奥运会正式开始,终于又有熬夜的理由了,俗话说:不爱体育的程序员不是好段子手,看奥运不只是看哪个国家获得奖牌最多,这里同时还是见证人类极限的地方,让我们一起为中国健儿加油,为奥运加油! + +
+ +> 本文原创发布于微信公众号 **AndroidDeveloper「googdev」**,转载请务必注明出处! + +![图片描述](/image/weixinpublic.jpg) + + diff --git a/_posts/2016-08-12-you-must-use-google.md b/_posts/2016-08-12-you-must-use-google.md new file mode 100644 index 0000000..06934ed --- /dev/null +++ b/_posts/2016-08-12-you-must-use-google.md @@ -0,0 +1,115 @@ +--- +layout: post +title: "你为什么一定要使用 Google ?" +--- +{% include codepiano/setup %} + +了解我的人知道,我是一个不折不扣的「百度黑」,在魏则西事件发生之后第一时间在微信上写了篇文章被疯转,为此也背了不少骂名,很多人骂我一点不客观,完全就是为了紧跟舆论,站在道德制高点,显示自己高尚罢了! + +然而很早关注我的人知道,我号召大家尽量不要使用百度不是一天两天了,远在魏则西事件之前就开始了,我一再强调,身为一个技术人,如果你不用 Google ,那么你真的太 low 了,如果只是单纯的谩骂就太苍白无力了,今天咱们就来摆事实,讲道理! + +## 我的经历 + +先说说我自己的经历吧: + +我自己是11年毕业,非计算机专业学渣,学校里上网就干两件事,看电影、打游戏,唯一知道的搜索引擎就是百度。第一份工作是测试,当时第一家公司十来个人,是做 .NET 开发的,就我一个测试,也是在这里我第一次知道程序员这个职业,这里的所有程序员都是在使用百度搜索解决问题,我一直觉得这没什么问题。 + +我在这家公司干了 8 个月,期间自学 Android 觉得差不多了,于是离职,准备找一份专职开发的工作。直到我加入了现在的公司,我发现这里都用 Google 的,我特么第一次接触 Google ,原来世界上还有另一个搜索引擎! + +那个时候貌似访问 Google 还不用翻墙,可以直接访问 Google HK ,但是出于习惯,我懒得改变,我还是习惯用百度搜索,当时市面上一些资料非常少,分享氛围也远没有现在这么好,我在做开发的过程中遇到种种困难,其中一个现象就是一个知识点我百度搜出来的结果都是千篇一律,都是这个博客抄那个博客的内容,而且很多知识点根本都没有实践,我曾不止一次被误导过,也就是那个时候,促使我开始写博客,而且一定要认真写,不管如何,自己写的东西一定是自己实践过的,把这些宝贵的经验总结出来对后来人有点帮助,没想到这一写坚持到现在就写了 4 年多。 + +做开发大概了一段时间,直到有一天我们 CTO 突然发现我搜索是用的百度,很惊讶,对我说:“你竟然用百度,做技术的用百度基本搜不到什么有用的东西,以后一定要用 Google ”。迫于压力,我之后就开始试着用 Google ,一开始很不习惯,因为自己英文很差,用 Google 搜索的结果很多都是英文,现在想想都觉得很可笑,在最开始我都是直接过滤掉英文搜索结果,只看中文结果。 + +直到有一次,遇到一个难题,用 Google 搜了很多中文结果都没能解决,抱着试试的状态,我试着用英文关键字搜索,点到第一条,这一下就看到了一个神奇的网站 Stackoverflow ,是的,就是这个网站的回答直接就解决了我的问题,简直像发现新大陆般,从此都是英文关键字搜索,彻底抛弃了百度,而 80% 以上的问题 StackOverFlow 都可以直接帮你解决。 + +再之后,我用 Google 发现了 GitHub ,接触了开源社区,Google + Stackoverflow + GitHub 就再也没有解决不了的问题了,而某种意义上,开发其实主要就是解决问题的能力! + +## 翻墙 + +具体不晓得突然哪一天 Google 彻底不能访问了,具体原因就不说了,这一下就炸了锅,根本就没法工作嘛,公司小伙伴们开始研究各种翻墙工具,从免费的 Goagent ,到自己搭建 VPS ,再到付费的 VPN ,总之是尝试了各种方法,只有翻墙了,你才能发现外面的世界有多精彩,如 Youtube 上 Google 的很多官方的教学视频, Google Plus 上很多大牛的技术交流,FB、Twitter 就不多说了。 + +如果说别的方向不能翻墙还好,身为 Android Developer 的我们,如果不会科学上网,那么真是说不过去。出于众所周知的原因, Android 官网,Android 开发工具,Android 官方博客统统访问不了,如果你不会翻墙,甚至你连下载开发工具都很难,所以无论如何,你都该拥有科学上网的能力。 + +曾经不少人让我推荐靠谱的翻墙工具,这里我不好推荐。因为这件事本身国家就睁一只眼闭一只眼,你做大了很可能就会找你麻烦,所以你们看不到有哪家公司到处打广告推广 VPN 的,而且即使不找你麻烦,如果我推荐了,用的人多了,速度、稳定性会越来越差。我只能跟你们说一句话:付费的肯定比免费的好。有些人总觉得有一种免费好用的方式,这个世界上永远没有免费午餐,又免费,又好用,又快,又稳定的根本不存在,如果你们真的不知道有哪些科学上网的方式,之后我可以考虑整理一下,但是具体选择哪一个你们自己决定。 + +## 摆事实,讲道理 + +有人可能会质疑,以上都是你一个人的经历而已,并不具代表性,我不用 Google 不也是活的好好的么?OK ,为了更具说服力,咱们就来用摆事实,讲道理。百度号称中文搜索最牛逼,那么咱们就拿中文搜索来做比较: + +- 搜索:android学习之路 + +咱们就不妨搜索下我那篇最火的博客,这篇博客帮助了无数刚入门的 Android 初学者,很多人给我反馈不少大学、培训机构都拿我这篇博客来做教学课程,咱们分别用百度和 Google 搜索看下结果: + +百度的结果: + + +![图片描述](/image/baidu_android.png) + +Google 的结果: + + +![图片描述](/image/google_android.png) + +看到没有,百度搜索的结果第一屏几乎全他妈是广告,而且比较隐蔽,这结果你告诉我你是一个搜索引擎?我们都是成年人,并不排斥你打广告,毕竟一家商业公司总要赚钱的。但是你这广告提示的能不能再隐蔽些?而且数量多的太令人发指了,现在还只是出过各种事情收敛之后的结果,可想而知没出事之前的搜索结果得有多恐怖。 + +而广告下面的结果妈蛋全是一些无良网站转载的,这些网站转载我的文章从没有跟我打过招呼,有些甚至都没有标明原文出处,而这篇文章最原始的出处却无影踪。 + +再看 Google 的搜索结果,毫无疑问我博客最原始的出处被放在了第一位,而且没有各种繁杂的广告。这结果对比显而易见! + +- 搜索:ios开发教程 + +有人又问我,你是不是拿你这篇博客说事呢?好,那么咱们不妨再来随意搜索几个跟我不相关的东西,就搜索关键字:ios开发教程,这几个关键字是我随意取的,而且跟我没任何关系,咱们看下各自的搜索结果: + +百度的结果: + +![图片描述](/image/baidu_ios.png) + +Google 的结果: + + +![图片描述](/image/google_ios.png) + +看到没有,百度同样的第一屏全是广告,恨不得第一页的结果全部打上广告,再看 Google 返回的结果,都是 GitHub、知乎、慕课网等非常有用的回答与教程。其他关键字,你们不妨自己亲自尝试比较下搜索结果。 + +以上只是拿百度最擅长的中文搜索做比较,并且只是技术类的话题,如果其他类别的话题,广告更多,而且用英文关键字搜索,Google 的结果会更准确! + +## 请努力改变 + +有些人说了,道理我都懂,可我英文差啊! + +我自己英文也很差,英语四级考了 3 次才考过,我身边好多英语四级没过的照样顺畅使用 Google ,而且 Google 搜索根本用不到太高深的英文水平,毕竟不是考试,遇到不会的单词借助一些翻译工具就行了,一开始确实不习惯,但是相信我,两周之后,你就会习惯。那些一再强调自己英文差而不愿使用的人说到底是你不愿改变罢了,因为改变需要学习成本,而你懒得学习。 + +现在大环境是 Google 全套服务在国内被屏蔽,这个我们没有能力去改变,但是只要你想,你总能想办法去克服。不过乐观点看,正是因为被屏蔽了,某种意义上才把技术人划分了等级。可以这么说,会使用 Google 的不一定是优秀的技术人,但是不会使用 Google 的一定不是优秀的技术人! + +还有不少读者可能会说,我现在才刚起步,处于初级水平,觉得用百度就够了。 + +然而我却不这么认为,正是因为你是初级水平,如果不把起点定高点,那你怎么能从众多初学者中脱颖而出?怎么能追赶上那些有经验的人?一开始就使用 Google ,去 Stackoverflow 解决问题,去查询官方 api ,去 GitHub 多看别人优秀的开源项目,比别人的起点高,才能逼着你适应,才能逼着你有更快的进步! + +## 总结 + +说了这么多,肯定有人会问?就会装逼,百度接广告怎么了?我不信你不用百度? + +我从始至终都没说我不用百度,而且百度接广告这件事也没错,这个世界靠情怀,是存活不下去的,别说百度了,包括我自己也没那么高尚,没人会跟钱过不去,我有时候也会在公号接点广告,也很希望你们赞赏、点广告支持原创,但是我接的广告一定是正规的,而且会主动告诉读者是广告,百度错的是太无底线,一直号称用户体验至上,然而搜索结果满屏的广告,你告诉我你们重视用户体验?更有甚者为了钱接一些无良广告,不考虑后果,有些甚至威胁到人的生命,而且这种事情不是一次两次,至今看不到任何改进的迹象。 + +所以我才会成为一个「百度黑」,可以这么说,迄今为止我好几次拒绝了百度的洗白与推广,现在是,以后也是。对于一些龌龊行为我没法改变,但是我起码可以做到让更多的人知道。 + +不过单纯从搜索结果来说,百度并不是一无是处,比如在查询一些八卦、新闻、娱乐方面确实比 Google 好用,毕竟本土资源优势,所以客观的说,我现在并不是完全不用百度! + +然而作为技术人,在查询一些专业知识、资料文献方面的请一定要用 Google ,这完全是两个世界,这是我作为过来人对你们的一点建议,也是我的一点忠告,相信我,如果你是因为看了这篇文章才开始使用的 Google ,那么以后你一定会很感谢我! + + +最后,作为了一名技术人,请大家一定要使用 Google ,虽然现在被墙,但是我坚信终有一天 Google 会回归,也许十年之后,也许五十年之后... + + +**如果可以,我愿意牺牲我的帅,来换取 Google 的回归!** + + +
+ +> 本文原创发布于微信公众号 **AndroidDeveloper「googdev」**,转载请务必注明出处! + +![图片描述](/image/weixinpublic.jpg) + + + + diff --git a/_posts/2016-08-21-android-studio-live-templates.md b/_posts/2016-08-21-android-studio-live-templates.md new file mode 100644 index 0000000..b84207e --- /dev/null +++ b/_posts/2016-08-21-android-studio-live-templates.md @@ -0,0 +1,86 @@ +--- +layout: post +keywords: blog +description: blog +title: "让你变懒的 Android Studio Live Templates" +--- +{% include codepiano/setup %} + +俗话说,不想偷懒的程序员不是好程序员!那么今天就教大家偷懒下! + +先举个例子,我们在 Android 开发中输入 *Toast* ,然后会有如下如下的快速操作: + +![](/image/live_templates1.gif) + +是不是很方便? + +有同学问,这不就是自动补全么?错了,乍一看是自动补全,其实不然。自动补全是对一个方法或类名的补全,比如你输入 *find* 然后就会有 *findViewById* 方法提示你,你可以快速定位,但是我们实际开发中一般还需要对它强制转型,然后加上 *R.id.xx* 来声明它的 id,但是你可以试着输入 *fbc* ,然后按 *tab* 或者 *enter* 键,你会发现比自动补全还要更方便。 + +这个就叫做 *Live Template* ,如果真要翻译姑且就叫做实时模板吧,在 AS 中有两种模板,一种就是你在新建一个 Activity 的时候可以选择 Empty Activity、FullScreen Activity 之类的,这个一般是对你整个文件而言的,还有一种就是本篇要介绍的 *Live Template* ,这个会在一些常用到的代码片段会非常有用。 + +打开 *设置 -> Editor -> Live Templates* ,可以看到默认已经有很多 *Live Templates* 了,可以看下我的截图 Android 分类下有如下这些模板: + +![](/image/live_templates2.png) + +你都可以输入那些缩写来快速启用这些模板,比如定义一个常量,快速设置 View 为 gone ,快速启动一个 Activity 等,你都可以直接输入 *const*、*gone*、*starter* 来快速操作,是不是觉得很酷炫! + +那具体是如何实现的呢?我们不妨点击这些模板列表的 *starter* ,有如下代码: + +``` ruby +public static void start(Context context) { + Intent starter = new Intent(context, $ACTIVITY$.class); + starter.putExtra($CURSOR$); + context.startActivity(starter); +} +``` + +其中 *$ACTIVITY$* 代表当前所在的类名,*$CURSOR$* 代表当前鼠标的定位位置,同理 *newInstance* 可以帮你在 Fragment 中快速声明一个新建 Fragment 的方法,它的代码如下: + +``` ruby +public static $fragment$ newInstance($args$) { + $nullChecks$ + Bundle args = new Bundle(); + $addArgs$ + $fragment$ fragment = new $fragment$(); + fragment.setArguments(args); + return fragment; +} +``` +其中 *$$* 代表是一个变量,中间包裹着这个变量的名字,你可以对这个变量声明类型,这个后面再说。 + +是不是很容易理解呢?如果理解了那么就可以来根据自己的使用习惯来定义自己的 *Live Templates* 了。 + +比如我们在开发中要经常写单例模式吧?每次都要写这么一大段是不是很烦?那么今天就教大家自定义一个单例模式的模板,以后轻松搞定单例。 + +到 *设置 -> Editor -> Live Templates* ,点击右上角的 + 号,选择 Template Group ,因为我习惯自定义的单独分组先,这样好管理,比如新建一个分组叫做 *stormzhang* ,然后就会看到有一个 *stormzhang* 的分组显示在了列表里,这时候鼠标选中该分组,然后再点击右上角的 + 号,点击 *Live Template* ,然后如下图填写缩写与描述,紧接着把如下代码拷贝到下面的输入框里(PS:单例模式的写法有很多种,这里就随意以其中一种为例) + +``` ruby +private static $CLASS$ instance = null; + +private $CLASS$(){ +} + +public static $CLASS$ getInstance() { + synchronized ($CLASS$.class) { + if (instance == null) { + instance = new $CLASS$(); + } + } + + return instance; +} +``` +注意这里,如果你这段代码是一些固定的代码,那么至此就结束了,但是这段代码里是动态的,里面有一些变量,因为每个类的类名如果都需要自己手动更改就太麻烦了,所以有个变量 *$CLASS$* ,所以需要点击下面的 *Define* ,先要定义变量所属的语言范围,点开之后可以看到这里支持 HTML、XML、JSON、Java、C++ 等,很明显,我们这里需要支持 Java ,选择选中 Java : + +![](/image/live_templates3.png) + +紧接着,我们需要给变量 *$CLASS$* 定义类型,这里的 *CLASS* 名字随意取的,为了可读性而已,你高兴可以取名 *abc* ,真正给这个变量定义类型的是点击 *Edit variables* 按钮,来对该变量进行编辑,我们选择 *className()* 选项,可以看到还有其他选项,但是看名字大家大概就猜到什么含义了,这里就不一一解释了。 + +![](/image/live_templates4.png) + +点击 *ok* 保存,至此我们定义的一个单例的 Live Template 就完成了。你可以随意打开一个类文件,然后输入 *singleton* 按 *tab* 或者 *enter* 键就可以看到神奇的一幕出现了,是不是很帅? + +看完这篇文章想想自己还有哪些常用到的代码片段,赶紧把它定义成一个 Live Template 吧,你会发现你又可以变懒了! + + + diff --git a/baidu_verify_PGGW8nCqcr.html b/baidu_verify_PGGW8nCqcr.html new file mode 100644 index 0000000..8f0f401 --- /dev/null +++ b/baidu_verify_PGGW8nCqcr.html @@ -0,0 +1 @@ +PGGW8nCqcr \ No newline at end of file diff --git a/image/baidu_android.png b/image/baidu_android.png new file mode 100644 index 0000000..cb93a08 Binary files /dev/null and b/image/baidu_android.png differ diff --git a/image/baidu_ios.png b/image/baidu_ios.png new file mode 100644 index 0000000..607f098 Binary files /dev/null and b/image/baidu_ios.png differ diff --git a/image/google.png b/image/google.png new file mode 100644 index 0000000..27ece4a Binary files /dev/null and b/image/google.png differ diff --git a/image/google_android.png b/image/google_android.png new file mode 100644 index 0000000..d72c116 Binary files /dev/null and b/image/google_android.png differ diff --git a/image/google_ios.png b/image/google_ios.png new file mode 100644 index 0000000..3c978dd Binary files /dev/null and b/image/google_ios.png differ diff --git a/image/live_templates1.gif b/image/live_templates1.gif new file mode 100644 index 0000000..05e0c7d Binary files /dev/null and b/image/live_templates1.gif differ diff --git a/image/live_templates2.png b/image/live_templates2.png new file mode 100644 index 0000000..d4da080 Binary files /dev/null and b/image/live_templates2.png differ diff --git a/image/live_templates3.png b/image/live_templates3.png new file mode 100644 index 0000000..34f773f Binary files /dev/null and b/image/live_templates3.png differ diff --git a/image/live_templates4.png b/image/live_templates4.png new file mode 100644 index 0000000..a603a01 Binary files /dev/null and b/image/live_templates4.png differ diff --git a/image/pic_zip.png b/image/pic_zip.png new file mode 100644 index 0000000..d47e849 Binary files /dev/null and b/image/pic_zip.png differ diff --git a/index.md b/index.md index 0c7fa38..40846af 100644 --- a/index.md +++ b/index.md @@ -9,13 +9,14 @@ categories: [Android] ## 每周推荐 -[如何发现优秀的开源项目?](http://stormzhang.com/github/2016/07/28/learn-github-from-zero7/) +[AndroidDeveloper Weekly No.4](http://stormzhang.com/weekly/2016/08/08/android-developer-weekly-no-4/) + +[Android开源项目推荐之「网络请求哪家强」](http://stormzhang.com/opensource/2016/08/05/android-open-source-project-recommend2/) -[AndroidDeveloper Weekly No.2](http://stormzhang.com/weekly/2016/07/25/android-developer-weekly-no-2/) +[如何发现优秀的开源项目?](http://stormzhang.com/github/2016/07/28/learn-github-from-zero7/) [给 Android 初学者的 Gradle 知识普及](http://stormzhang.com/android/2016/07/02/gradle-for-android-beginners/) -[我的知乎专栏 AndroidDeveloper](https://zhuanlan.zhihu.com/stormzhang) * 我的微信公众号: AndroidDeveloper「googdev」 (专注Android的原创分享,关注并回复googdev自学Android资料免费获取)