+```
+
+通过 Behavior.setTag()/Behavior.getTag() 可以保存临时数据,onSaveInstanceState()/onRestoreInstanceState() 可以保存 Behavior 相关的实例状态。虽说我建议你创建自己的 Behavior,但这些方法让你能够创建状态性 Behavior。
+
+##关联 Behavior
+
+当然,Behavior 不能单干 - 它需要绑定到 CoordinatorLayout 的子元素才能被使用,下面是关联的三种办法。
+
+###通过代码绑定
+
+你可能觉得 Behavior 是 CoordinatorLayout 给每个 View 添加的某种额外属性/其他的东西,但如果我告诉你 Behavior 是每个 View 的 LayoutParams 存储的内容,请不要太惊讶 - 这也是 Behavior 必须关联到 CoordinatorLayout 子元素上的原因,因为只有它们才有 LayoutParams 中对应的属性。
+
+```java
+FancyBehavior fancyBehavior = new FancyBehavior();
+CoordinatorLayout.LayoutParams params =
+ (CoordinatorLayout.LayoutParams) yourView.getLayoutParams();
+params.setBehavior(fancyBehavior);
+```
+
+在这种情况下,你会使用默认构造方法,当然,你也可以给构造方法设置任何你想要的参数 - 反正代码在手,天下我有嘛。
+
+###通过 xml 绑定
+
+不过不得不说,每次都用代码去完成绑定的工作有一丢丢麻烦,就像大多数自定义 LayoutParams,我们也有相应的
+layout_ 属性去设置 Behavior:
+
+```xml
+
+```
+
+此时会调用 FancyBehavior(Context context, AttributeSet attrs) 构造方法,也就意味着可以声明任意自定义属性,然后在代码中获得这些属性,如果你想通过 xml 自定义 Behavior 的功能,这个办法就变得很棒了。
+
+> Note: 与使用 layout_ 类似,你也可以使用 behavior_ 指定 Behavior 使用的属性。
+
+###自动绑定
+
+如果你创建了需要自定义 Behavior 的自定义 View,那你可能想让该 View 绑定默认的 Behavior,而不用在每次使用时在代码或 xml 中声明。为了实现这个特性,代码需要改成下面这样:
+
+```java
+@CoordinatorLayout.DefaultBehavior(FancyFrameLayoutBehavior.class)
+public class FancyFrameLayout extends FrameLayout {
+}
+```
+
+这样就会自动绑定 Behavior 了,相当于 layout_behavior 默认设置为 DefaultBehavior。
+
+##拦截点击事件
+
+一旦自定义 Behavior 开发完成,就可以用它完成一些任务了,例如拦截点击事件。
+
+不使用 CoordinatorLayout,总是需要创建 ViewGroup 的子类才能得到点击事件。但有了 CoordinatorLayout,就能在 Behavior 里调用 onInterceptTouchEvent() 以控制 CoordinatorLayout 的 onInterceptTouchEvent(),使 Behavior 能拦截点击事件。通过返回 true,Behavior 就能获取所有点击事件,这就是 SwipeDismissBehavior 的原理。
+
+在 blocksInteractionBelow() 方法中返回 true,就会阻塞所有事件传递的交互,拦截所有事件。当然了,你可能希望得到一些视觉上的信号让你知道交互产生的事件都被阻塞了(最起码要让用户知道 App 崩溃了) - 这也是 blocksInteractionBelow() 的默认功能依赖于 getScrimOpacity() 的值的原因 - getScrimOpacity() 方法返回一个非 0 的值,以在 View 上绘制覆盖颜色(getScrimColor() 方法返回对应的颜色,默认是黑色),而且一下子禁止了所有点击事件。很方便。
+
+##拦截窗口插入
+
+我先假设你读过“Why would I want to fitsSystemWindows”,在博文中我们讨论了 fitsSystemWindows 到底干了啥,但说穿了他就是让你得到避免在系统窗口下绘制的窗口插入(例如状态栏和导航栏)。如果 fitsSystemWindows=“true”,那么任何绑定的 Behavior 都会调用 onApplyWindowInsets(),让 Behavior 具有比 View 更高的优先级。
+
+> Note: 大多数情况下,Behavior 不会消耗所有的窗口插入,窗口插入应该通过 ViewCompat.dispatchApplyWindowInsets() 传递,以确保所有子 View 都有机会接触窗口插入。
+
+##拦截 Measurement 和 Layout
+
+Measurement 和 Layout 是 Android 绘制机制的关键部分,这也意味着 Behavior 作为一切的拦截者,能够通过 onMeasureChild() 和 onLayoutChild() 回调先于 CoordinatorLayout 进行 measurement 和 layout 。
+
+例如,让 Behavior 接受任意类型的 ViewGroup,并添加 maxWidth:
+
+```java
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * 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 com.example.behaviors;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.support.design.widget.CoordinatorLayout;
+import android.util.AttributeSet;
+import android.view.ViewGroup;
+
+import static android.view.View.MeasureSpec;
+
+/**
+ * Behavior that imposes a maximum width on any ViewGroup.
+ *
+ * Requires an attrs.xml of something like
+ *
+ *
+ * <declare-styleable name="MaxWidthBehavior_Params">
+ * <attr name="behavior_maxWidth" format="dimension"/>
+ * </declare-styleable>
+ *
+ */
+public class MaxWidthBehavior extends CoordinatorLayout.Behavior {
+ private int mMaxWidth;
+
+ public MaxWidthBehavior(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ TypedArray a = context.obtainStyledAttributes(attrs,
+ R.styleable.MaxWidthBehavior_Params);
+ mMaxWidth = a.getDimensionPixelSize(
+ R.styleable.MaxWidthBehavior_Params_behavior_maxWidth, 0);
+ a.recycle();
+ }
+
+ @Override
+ public boolean onMeasureChild(CoordinatorLayout parent, V child,
+ int parentWidthMeasureSpec, int widthUsed,
+ int parentHeightMeasureSpec, int heightUsed) {
+ if (mMaxWidth <= 0) {
+ // No max width means this Behavior is a no-op
+ return false;
+ }
+ int widthMode = MeasureSpec.getMode(parentWidthMeasureSpec);
+ int width = MeasureSpec.getSize(parentWidthMeasureSpec);
+
+ if (widthMode == MeasureSpec.UNSPECIFIED || width > mMaxWidth) {
+ // Sorry to impose here, but max width is kind of a big deal
+ width = mMaxWidth;
+ widthMode = MeasureSpec.AT_MOST;
+ parent.onMeasureChild(child,
+ MeasureSpec.makeMeasureSpec(width, widthMode), widthUsed,
+ parentHeightMeasureSpec, heightUsed);
+ // We've measured the View, so CoordinatorLayout doesn't have to
+ return true;
+ }
+
+ // Looks like the default measurement will work great
+ return false;
+ }
+}
+```
+
+泛型 Behavior 固然好用,但你要记住,不是所有 Behavior 都应该是泛型的。
+
+##理解 View 间依赖
+
+上述所有功能只需要一个 View,但 Behavior 的魔力真正来源于在 View 间建立以来 - 例如,当另一个 View 发生改变,Behavior 获得回调,基于外部条件改变其功能。
+
+Behavior 可以通过两种方式依赖于 View:当一个 View 被锚定到其他 View 上(被实现的依赖)或在 layoutDependsOn() 方法中返回 true。
+
+使用 CoordinatorLayout 的 layout_anchor 属性就可以完成锚定。此外,再使用 layout_anchorGravity 属性,你可以有效地将两个 View 的位置绑定在一起。例如,将 FAB 锚定到 AppBarLayout 中,此时 FloatingActionButton.Behavior 会通过隐式依赖,在 AppBarLayout 滚动到屏幕可见范围之外时隐藏自身。
+
+不管怎样,Behavior 都会在依赖的 View 被移除时获得 onDependentViewRemoved() 回调,而且只要依赖 View 发生了改变,onDependentViewChanged() 回调也会被触发。(例如改变自身大小,或者改变位置)
+
+将 View 绑定在一起的能力就是 Design Library 实现这么多酷炫效果的秘密 - 举例来说吧,FAB 和 Snackbar 的交互,FAB 的 Behavior 依赖于添加到 CoordinatorLayout 中的 Snackbar,通过调用 onDependentViewChanged() 回调就可以将 FAB 移动到 Snackbar 的上面,避免覆盖。
+
+> Note: 当你添加依赖,View 总会在被依赖 View 被放置后被放置,无论其布局关系如何。
+
+##嵌套滚动
+
+对于嵌套滚动,下面几件事你需要记住:
+1. 不需要在 NestedScrollView 中声明依赖,因为 CoordinatorLayout 的每一个子元素都能够获得 NestedScrollView 中的滚动事件
+2. NestedScrollView 不仅仅能应用于 CoordinatorLayout 的直接子元素,而能应用到 CoordinatorLayout 中的任意 View 上(CoordinatorLayout 的子布局的子布局的子布局的子布局……)
+3. 虽说我把它叫做嵌套滚动,但实际上它能滚动和挥动
+
+在 onStartNestedScroll() 方法中处理你感兴趣的嵌套滚动事件吧,你能在这得到滚动的坐标轴(例如水平和垂直坐标轴 - 不用在意到底在哪个方向发生了滚动),为了获得该方向上随后的滚动事件,必须返回 true。
+
+onStartNestedScroll() 返回 true 后,嵌套滚动会按如下步骤运行:
+
+- onNestedPreScroll() 在 ScrollView 获得滚动事件前被调用,允许 Behavior 消耗一部分或所有滚动事件(最后被消耗的滚动事件是 int[] out 参数,也就是你能得到你消耗了什么事件的参数)
+- onNestedScroll() 在滚动 View 滚动时被调用 - 你可以得到 View 已经滚动了多远以及还有多少没有滚动。
+
+此外,还有与挥动操作等价的情况(即使挥动前的回调必须消耗所有非挥动的滚动事件,或不消耗任何一个)。
+
+当嵌套滚动(挥动)结束,获得 onStopNestedScroll() 的回调调用,该回调标记了滚动的结束 - 同时期望下一次滚动发生前得到新的 onStartNestedScroll() 调用。
+
+例如,你想在向下滚动时隐藏 FAB,向上滚动时显示 FAB - 实现这个功能将涉及 onStartNestedScroll() 和 onNestedScroll(),就像 ScrollAwareFABBehavior 中实现的那样。
+
+###而这只是开始
+
+Behavior 的每一个部分都很有趣,把它们组合起来就能对界面施行魔法,让界面变得酷炫。我强烈建议大家去看看 Design Library 的源码以发现更多更高级的 Behavior - Android SDK 搜索的 Chrome 拓展一直是我最爱的 Android 开源项目源码。
diff --git "a/issue-43/\351\201\277\345\205\215Android\345\272\224\347\224\250\345\206\267\345\220\257\345\212\250\351\227\256\351\242\230.md" "b/issue-43/\351\201\277\345\205\215Android\345\272\224\347\224\250\345\206\267\345\220\257\345\212\250\351\227\256\351\242\230.md"
new file mode 100644
index 00000000..3638b952
--- /dev/null
+++ "b/issue-43/\351\201\277\345\205\215Android\345\272\224\347\224\250\345\206\267\345\220\257\345\212\250\351\227\256\351\242\230.md"
@@ -0,0 +1,182 @@
+避免Android应用冷启动问题
+---
+
+> * 原文链接 : [Avoiding cold starts on Android](http://saulmm.github.io/avoding-android-cold-starts)
+* 原文作者 : [Saúl Molinero](http://saulmm.github.io/)
+* 译文出自 : [开发技术前线 www.devtf.cn](http://www.devtf.cn)
+* 转载声明: 本译文已授权[开发者头条](http://toutiao.io/download)享有独家转载权,未经允许,不得转载!
+* 译者 : [chaossss](https://github.com/chaossss)
+* 校对者: [chaossss](https://github.com/chaossss)
+* 状态 : 完成
+
+
+
+在过去的几周里,Android 开发者社区有人在讨论 Android 应用的冷启动问题(即启动应用时有一段时间屏幕不显示内容,背景全为白/黑),在本篇博文中,我将解释解决这个问题是否必要,以及如何解决它以使用户得到最好的使用体验。
+
+本篇博文涉及的代码可以在 [Github](https://github.com/saulmm/onboarding-examples-android)
+ 看到。
+
+##应用的冷启动问题
+
+Colt McAnlis(Google 的一名工程师)再次开启了一个讨论帖来讨论有关 Splash/Launch 启动页面的正确用法,讨论的主题和 Cyril Mottier 之前开启的讨论相同,大体是说为什么我们在开发的时候应该避免使用 Splash 启动页。讨论的冲突点在于一部分人认为 Splash 启动页破坏了用户体验,增加了应用的体积等等……
+
+在我看来,用户在使用应用时,应用的内容应该尽可能快呈现给用户,但当用户启动某个应用,Android 内核总会创建一个进程,使得屏幕不可避免地显示黑/白(取决于应用的 theme 或入口 Activity 的 theme)。
+
+应用本身越复杂,或应用使用的 Application 类被重写过以需要完成更多的任务(如初始化数据分析,错误报告,等等……)时,这段时间会变得更长。
+
+![](https://github.com/saulmm/OnboardingSample/blob/master/art/airbnb.gif?raw=true)
+
+Airbnb 在初始化时就会像上图那样留白
+
+对用户来说,这样的界面显然不是他们想要看到的。假如应用的加载时间很长,我们可以通过 placeholder 用一些内容去填充它,或者显示 Logo 以加强品牌印象。
+
+![](https://github.com/saulmm/OnboardingSample/blob/master/art/aliexpress.gif?raw=true)
+
+AliExpress 在初始化时会显示其 Logo
+
+##你的新帮手,windowBackground
+
+就像我们之前讨论的,在进程处于加载状态时,WindowManager 显示的 Window 由应用的 theme 决定其显示内容,准确地说,是由 android:windowBackground 的值决定的。就像 [Ian Lake](https://plus.google.com/+AndroidDevelopers/posts/Z1Wwainpjhd) 的这篇博文所提到的,如果我们为该属性设置 元素,该元素使用 MainActivity 的背景颜色,并在屏幕中间显示一个 Pizza 图像,可以实现下面的效果:
+
+![](https://github.com/saulmm/OnboardingSample/blob/master/art/simple.gif?raw=true)
+
+```xml
+
+
+
+
+ -
+
+
+
+```
+
+这里要将 的 android:opacity 属性设置为 opaque,使 为不透明的,要不然会出现一些问题,请读者记住这一点。此外,Activity 的布局背景应该填充了某个颜色,不然的话 会留在你的 Activity 中。
+
+```xml
+
+
+
+
+
+```
+
+##自定义启动页
+
+利用 windowBackground 属性可以给用户更好的体验。如果应用很复杂,那么可以显示一个独特的 Activity 来完成登录操作或进行选择操作,利用图片和动画可以实现下面这个酷炫的效果:
+
+![](https://github.com/saulmm/OnboardingSample/blob/master/art/center.gif?raw=true)
+
+该动画在竖直方向上移动 ImageView,该 ImageView 包含了 元素。
+
+```java
+ViewCompat.animate(logoImageView)
+ .translationY(-250)
+ .setStartDelay(STARTUP_DELAY)
+ .setDuration(ANIM_ITEM_DURATION).setInterpolator(
+ new DecelerateInterpolator(1.2f)).start();
+```
+
+
+从效果图可以看到,ImageView 要稍微高于屏幕的中心点,实际位置会受 SystemBar 的大小影响,在这里我为它设置了 12dp 的顶部间距,差不多是状态栏高度的一半。
+
+```java
+
+```
+
+##自定义 placeholder
+
+使用 可以创建 placeholder 以显示 MainActivity 的内容,例如,可以通过 模仿 Toolbar。
+
+![](https://github.com/saulmm/OnboardingSample/blob/master/art/toolbar_placeholder.png?raw=true)
+
+```xml
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+```
+
+其中,第二个 - 模仿真正要被显示到屏幕上的 Toolbar,甚至我们可以将它的高度设置为 Toolbar 的高度(宽度小于状态栏一点点),应用一些酷炫的动画到 Toolbar,给用户更好的体验,效果图:
+
+![](https://github.com/saulmm/OnboardingSample/blob/master/art/placeholder.gif?raw=true)
+
+```java
+private void collapseToolbar() {
+ int toolBarHeight;
+ TypedValue tv = new TypedValue();
+ getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, true);
+ toolBarHeight = TypedValue.complexToDimensionPixelSize(
+ tv.data, getResources().getDisplayMetrics());
+
+ ValueAnimator valueHeightAnimator = ValueAnimator
+ .ofInt(mContentViewHeight, toolBarHeight);
+
+ valueHeightAnimator.addUpdateListener(
+ new ValueAnimator.AnimatorUpdateListener() {
+
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ ViewGroup.LayoutParams lp = mToolbar.getLayoutParams();
+ lp.height = (Integer) animation.getAnimatedValue();
+ mToolbar.setLayoutParams(lp);
+ }
+ });
+
+ valueHeightAnimator.start();
+ valueHeightAnimator.addListener(
+ new AnimatorListenerAdapter() {
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ super.onAnimationEnd(animation);
+
+ // Fire recycler animator
+ mAdapter.addAll(ModelItem.getFakeItems());
+
+ // Animate fab
+ ViewCompat.animate(mFab).setStartDelay(600)
+ .setDuration(400).scaleY(1).scaleX(1).start();
+
+ }
+ });
+}
+```
\ No newline at end of file
diff --git "a/issue-45/IndeterminateProgressbar\350\247\243\346\236\220-Part 3.md" "b/issue-45/IndeterminateProgressbar\350\247\243\346\236\220-Part 3.md"
new file mode 100644
index 00000000..5674d6c4
--- /dev/null
+++ "b/issue-45/IndeterminateProgressbar\350\247\243\346\236\220-Part 3.md"
@@ -0,0 +1,224 @@
+IndeterminateProgressbar解析-Part 3
+---
+
+> * 原文链接 : [Indeterminate – Part 3](https://blog.stylingandroid.com/indeterminate-part-3/)
+* 原文作者 : [Mark Allison](blog.stylingandroid.com)
+* 译文出自 : [开发技术前线 www.devtf.cn](http://www.devtf.cn)
+* 转载声明: 本译文已授权[开发者头条](http://toutiao.io/download)享有独家转载权,未经允许,不得转载!
+* 译者 : [chaossss](https://github.com/chaossss)
+* 校对者: [chaossss](https://github.com/chaossss)
+* 状态 : 完成
+
+
+
+Indeterminate ProgressBars are a useful tool for communicating to our users that an operation is in progress when we cannot predict how long it is likely to take. Previously on Styling Android we’ve covered how to create a backwardly compatible approximation of the material styled horizontal indeterminate ProgressBar but we haven’t looked at the circular form – in this series we’ll create an approximation of the material circular indeterminate ProgressBar which will be backwardly compatible to API 11 (Honeycomb).
+
+Previously we’ve taken a deep dive in to the Lollipop+ implementation of the material circular indeterminate drawable, and now we’ll turn our attention to actually creating our own.
+
+First we’ll look at the actual Drawable component (which is analogous to the VectorDrawable we looked at in AOSP) that is responsible for actually drawing the circular component (or a section of one, at least). We can’t use VectorDrawable because it’s Lollipop+ only and VectorDrawableCompat isn’t ready for serious use (at the time of writing). But we can use good, old-fashioned Canvas and Paint to do what we need.
+
+Let’s first of all look at how we construct it:
+
+```java
+public class IndeterminateDrawable extends Drawable implements Animatable {
+ private static final int STROKE_WIDTH = 6;
+ private static final int PADDING = 3;
+
+ private final Paint paint;
+ private final RectF bounds;
+ private final float padding;
+ private float startAngle;
+ private float endAngle;
+ private float rotation;
+ private Animator animator;
+
+ public static IndeterminateDrawable newInstance(Context context) {
+ DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
+ float strokeWidthPx = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, STROKE_WIDTH, displayMetrics);
+ float paddingPx = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, PADDING, displayMetrics);
+ Paint paint = createPaint(fetchAccentColour(context), strokeWidthPx);
+ RectF bounds = new RectF();
+ float padding = strokeWidthPx / 2 + paddingPx;
+ IndeterminateDrawable drawable = new IndeterminateDrawable(paint, bounds, padding);
+ drawable.createAnimator();
+ return drawable;
+ }
+
+ @ColorInt
+ private static int fetchControlColour(Context context) {
+ TypedArray typedArray = context.obtainStyledAttributes(0, new int[]{R.attr.colorControlActivated});
+ try {
+ return typedArray.getColor(0, 0);
+ } finally {
+ typedArray.recycle();
+ }
+ }
+
+ static Paint createPaint(@ColorInt int colour, float strokeWidth) {
+ Paint paint = new Paint();
+ paint.setColor(colour);
+ paint.setStyle(Paint.Style.STROKE);
+ paint.setStrokeWidth(strokeWidth);
+ paint.setAntiAlias(true);
+ paint.setStrokeCap(Paint.Cap.SQUARE);
+ return paint;
+ }
+
+ IndeterminateDrawable(Paint paint, RectF bounds, float padding) {
+ this.paint = paint;
+ this.bounds = bounds;
+ this.padding = padding;
+ }
+
+ private void createAnimator() {
+ startAngle = 0;
+ endAngle = 270;
+ animator = new AnimatorSet();
+ }
+ .
+ .
+ .
+}
+```
+
+First we determine the pixel values for the stroke width and internal padding of the drawable to closely match those used my the actual material drawable. It is important to convert these from DIP to PX values based upon the DisplayMetrics at runtime to ensure that we can consistency across displays with differing densities.
+
+Next we create a Paint object with the necessary colour and stroke width which will be used to actually draw the section of the circle. We can retrieve the correct colour from the theme by performing the appropriate lookup (we’re using the Design support library so this will honour the values in our Theme).
+
+It’s important to turn on anti-aliasing on the Paint otherwise we’ll get some lovely jaggy edges. Also we set a square cap on the path which mimics what is set for the pathData in the material VectorDrawable that we looked at earlier in the series.
+
+We also create a RectF object which we’ll use later on. Both the Paint and RectF objects will be used in the onDraw() method and we create them in advance and re-use them each time onDraw() is called to avoid any object creation and keep our onDraw() implementation as lean and clean as possible to ensure that we don’t drop any frames in the animations.
+
+Next we actually create the IndeterminateDrawable instance itself before calling createAnimator() to construct the animations. This is currently a dummy implementation which just sets some static default values. We’ll get the the Animators in due course!
+
+Because we subclass Drawable, we need to override some abstract methods:
+
+```java
+public class IndeterminateDrawable extends Drawable implements Animatable {
+ .
+ .
+ .
+ @Override
+ public void setAlpha(int alpha) {
+ paint.setAlpha(alpha);
+ }
+
+ @Override
+ public void setColorFilter(ColorFilter colorFilter) {
+ paint.setColorFilter(colorFilter);
+ }
+
+ @Override
+ public int getOpacity() {
+ return paint.getAlpha();
+ }
+ .
+ .
+ .
+}
+```
+
+We just need to apply changes to our Paint object as needed.
+
+Because we implement Animatable we also need to override some methods to control the animation state:
+
+```java
+public class IndeterminateDrawable extends Drawable implements Animatable {
+ .
+ .
+ .
+ @Override
+ public void start() {
+ animator.start();
+ }
+
+ @Override
+ public void stop() {
+ animator.end();
+ }
+
+ @Override
+ public boolean isRunning() {
+ return animator.isRunning();
+ }
+ .
+ .
+ .
+}
+```
+
+Once again we delegate these only to the Animator this time.
+
+We now need to implement some setters which will be used by the Animators later to change the parameters of the Drawable in order to animate it:
+
+```java
+public class IndeterminateDrawable extends Drawable implements Animatable {
+ .
+ .
+ .
+ public void setStartAngle(float startAngle) {
+ this.startAngle = startAngle;
+ invalidateSelf();
+ }
+
+ public void setEndAngle(float endAngle) {
+ this.endAngle = endAngle;
+ invalidateSelf();
+ }
+
+ public void setRotation(float rotation) {
+ this.rotation = rotation;
+ invalidateSelf();
+ }
+ .
+ .
+ .
+}
+```
+
+If you’ve read the previous article in this series these should be fairly self-explanatory – we are going to use animators to dynamically change the start and end of the sweep, and also rotate the whole thing.
+
+Finally we have our onDraw():
+
+```java
+public class IndeterminateDrawable extends Drawable implements Animatable {
+ .
+ .
+ .
+ @Override
+ public void draw(Canvas canvas) {
+ bounds.set(padding, padding, canvas.getWidth() - padding, canvas.getHeight() - padding);
+ canvas.drawArc(bounds, rotation + startAngle, endAngle - startAngle, false, paint);
+ }
+}
+```
+
+This is really simple! First we populate the RectF bounds object that we created earlier with the dimensions of the Canvas taking in to account the internal padding. Then we draw an arc within these bounds and set the start and end angles according to the values set. We also add the rotation to the start angle and this will effectively rotate everything. This will get rendered using the Paint object that we set up earlier.
+
+Actually using this in our Activity is pretty easy. We include a View in our layout (I’ve used an ImageView in the example code) and then construct the IndeterminateDrawable, and start the animations in exactly the same way as you would start and AnimatedVectorDrawable:
+
+```java
+public class MainActivity extends AppCompatActivity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+
+ ImageView imageView = (ImageView) findViewById(R.id.image);
+ IndeterminateDrawable drawable = IndeterminateDrawable.newInstance(this);
+ imageView.setImageDrawable(drawable);
+ drawable.start();
+ }
+}
+```
+
+If we run this we can see that we get a static three quarters of a circle drawn because of the default values that we use in place of the animator construction:
+
+![](https://i2.wp.com/blog.stylingandroid.com/wp-content/uploads/2016/01/static_IndeterminateDrawable.png?resize=300%2C225&ssl=1)
+
+Just before we finish it is worth pointing out that there are some known issues with drawArc in the Skia library which Android uses to render things. Eugenio Marletti has [described these in detail](https://medium.com/@workingkills/the-mysterious-case-of-who-killed-arcs-on-android-9155f49166b8#.2uznv5mun) and his post is well worth a read. However, we’re only drawing a single arc here so I’m not bothered about the slight rendering discrepancies – they simply won’t be apparent in this case.
+
+In the next article we’ll turn our attention to the Animators which will bring this to life!
+
+The source code for this article is available [here](https://github.com/StylingAndroid/Indeterminate/tree/Part3).
\ No newline at end of file
diff --git "a/issue-45/\344\275\277\347\224\250\345\217\215\345\260\204\345\210\260\345\272\225\344\274\232\345\257\271\346\200\247\350\203\275\351\200\240\346\210\220\345\244\232\345\244\247\345\275\261\345\223\215\357\274\237.md" "b/issue-45/\344\275\277\347\224\250\345\217\215\345\260\204\345\210\260\345\272\225\344\274\232\345\257\271\346\200\247\350\203\275\351\200\240\346\210\220\345\244\232\345\244\247\345\275\261\345\223\215\357\274\237.md"
new file mode 100644
index 00000000..6f57c5e9
--- /dev/null
+++ "b/issue-45/\344\275\277\347\224\250\345\217\215\345\260\204\345\210\260\345\272\225\344\274\232\345\257\271\346\200\247\350\203\275\351\200\240\346\210\220\345\244\232\345\244\247\345\275\261\345\223\215\357\274\237.md"
@@ -0,0 +1,99 @@
+使用反射到底会对性能造成多大影响?
+---
+
+> * 原文链接 : [How Slow is Reflection in Android?](http://blog.nimbledroid.com/2016/02/23/slow-Android-reflection.html)
+* 原文作者 : [Anton Krasov](http://blog.nimbledroid.com/)
+* 译文出自 : [开发技术前线 www.devtf.cn](http://www.devtf.cn)
+* 转载声明: 本译文已授权[开发者头条](http://toutiao.io/download)享有独家转载权,未经允许,不得转载!
+* 译者 : [chaossss](https://github.com/chaossss)
+* 校对者: [chaossss](https://github.com/chaossss)
+* 状态 : 完成
+
+
+
+(So far we’ve analyzed a lot of apps and discovered a handful of issues that significantly slow down many apps. Starting from this post, we’ll describe these issues one by one.)
+
+Reflection is, of course, an extremely useful aspect of Java and Android development. Yet it turns out that reflection can very often be the source of significant slowdown within an Android application. Perhaps the most intuitive way of understanding this is going through a couple of real-life examples.
+
+##Two Real-world Examples
+
+Our first example involves NYTimes Android app. With the help of NimbleDroid, our friends at NYTimes found out that the reflective type adapters in Gson cost their Android app a 700ms startup delay. They eventually fixed this delay with manually written custom type adapters.
+
+Our second example involves Photobucket, a large photo-sharing platform. Here, reflection again causes a big bottleneck.
+
+![](http://blog.nimbledroid.com/assets/slow-android-reflection/com.photobucket.android-iricle-graph-top.png)
+660ms for call com.photobucket.api.client.jersey.UserClient constructor
+
+We see that the com.photobucket.api.client.jersey.UserClient constructor takes an entire 660ms to run. Looking further into the icicle graph, we see that the reason for such a lag lies in reflection. Check this out:
+
+![](http://blog.nimbledroid.com/assets/slow-android-reflection/com.photobucket.android-iricle-graph-bottom.png)
+
+lots of reflection calls, like: java.lang.Class.getGenericInterfaces
+
+Note that the getGenericInterfaces() method returns the types of the interfaces that this class directly implements. Here, it is invoked 5 times and takes ~81ms. Sure, on the surface this may not seem like much, but altogether, use of the method is causing ~600ms of start time delay. Let’s take a deeper look at why this is taking so long.
+
+It turns out that this library allows developers to configure a REST client with annotations. The issue is that the library doesn’t process the annotations during build time, but instead parses and creates the REST client during runtime (with the help of reflection). From a performance point of view, this is catastrophic.
+
+##Micro-benchmarks
+
+We’ve created a simple test to quantify how slow reflection is.
+
+We will work with the android.app.Activity class and repeat operations 10,000 times, like this:
+
+```java
+Class> clazz = android.app.Activity.class;
+for (int i = 0; i < 10000; i++) {
+ clazz.getFields();
+}
+```
+
+We’ve also set up two tests that include creating objects (of the type DummyItem, an empty dummy class) to look at the overhead purely caused by reflection. Here’s an example:
+
+```java
+try {
+ for (int i = 0; i < 1_000_000; i++) {
+ DummyItem.class.newInstance();
+ }
+} catch (InstantiationException e) {
+ e.printStackTrace();
+} catch (IllegalAccessException e) {
+ e.printStackTrace();
+}
+```
+
+And here are our results (all numbers are in ms, measured on our personal devices with real usage to make the results more faithful to real world):
+
+||NEXUS 5 (6.0) ART|GALAXY S5 (5.0) ART|GALAXY S3 mini (4.1.2) Dalvik|
+|getFields|1108|1626|27083|
+|getDeclaredFields|347|951|7687|
+|getGenericInterfaces|16|23|2927|
+|getGenericSuperclass|247|298|665|
+|makeAccessible|14|147|449|
+|getObject|21|167|127|
+|setObject|21|201|161|
+|createDummyItems|312|358|774|
+|createDummyItemsWithReflection 1332|6384|2891|
+
+It’s evident that reflection in Android is excruciatingly slow - compare the (1332ms, 6384ms, 2891ms) with reflection to the (312ms, 358ms, 774ms) without reflection. Interestingly, Android 5.0 ART on a more powerful device actually makes reflection much slower than Android 4.1 Dalvik on a less powerful device; only in Android 6.0 ART is the overhead reduced, but the overhead is still quite significant.
+
+##More real-world examples
+
+ActiveAndroid is another library that uses reflection. Let’s take a look at how it can affect start time by analyzing some real apps on the Play store:
+
+Here’s the Scribd app:
+
+![](http://blog.nimbledroid.com/assets/slow-android-reflection/Scribd.png)
+
+1093ms for call com.activeandroid.ActiveAndroid.initialize
+
+Myntra sees similar problems:
+
+![](http://blog.nimbledroid.com/assets/slow-android-reflection/Myntra.png)
+
+1421ms for call com.activeandroid.ActiveAndroid.initialize
+
+As you can see, the library requires more than a second to initialize. That’s a lot of time, especially taking into consideration that users expect an average app start time of 2s.
+
+To conclude, reflection in Android is really slow. To guarantee you offer users the smoothest experience possible, we recommend the following:
+
+> Recommendation: avoid using reflection (or libraries that use reflection) altogether. In particular, do not use reflective type adapters to serialize Java objects.
\ No newline at end of file
diff --git "a/issue-44/\345\256\211\345\215\223Binder\346\236\266\346\236\204\346\246\202\350\277\260.md" "b/issue-45/\345\256\211\345\215\223Binder\346\236\266\346\236\204\346\246\202\350\277\260.md"
similarity index 100%
rename from "issue-44/\345\256\211\345\215\223Binder\346\236\266\346\236\204\346\246\202\350\277\260.md"
rename to "issue-45/\345\256\211\345\215\223Binder\346\236\266\346\236\204\346\246\202\350\277\260.md"
diff --git "a/issue-45/\347\256\200\345\214\226\345\244\215\346\235\202\347\232\204\350\247\206\345\233\276\345\261\202\346\254\241.md" "b/issue-45/\347\256\200\345\214\226\345\244\215\346\235\202\347\232\204\350\247\206\345\233\276\345\261\202\346\254\241.md"
new file mode 100644
index 00000000..e5691c66
--- /dev/null
+++ "b/issue-45/\347\256\200\345\214\226\345\244\215\346\235\202\347\232\204\350\247\206\345\233\276\345\261\202\346\254\241.md"
@@ -0,0 +1,90 @@
+简化复杂的视图层级
+---
+
+> * 原文链接 : [Simplify Complex View Hierarchies](https://medium.com/google-developers/simplify-complex-view-hierarchies-5d358618b06f#.kuqg1wpi1)
+* 原文作者 : [Aleks Haecky](https://medium.com/@alekshaecky)
+* 译文出自 : [开发技术前线 www.devtf.cn](http://www.devtf.cn)
+* 转载声明: 本译文已授权[开发者头条](http://toutiao.io/download)享有独家转载权,未经允许,不得转载!
+* 译者 : [DroidWorkerLYF](https://github.com/DroidWorkerLYF)
+* 校对者: [desmond1121](https://github.com/desmond1121)
+* 状态 : 完成
+
+App的核心是使用视图层级来创造用户界面和视觉体验。随着app的功能越来越丰富,视图层级会越来越复杂,并且成为性能问题的来源之一。最常见的表象是app卡顿,尤其是渲染复杂视图时。
+
+简化或者重新布局你的视图层级可以提升app的性能表现,尤其是在低配设备和早期的Android版本上。额外的好处是,你的app会变得更容易维护。
+
+**前期准备**阅读[通过移除无用的背景减少过度绘制](https://medium.com/google-developers/draw-what-you-see-and-clip-the-e11-out-of-the-rest-6df58c47873e#.d9t0874dv)这篇文章,来排除导致卡顿的这一常见原因,避免和视图层级带来的问题混淆在一起。
+
+### 分析视图层级
+分析视图层级就是使用几个工具来定位并修复性能问题。所以,有时你只需要一个工具,有时则需要全部的工具一起使用来优化性能。
+
+#### GPU呈现模式分析
+
+1. [**运行GPU呈现模式分析**](http://developer.android.com/tools/performance/profile-gpu-rendering/index.html?utm_campaign=app_series_complexviewhierarchies_012616&utm_source=medium&utm_medium=blog)**并且观察柱状图蓝色的部分。** 如果蓝色的部分过高并且导致柱状图高度超过了16ms的标志线,那就是你的app花费了大量时间来更新display list。在Android 6.0版本中增加了额外的颜色,表示Measure/Layout的浅绿色也容易超乎预期的耗时。导致这些的一个原因就是试图层级过于复杂了。当然这只能告诉你有问题,而不能告诉你问题出在哪里。让我们接着往下看。
+
+#### 显示GPU视图更新
+
+1. 在你的设备上**运行显示GPU视图更新工具**。在**开发者选项中**,找到**硬件加速渲染**然后打开**显示GPU视图更新**。
+2. 操作你的app。
+3. 在屏幕上的试图更新时会闪烁红色。如果你注意到屏幕上和正在更新的区域无关的视图闪烁,那很可能是两者之间在视图层级上相关联所以导致了视图被不正确的失效了。这样,你就可以关注在这些区域上来更快的查找到问题。
+
+#### Hierarchy Viewer
+这就是你要做大量工作的工具了
+
+1. **开启** [**Hierarchy Viewer工具**](http://developer.android.com/tools/performance/hierarchy-viewer/index.html?utm_campaign=app_series_complexviewhierarchies_012616&utm_source=medium&utm_medium=blog)。
+2. 找到你app中仍然有大量过度绘制的视图层级。考虑重新调整你的视图来减少过度绘制。
+3. 定位到视图层级复杂的区域,考虑如何能简化它。
+4. [**分析**](https://developer.android.com/tools/performance/hierarchy-viewer/profiling.html?utm_campaign=app_series_complexviewhierarchies_012616&utm_source=medium&utm_medium=blog)视图层级中额外潜在的问题节点。
+
+#### 使用lint深入挖掘问题
+
+在布局文件上使用[lint](http://developer.android.com/tools/debugging/improving-w-lint.html?utm_campaign=app_series_complexviewhierarchies_012616&utm_source=medium&utm_medium=blog)来搜寻对视图层级可能的优化。然而关于lint的好处需要另写一篇文章。
+
+### 简化视图层级
+#### 移除对最终图像无用的视图
+
+按照如下步骤来确定对最终呈现到屏幕上的图像无用的视图:
+
+1. 在Hierarchy Viewer中,从叶子节点像根节点查看视图层级。
+2. 点击每一个节点来查看屏幕当前的图像。在Layout View窗口查看视图是如何分层的
+3. 如果一个之前可见的视图被完全隐藏,那么你可能根本就不需要这个视图,如图1.
+4. 在你的代码中移除被完全遮盖,从来不显示或者在屏幕区域外的视图。
+
+![](https://github.com/DroidWorkerLYF/Translate/blob/master/Simplify-Complex-View-Hierarchies/1.png?raw=true)
+
+图1. 视图2和3被完全遮盖可以安全的移除。
+
+#### 扁平化视图层级来减少嵌套
+1. 你的视图层级中有没有看起来类似图2的嵌套?
+2. 当可行时,使用相对布局替代嵌套的线性布局来扁平化视图层级。查看[优化视图层级](http://developer.android.com/training/improving-layouts/optimizing-layout.html?utm_campaign=app_series_complexviewhierarchies_012616&utm_source=medium&utm_medium=blog)这篇文章.
+
+![](https://github.com/DroidWorkerLYF/Translate/blob/master/Simplify-Complex-View-Hierarchies/2.png?raw=true)
+
+图2. 这个层次很深的视图层级可以变得扁平化来提升性能。
+
+#### 减少视图的数量
+
+1. 如果你的用户界面有很多简单的视图,你可以在不影响用户体验的前提下,像图3那样结合其中的一些。
+2. 所有的改变都会影响你呈现信息的方式当然设计上要做出权衡。不过要记住性能表现是你app成功与否最重要的一点,无论什么情况下,你都应该尽可能的选择优化它。
+3. 合并一些视图。比如:如果你减少字体和样式,就可以合并text view。
+4. 重新设计你的用户界面来使用更少的视图。
+
+![](https://github.com/DroidWorkerLYF/Translate/blob/master/Simplify-Complex-View-Hierarchies/3.png?raw=true)
+
+图3. 合并视图的列子
+
+#### 简化会导致多次layout的嵌套布局
+
+像RelativeLayout这样的父视图,需要两次布局来最终确定子视图的位置。结果就是,他们的子视图也需要两次布局。当你再把这些父视图嵌套在一起时,每一个视图层级的布局的次数就会以指数级增长。
+
+举个列子,RelativeLayout中嵌套一个ListView,ListView中嵌套一个GridView,GridView中嵌套一个view,这会导致8倍的布局次数,如图4.
+
+![](https://github.com/DroidWorkerLYF/Translate/blob/master/Simplify-Complex-View-Hierarchies/4.png?raw=true)
+
+- [RelativeLayout](http://developer.android.com/reference/android/widget/RelativeLayout.html?utm_campaign=app_series_complexviewhierarchies_012616&utm_source=medium&utm_medium=blog)
+- [Linearlayouts](http://developer.android.com/reference/android/widget/LinearLayout.html?utm_campaign=app_series_complexviewhierarchies_012616&utm_source=medium&utm_medium=blog)使用*measureWithLargestChild*方法
+- [GridView](http://developer.android.com/reference/android/widget/GridView.html?utm_campaign=app_series_complexviewhierarchies_012616&utm_source=medium&utm_medium=blog)使用gravity
+- 继承自以上容器的自定义视图
+- 一些weights的使用也可以导致加倍的布局
+
+使用任何以上的容器作为一个复杂视图的根节点,比如一个很深的子树的父节点,或者在布局中大量使用,都会影响性能。所以,多考虑如何在避免布局次数指数级增长的情况下达到相同的布局效果。比如,使用不设置gravity的gridview来替代relative layout作为根节点。
\ No newline at end of file