程序亦非猿

菩提本无树,程序亦非猿。


  • 首页

  • 关于

  • 标签

  • 分类

  • 归档

  • 友链

  • 搜索

Android程序猿学Css(中)

发表于 2016-07-14 | 更新于: 2019-02-12 | 分类于 Web | 阅读次数:
字数统计: 12 | 阅读时长 ≈ 1 分钟

前言

上篇Android程序猿学Css(上)

阅读全文 »

一步一步深入理解CoordinatorLayout

发表于 2016-07-12 | 更新于: 2019-02-12 | 分类于 Android | 阅读次数:
字数统计: 3.8k | 阅读时长 ≈ 15 分钟

一步一步深入理解CoordinatorLayout

Google推出Design库已经一年了,国内也出过一些文章关于CoordinatorLayout,但是都是教你怎么使用用,或者简单的自定义一些Behavior,并没有一篇文章深入去了解它的原理。

刚好这两天为了实现一个UI效果,看了CoordinatorLayout(后面简称Col)的官方文档以及源码,搞懂了它的原理,于是想着拿出来分享,特在此记录分享如何一步一步深入理解Col,希望可以填补这个空缺。

补充说明:

  1. Col等源码基于23.2.1版本
  2. 本文侧重在于Col与Behavior之间的交互,侧重于原理,并选择要点进行讲解,所以可能会有一些点被我忽略,不过看完后我相信你对Col会有更深一层的了解。

初步了解

学习最好的习惯就是看官方文档,来看看Col的定义以及官网的介绍:

1
2
public class CoordinatorLayout
extends ViewGroup implements NestedScrollingParent

官网介绍:

CoordinatorLayout is a super-powered FrameLayout.
CoordinatorLayout is intended for two primary use cases:

  1. As a top-level application decor or chrome layout
  2. As a container for a specific interaction with one or more child views

从定义可以看到Col继承自ViewGroup,并且它被设计成一个top-level的根布局,它本身只是一个ViewGroup,实现了NestedScrollingParent接口,看似非常普通,
但是说CoordinatorLayout是Design库最为重要的控件也不为过。

这里额外需要注意的是:

  1. 由于Col只实现了NestedScrollingParent,所以当Col嵌套(作为一个子View)的时候会得不到你想要的效果,需要自己写一个Col去实现NestedScrollingChild接口!
  2. 没有实现NestedScrollingChild接口的子View如:ListView,ScrollView在5.0以下版本跟Col是配合不了的需要使用RecyclerView,NestedScrollView才行

why?它super-powered在哪里呢?

Col最为重要的作用是:提供给子View实现各种交互的极大便利
直观的表现是我们可以使用Col非常方便地实现很多交互效果,具体效果可以看cheesesquare这个项目。

要知道,在没有Col的日子要实现简单的交互也不是件容易的事,需要通过各种回调/Event,相互回调,相互通知,甚至相互持有引用,复杂而且难以复用,但是现在有了Col,一切都变得方便了~

How?它是怎么做到的呢?
说到这里,不得不提到Col的静态内部类—>Behavior
接下去来了解一下它,老司机要开车了,快上车~

拦截一切的Behavior

Behavior是什么,有什么作用?

Interaction behavior plugin for child views of CoordinatorLayout.

A Behavior implements one or more interactions that a user can take on a child view. These interactions may include drags, swipes, flings, or any other gestures.

简单说,Behavior可以负责所有的交互甚至测量以及布局。

其实官网资料说得挺含蓄的,官方在Medium有一篇文章,叫:Intercepting everything with CoordinatorLayout Behaviors ,私以为用这个标题来形容Behavior,再合适不过,intercepting-everything!(这篇文章讲得很好也很全面,极力推荐阅读)

拦截一切!!迫不及待进一步了解!!

深入了解

如何实例化指定Behavior

  1. 通过构造方法实例,并在代码中设置到LayoutParams里
  2. Xml里指定,比如app:app:layout_behavior="me.yifeiyuan.demo.HeaderBehavior"
  3. 通过DefaultBehavior注解指定,比如`@CoordinatorLayout.DefaultBehavior(AppBarLayout.Behavior.class)`

第一种方式很简单,不多说,这里针对其他两种方式讲解一下,有一些注意点我们需要知道:

Xml方式

先撇一下Behavior的定义以及其构造方法如下:

1
2
3
4
5
6
//定义 V 为泛型,可指定针对哪种类型的View
public static abstract class Behavior<V extends View>
//默认的构造方法
public Behavior() {}
// xml里使用
public Behavior(Context context, AttributeSet attrs) {}

当我们在Xml里指定的时候,在LayoutParams的构造方法里会去调用parseBehavior这个方法,parseBehavior关键代码如下(不贴代码不行了,已尽量精简):

1
2
3
4
5
6
7
8
9
10
11
12
13
static Behavior parseBehavior(Context context, AttributeSet attrs, String name) {
//...省略了很多代码,只留下关键的部分
try {
//获取构造方法
Map<String, Constructor<Behavior>> constructors = sConstructors.get();
//...
// 注意这一行,这里传递了attrs,所以我们必须要有第二个构造方法!!!
return c.newInstance(context, attrs);
} catch (Exception e) {
//否则会报错 crash
throw new RuntimeException("Could not inflate Behavior subclass " + fullName, e);
}
}

这里我们需要注意的是: 如果要在xml里使用Behavior 那么第二个构造方法必不可少,所以我们自定义Behavior的时候需要注意;另外你在xml定义的属性会传递到第二个构造方法里去,可以获取你在xml里配置的属性,非常方便,可以说考虑还是非常周到的

注解方式

第三种通过注解的方式,又是在什么时候,怎么去实例化的呢?

在Col中的onMeasure中会去调用prepareChildren方法,而prepareChildren方法又调用了一个叫getResolvedLayoutParams的方法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
LayoutParams getResolvedLayoutParams(View child) {
final LayoutParams result = (LayoutParams) child.getLayoutParams();
//如果没有解析过 则去解析
if (!result.mBehaviorResolved) {
Class<?> childClass = child.getClass();
DefaultBehavior defaultBehavior = null;
while (childClass != null &&
(defaultBehavior = childClass.getAnnotation(DefaultBehavior.class)) == null) {//如果 有DefaultBehavior这个注解
childClass = childClass.getSuperclass();
}
if (defaultBehavior != null) {
try {
//实例化Behavior并把这个Behavior赋值给result
result.setBehavior(defaultBehavior.value().newInstance());
} catch (Exception e) {
Log.e(TAG, "Default behavior class " + defaultBehavior.value().getName() +
" could not be instantiated. Did you forget a default constructor?", e);
}
}
result.mBehaviorResolved = true;//标记已经解析过
}
return result;
}

所以注解方式是在onMeasure中通过getResolvedLayoutParams去实例化的。

另外还需要知道的是,Behavior是Col.LayoutParams的成员变量,那么也就是说只有当你的Behavior设置给Col的 直接子View 才会有效果,这点要记住,不然徒劳无功。(Col的子View的子View就不要给它设置Behavior啦,没效果的)

以上需要牢记,不过仅仅知道这些显然是不够的!至少我不会到这里就停~

接下去继续深入阅读Behavior的源码一探究竟(一言不合就看源码)

在我阅读了Behavior的源码后,我觉得非常有必要先搞清楚几个非常重要的概念。

child与dependency

  1. child,the child view associated with this Behavior
    它是一个View,是该Behavior的关联对象,也即Behavior所要操作的对象
  2. dependency,也是个View,是 child的依赖对象,同时也是Behavior对child进行操作的根据

弄清楚这些个概念后看源码会比较简单了,Behavior除了构造方法外,有23个方法,限于篇幅与精力,我挑选几个最重要的方法来讲解,当然我不会死板的一个一个毫无逻辑地解释过去。

那些不能不懂的方法

layoutDependsOn

之前提到了child与dependency有着依赖关系,那么问题来了: 这个依赖关系是如何建立的?

在Behavior类中有个方法:

1
public boolean layoutDependsOn(CoordinatorLayout  parent, V child, View dependency)

它会被Behavior的LayoutParams的dependsOn方法调用:

1
2
3
4
boolean dependsOn(CoordinatorLayout parent, View child, View dependency) {
return dependency == mAnchorDirectChild
|| (mBehavior != null && mBehavior.layoutDependsOn(parent, child, dependency));
}

而LayoutParams的dependsOn方法会被Col调用,dependsOn方法就是用来确定依赖关系的。

所以,最简单的确定依赖关系的方法是重写layoutDependsOn方法,并在一定条件下返回true即可确立依赖关系。

那为什么说一定条件呢?

比如FAB依赖于SnackBar,是因为它在SnackBar出现以及消失的时候需要改变自身的位置,所以FAB的layoutDependsOn方法中对Snackbar.SnackbarLayout返回了true,而没有依赖其他的控件:

1
2
3
4
5
@Override
public boolean layoutDependsOn(CoordinatorLayout parent,FloatingActionButton child, View dependency) {
// We're dependent on all SnackbarLayouts (if enabled)
return SNACKBAR_BEHAVIOR_ENABLED && dependency instanceof Snackbar.SnackbarLayout;
}

另外需要注意的是:当确定依赖关系后,当dependency被布局(或测量)后child会紧接着被布局(或测量),Col会无视子view的顺序(原因是Col内有个ComparatormLayoutDependencyComparator会按照依赖关系对所有的子View进行排序),这会影响它们的测量以及布局顺序

可以说layoutDependsOn方法是自定义Behavior最为重要的方法

onDependentViewChanged

建立起依赖关系之后呢?

想要做交互,似乎还缺点什么,我想在dependency发生变化的时候改变一下child,我该如何知道这个改变的时机呢?

其实不需要我们去主动获取去判断,Col跟Behavior已经帮我们做好了这一切,onDependentViewChanged登场。

onDependentViewChanged方法的定义:

1
2
3
4
5
6
7
8
9
/**
* Respond to a change in a child's dependent view
* This method is called whenever a dependent view changes in size or position outside
* of the standard layout flow. A Behavior may use this method to appropriately update
* the child view in response.
*/
public boolean onDependentViewChanged(CoordinatorLayout parent, V child, View dependency) {
return false;
}

简单来说就是,当我们的dependency发生改变的时候,这个方法会调用,而我们在onDependentViewChanged方法里做出相应的改变,就能做出我们想要的交互效果了!

可能你也注意到了onDependentViewChanged方法是有返回值的

当我们改变了child的size或者position的时候我们需要返回true,差不多可以理解为 当我们的dependency发生了改变,同样的,child也需要发生改变,这个时候我们需要返回true

提一下:onDependentViewChanged方法是在Col的dispatchOnDependentViewChanged里调用的

其他

除了以上两个特别重要的方法外,Nested系列方法也非常重要,如onStartNestedScroll和onStopNestedScroll来监听嵌套滚动的开始和结束,不过限于篇幅,想再另外开篇去写,这里就不写了

另外还有onMeasureChild,onLayoutChild这个后面会讲。

为什么Behavior可以拦截一切?

我们知道,ViewGroup的测量,布局,事件分发都是需要自己处理的,那么Col究竟给了Behavior什么特权,让它能够让它拦截一切?

让我们挨个一点一点看下去

onMeasure

直接备注在源码里了,不多说啦!~

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//之前已经提到过了 解析Behavior,并按依赖顺序重排子View顺序
prepareChildren();
//用于addPreDrawListener,OnPreDrawListener里会调用 dispatchOnDependentViewChanged(false)
ensurePreDrawListener();
//...
// 计算 padding width height 处理 fitSystemWindow等
//...
final int childCount = mDependencySortedChildren.size();
for (int i = 0; i < childCount; i++) {
final View child = mDependencySortedChildren.get(i);
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
int keylineWidthUsed = 0;
//...处理keyline childWidthMeasureSpec等
final Behavior b = lp.getBehavior();
//当behavior的onMeasureChild方法返回true的时候,我们就可以拦截Col默认的measure
if (b == null || !b.onMeasureChild(this, child, childWidthMeasureSpec, keylineWidthUsed,
childHeightMeasureSpec, 0)) {
onMeasureChild(child, childWidthMeasureSpec, keylineWidthUsed,
childHeightMeasureSpec, 0);
}
//...
}
//...
final int width = ViewCompat.resolveSizeAndState(widthUsed, widthMeasureSpec,
childState & ViewCompat.MEASURED_STATE_MASK);
final int height = ViewCompat.resolveSizeAndState(heightUsed, heightMeasureSpec,
childState << ViewCompat.MEASURED_HEIGHT_STATE_SHIFT);
setMeasuredDimension(width, height);
}

onLayout

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
final int layoutDirection = ViewCompat.getLayoutDirection(this);
//mDependencySortedChildren 在 onMeasure里已经排过序了
final int childCount = mDependencySortedChildren.size();
for (int i = 0; i < childCount; i++) {
final View child = mDependencySortedChildren.get(i);
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
final Behavior behavior = lp.getBehavior();
//可以看到,当behavior.onLayoutChild()返回true的时候,就可以拦截掉Col的默认Layout操作!
if (behavior == null || !behavior.onLayoutChild(this, child, layoutDirection)) {
onLayoutChild(child, layoutDirection);
}
}
}

原理其实跟onMeasure方法一样的。

onInterceptTouchEvent & onTouchEvent

在处理touch事件中,Col重写了onInterceptTouchEvent和onTouchEvent,另外,它们都调用了Col里定义的一个处理拦截的方法,performIntercept(关键代码都在这方法之中),就看一下它们的实现吧:

onInterceptTouchEvent的实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
MotionEvent cancelEvent = null;
final int action = MotionEventCompat.getActionMasked(ev);
// Make sure we reset in case we had missed a previous important event.
if (action == MotionEvent.ACTION_DOWN) {
//down的时候,跟大部分ViewGroup一样,需要重置一些状态以及变量,比如 mBehaviorTouchView
resetTouchBehaviors();
}
//这里看performIntercept TYPE_ON_INTERCEPT标记是 onInterceptTouchEvent
final boolean intercepted = performIntercept(ev, TYPE_ON_INTERCEPT);
if (cancelEvent != null) {
cancelEvent.recycle();
}
//当事件为UP和Cancel的时候去重置(同down)
if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
resetTouchBehaviors();
}
return intercepted;
}

onTouchEvent的实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Override
public boolean onTouchEvent(MotionEvent ev) {
boolean handled = false;
boolean cancelSuper = false;
MotionEvent cancelEvent = null;
final int action = MotionEventCompat.getActionMasked(ev);
// mBehaviorTouchView不为null(代表之前有behavior处理了down事件) 或者 performIntercept返回true 那么事件就交给mBehaviorTouchView
if (mBehaviorTouchView != null || (cancelSuper = performIntercept(ev, TYPE_ON_TOUCH))) {
// Safe since performIntercept guarantees that
// mBehaviorTouchView != null if it returns true
final LayoutParams lp = (LayoutParams) mBehaviorTouchView.getLayoutParams();
final Behavior b = lp.getBehavior();
if (b != null) {
// 交给 behavior去处理事件
handled = b.onTouchEvent(this, mBehaviorTouchView, ev);
}
}
// Keep the super implementation correct
// 省略调用默认实现 up&cancel的时候重置状态
//...
return handled;
}

可以看到,其实这两个方法做的事情并不多,其实都交给performIntercept方法去做处理了!

performIntercept的实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
// type 标记是intercept还是touch
private boolean performIntercept(MotionEvent ev, final int type) {
boolean intercepted = false;
boolean newBlock = false;
MotionEvent cancelEvent = null;
final int action = MotionEventCompat.getActionMasked(ev);
final List<View> topmostChildList = mTempList1;
//按Z轴排序 原因很简单 让最上面的View先处理事件
getTopSortedChildren(topmostChildList);
// Let topmost child views inspect first
final int childCount = topmostChildList.size();
for (int i = 0; i < childCount; i++) {
final View child = topmostChildList.get(i);
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
final Behavior b = lp.getBehavior();
//当前事件已经被某个behavior拦截了(or newBlock),并且事件不为down,那么就发送一个 取消事件 给所有在拦截的behavior之后的behavior
if ((intercepted || newBlock) && action != MotionEvent.ACTION_DOWN) {
// Cancel all behaviors beneath the one that intercepted.
// If the event is "down" then we don't have anything to cancel yet.
if (b != null) {
if (cancelEvent == null) {
final long now = SystemClock.uptimeMillis();
cancelEvent = MotionEvent.obtain(now, now,
MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0);
}
switch (type) {
case TYPE_ON_INTERCEPT:
b.onInterceptTouchEvent(this, child, cancelEvent);
break;
case TYPE_ON_TOUCH:
b.onTouchEvent(this, child, cancelEvent);
break;
}
}
continue;
}
// 如果还没有被拦截,那么继续询问每个Behavior 是否要处理该事件
if (!intercepted && b != null) {
switch (type) {
case TYPE_ON_INTERCEPT:
intercepted = b.onInterceptTouchEvent(this, child, ev);
break;
case TYPE_ON_TOUCH:
intercepted = b.onTouchEvent(this, child, ev);
break;
}
//如果有behavior处理了当前的事件,那么把它赋值给mBehaviorTouchView,它其实跟ViewGroup源码中的mFirstTouchTarget作用是一样的
if (intercepted) {
mBehaviorTouchView = child;
}
}
// Don't keep going if we're not allowing interaction below this.
// Setting newBlock will make sure we cancel the rest of the behaviors.
// 是否拦截一切在它之后的交互 好暴力-0-
final boolean wasBlocking = lp.didBlockInteraction();
final boolean isBlocking = lp.isBlockingInteractionBelow(this, child);
newBlock = isBlocking && !wasBlocking;
if (isBlocking && !newBlock) {
// Stop here since we don't have anything more to cancel - we already did
// when the behavior first started blocking things below this point.
break;
}
}
topmostChildList.clear();
return intercepted;
}

通过分析源码,可以知道,Col在关键的方法里把处理权优先交给了Behavior,所以才让Behavior拥有了拦截一切的能力,所以,原来是Col放任了Behavior!!~

结语

Col以及Behavior的重要的几个环节分析完毕,相信大家看完后能够对它们有更深层次的了解,而不是仅仅停留在使用上面。

这篇文章断断续续写了快一个月,思路断断续续,也有几次推翻重来,原本也打算想讲得更多更细一些,只是限于篇幅与精力,最终的效果跟我最初的预期有所差距,可能也有些错误或者讲解不清晰的地方。

如果你发现任何错误,或者写得不好的地方,或者不理解的地方,非常欢迎批评指正,也非常欢迎吐槽!!!!

其实我还顺带看了AppBarLayout等的源码,如有可能,我还想把Design库下的所有控件都分析一遍。

感谢你的阅读。

资料

Intercepting everything with CoordinatorLayout Behaviors

CoordinatorLayout.Behavior

http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2016/0224/3991.html

推荐阅读

ViewStub是如何实现懒加载的
Space源码分析
LayoutInflater源码分析(一)之inflate深度分析

博客收到第一次打赏的喜与悲

发表于 2016-07-11 | 更新于: 2019-02-12 | 分类于 Android | 阅读次数:
字数统计: 1.1k | 阅读时长 ≈ 3 分钟

前言

今天微信突然收到一个 面对面收钱的到账通知 , 楞了一下,谁给我转的钱?
仔细一看,显示的名字是 Major,在我的记忆中,我并没有这么一个好友.

我一搜,确实不是我的好友.

刚开始还没反应过来,后来仔细一想,好像我在我的博客开放着我的微信二维码,那他应该是我的读者,这应该是对我博客的一份支持了!

非常激动,非常感激,想加他微信亲自表示感谢,但是搜索不到微信号,很是可惜.

后面是废话和牢骚,不看也罢

也因此,回想起自己写博客的经历,两年前开始写博客,一路以来自己 坚持原创,坚持授人以鱼 不如授人以渔,写博客这么久以来,写了约100篇左右,在博客上从来没有收到过打赏支持(说心里话,其实内心是比较失望的,那时候博客的图片放在七牛,连服务费都付不起呢,oh,现在依然如此).

因为自己深知写博客写文章的不易,写一篇文章通常比自己学习知识花费的时间更多.

特别是随着时间的增长,随着自己能力的提升,担当更多更重的任务,同时也发现自己更多的不足,要不断地去学习更多的知识,(比如什么OkHttp,RxJava
,Retrofit,Glide,Dagger2,RN等等等等),被更多的知识Push着,以至于停下脚步来写维护博客的时间越来越少.

以前写一篇文章我还同步到简书,慕课网等,还在各个平台分享出去,还去发微博at一大堆大V,甚至还开通了微信公众账号希望分享给更多的朋友,而现在,即使写了,都懒得去折腾这些了.

以前开的坑 比如 群英传,艺术探索,EJ,设计模式等系列也都因为时间与精力的关系更新缓慢,再比如最近定的一篇<<一步一步深入理解CoordinatorLayout>>(看了3天源码准备总结的),断断续续写了两个礼拜了,才写了1600字,估计才完成一半,但是始终没有将它完结,分享到博客来!

再加上写博客其实是一件十分吃力不讨好的事,花费极大的精力,可能换来的是几十或者一两百的PV,甚至被那些恶心的傻逼网站全文爬走,连个出处都不给你,再加上我自己的拖拉,很多文章以及系列都只存在我的脑海蓝图中,有的甚至还没提笔就已胎死腹中.

所以,我想,可能没有人比我更懂坚持写原创博客的艰辛了.

所以,我特别佩服那些在百忙之中还能写出精彩文章的作者.

而对于优秀的文章,我向来是非常支持的,我本人经常会打赏那些好的文章,特别是在简书上,我打赏出去的钱是我收进来的几十倍!

并且在国内现在这个环境下,鸡汤文,垃圾文遍地,各种抄袭,爬文章各种猖狂,我总怕,坚持写优秀博客的人越来越少,我能支持就支持一下.

另外,在别人支持我的时候,我总是非常感激,非常非常感激那些给予我支持的人,你们每个人的每一份打赏,我都会在这里记录 ,虽然写文章并不是为了钱,但是不可否认的是,这是其中一个动力来源.

如果可以,我希望我的读者,屏幕前的你,能够与我多一些互动,多给我一些建议,如果我写得烂,请喷我,如果写得好,可以支持我一下

我会非常感激,如果你能这么做的话!

我依然会坚持写博客

希望你依然会光顾

希望你会喜欢

但行好事

莫问前程

就这样

祝好

安

Android程序猿学Css(上)

发表于 2016-07-06 | 更新于: 2019-02-12 | 分类于 Web | 阅读次数:
字数统计: 955 | 阅读时长 ≈ 3 分钟

前言

前面学习了Html,现在接下去学习一下Css.

CSS全称为“层叠样式表 (Cascading Style Sheets)”,它主要是用于定义HTML内容在浏览器内的显示样式,如文字大小、颜色、字体加粗等。

我觉得可以把CSS理解为Android的Style&Theme

css 样式由选择符和声明组成,而声明又由属性和值组成,如下:

Css语法

选择符:又称选择器,指明网页中要应用样式规则的元素

例子如下:

1
2
3
4
5
p{
font-size:12px;
color:red;
font-weight:bold;
}

意思是修改<p>标签的相关属性.

阅读全文 »

Html入门学习

发表于 2016-07-05 | 更新于: 2019-02-12 | 分类于 Web | 阅读次数:
字数统计: 1.5k | 阅读时长 ≈ 5 分钟

前言

前几天玩了React Native,(文章),发现如果想真的学好的话,还需要学习一下Html,Css,JavaScript,Node,ES6什么的,感觉东西好多好多
一样一样来吧,从Html开始涉猎吧!

阅读全文 »

第2章-IPC机制

发表于 2016-06-30 | 更新于: 2019-02-12 | 分类于 读书笔记 | 阅读次数:
字数统计: 610 | 阅读时长 ≈ 2 分钟

// todo 尚未完成

前言

IPC是 Inter-Process Communication的缩写,含义为进程间通信或者跨进程通信是指两个进程之间进行数据交互的过程.

在Android系统中IPC非常非常重要,需要掌握!!!

阅读全文 »

那些做Android开发必须知道的ADB命令

发表于 2016-06-30 | 更新于: 2019-02-12 | 分类于 Android | 阅读次数:
字数统计: 574 | 阅读时长 ≈ 2 分钟

那些必须知道的ADB命令

科普: ADB的全称是Android Debug Bridge

熟练掌握ADB命令可以提高开发效率
以下记录一些比较常用的命令:

阅读全文 »

微博这是要完

发表于 2016-06-28 | 更新于: 2019-02-12 | 分类于 Android | 阅读次数:
字数统计: 107 | 阅读时长 ≈ 1 分钟

前言

玩微博有一两年了,老是遇到偷偷摸摸给我关注一些乱七八糟的账号

今天又发现我关注别人了,更可恶的是,tm居然还自动发微博了,还有没有底线了?

360安全浏览器什么鬼?

我用的MAC啊!!!~

iPhone什么鬼?

我用的Android啊!~

臭不要脸的微博!!!

迟早跟百度一样!

微博这是要完.

初试ReactNative

发表于 2016-06-28 | 更新于: 2019-02-12 | 分类于 Android | 阅读次数:
字数统计: 223 | 阅读时长 ≈ 1 分钟

前言

博客写累了,玩玩 ReactNative!~

阅读全文 »

第1章-Activity的生命周期和启动模式

发表于 2016-06-27 | 更新于: 2019-02-12 | 分类于 读书笔记 | 阅读次数:
字数统计: 1.9k | 阅读时长 ≈ 7 分钟

Activity的生命周期

  1. 正常状态
  2. 异常状态(系统杀死/Configuration变化如屏幕旋转)

正常状态

  1. onCreate 表示Activity正在创建,可以做一些初始化操作
  2. onRestart 正在重新启动,onstop后回来会调用
  3. onStart 正在被启动,后台,不可交互
  4. onResume 可见可交互前台,非常重要,许许多多的重要的类在这里初始化
  5. onPause 正在停止 后台(不一定不可见) 不可做太耗时的操作,因为onPause之后新启动Activity的onResume才能被调用
  6. onStop 即将停止,不可见 可以做一些稍微重量级 的回收
  7. onDestroy 即将销毁,可以做一些回收资源,关闭线程,移除Handler消息等操作

生命周期配对去记忆效果更佳:
create – destroy
start – stop
resume – pause

阅读全文 »
1…567…15
程序亦非猿

程序亦非猿

144 日志
11 分类
101 标签
GitHub
0%
© 2015 — 2021 程序亦非猿 | Site words total count: 122.7k
由 Hexo 强力驱动
|
主题 — NexT.Gemini v5.1.4
人次 次