对Lamda表达式的简单理解

第一次见Lamda表达式

第一次看到这行代码的时候,我是百思不得姐:

1
Toolkit.let(mUserTabFragment, f -> f.setUserVisibleHint(true));

点击进入let函数看到其定义如下:

1
2
3
4
5
6
public static <T> void let(@Nullable T input, Consumer<T> consumer) {
if (input == null || consumer == null) {
return;
}
consumer.accept(input);
}

可以看出let的第二个参数是一个Consumer,但是上面的f->f.setUserVisibleHint(isVisibleToUser));是什么鬼,是Consumer吗?答案是 是的,这样看就明白了,首先,我们创建一个Consumer对象:

1
2
3
4
5
6
Consumer<Fragment> consumer = new Consumer<Fragment>() {
@Override
public void accept(Fragment f) {
f.setUserVisibleHint(true));
}
};

上面代码的Lamda形式为:

1
Consumer<Fragment> consumer = (f)-> f.setUserVisibleHint(true));

所以 可以直接将等号右边带入let函数的第二个参数,就变成了那个样子:

1
Toolkit.let(mUserTabFragment, f -> f.setUserVisibleHint(true));

现在应该就明白了第二个参数到底是啥了,其实就是一种Lamda表达式。

Read more

Android中动画的使用

Android中动画的使用

前言:

在Android中,如果想让一个View的消失,如果没有做任何处理,直接setVisibility(View.GONE),你会发现整个View是瞬间消失的,没有任何过度。为了让用户感知到View的消失,就要让这个View消失的时候带一个动画效果,这样可以减轻用户的焦虑感。

Android中动画的种类

Android中共有三种动画系统,分别是:

  • View Animations - 最原始的Android动画,性能差而且不够灵活.Property Animations动画出现后就被废弃了。
  • Property Animations - 自Android 3.0后引入的强大灵活的动画系统
  • Transition Animations - 上面两种动画只是对某个View进行改变,而不会影响其所在的容器及周边的Views,而Transition动画可以适应layout的变化。默认的Transition框架支持Andorid 4.4以上的系统,使用com.android.support:transition支持库可以使Transition框架兼容到Android 4.0及以上。

Property Animation 属性动画

其中我们最常用的是Property animation,称之为,属性动画。顾名思义,属性动画可以对任意对象的任意属性在一段时长内进行渐变:

Property animations allow us to animate any property of any object from one value to another over a specified duration.

所以,属性动画除了可以对View的位置、角度做变换外,还可以对字体的大小、View的颜色等属性进行变换。

Android中常用的动画叫Property Animation(属性动画),它是出现在View Animation(视图动画) (包括 Tween Animation(补间动画)和 Frame Animation(逐帧动画)) 之后的,相比老的视图动画,Property Animation的主要优势是:

老的View Animation只是对View对象的外观进行动画操作,但是并没有真正的改变对象本身的属性。例如对某个View平移以后,只是视觉特效,并没有真正改变这个View的位置,也就是说你点击平移后的View是不能触发onClick的,因为其属性中的位置还在原来的位置(the previous animations changed the visual appearance of the target objects… but they didn’t actually change the objects themselves.)。而Property Animation除了视觉效果,还能真正的改变View的属性。而使用Property Animation不仅可以对View进行透明度渐变、缩放、平移操作,还可以对其他的一些属性进行动画操作,例如字体大小,颜色,背景等,实现炫酷的字体颜色变化,或者背景颜色变化等等。

Property Animation(属性动画)的主要实现类是:ObjectAnimation。这个类是我们实现动画最常用的类。

ObjectAnimator 动画

用法示例

ObjectAnimator的主要用法如下,假设要让一个View进行透明度从透明到不透明:

1
ObjectAnimator alphaAnim = ObjectAnimator.ofFloat(view,"Alpha", 0f, 1f) .setDuration(getResources().getInteger(R.integer.china_date_switch_btn_gone_duration));

上面代码中ofFloat就是指让这个动画按照float类型的精度去变化。ofFloat函数源码中的常用构造函数如下:

1
ofFloat(Object target, String propertyName, float... values)

第一个target是要赋予动画的对象,第二个propertyName是赋予什么动画或者对这个对象的什么属性进行变化,第三个是一个可变长度的参数,那三个点表示这个参数可以有多个,例如上面示例代码中有两个,分别是0f和1f,表示从透明变到不透明。也可以添加任何多个,例如0f, 1f, 0.5f,指的就是从透明到不透明又到半透明。

上面简单的例子就实现了透明度动画。除了透明度属性,常用的属性还有:

常用的propertyName有以下:

| 属性 | 作用 | 数值类型 | | ———— | ——————————— | ——– | | Alpha | 控制View的透明度 | float | | TranslationX | 控制X方向的位移(相对于当前位置) | float | | TranslationY | 控制Y方向的位移(相对于当前位置) | float | | ScaleX | 控制X方向的缩放倍数 | float | | ScaleY | 控制Y方向的缩放倍数 | float | | Rotation | 控制以屏幕方向为轴的旋转度数 | float | | RotationX | 控制以X轴为轴的旋转度数 | float | | RotationY | 控制以Y轴为轴的旋转度数 | float |

除了上面的属性,ObjectAnimator可以对一个对象的任意属性进行动画渐变,例如:

1
2
3
ObjectAnimator.ofFloat(mTextView,"textSize",  0, 100, 50)
.setDuration(5000)
.start();

这样就相当于不断调用TextView的setTextSize()方法对文字大小进行设置,就实现字体变大,再变小的动画。

示例

但是需要注意的是,如果要对一个对象的属性进行变化,这个对象必须有公开的set的方法例如TextView有setTextSize这个方法,那么就可以用“textSize”这个属性。

这时你可能会疑惑了🤔,如果想控制的对象方法名字不是set开头,而是叫changeTextSize或者moveXPosition等,或者一个对象有set方法,但是没有public暴露给大家使用怎么办呢?

这时可以提出两种抛砖引玉的方法:

  • 在对象外层包装一个类,自己写一个public的set方法控制对象的属性。
  • 使用ValueAnimator。至于什么是ValueAnimator,下面就马上会讲到。

ValueAnimator

明白了怎么用,我们再简单了解一下它实现的原理,想一想怎样实现对象的属性动画呢?如果我们想实现一个1秒钟内将透明度从0变到1的动画,其实是把整个工作分成了两部分:

  • 计算属性(透明度)的值。也就是这一秒内,每个时间点的属性值应该是多少,这部分工作由ValueAnimator完成。

  • 设置属性(透明度)的值。将每个时间点的值设置到对象上。这部分由ObjectAnimator完成。

其实ValueAnimator就是一个时间机制,你甚至可以单纯的利用它的时间机制实现除了动画以外的其他逻辑:

1
2
3
4
5
6
7
8
9
ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);
anim.setDuration(500);
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
public void onAnimationUpdate(ValueAnimator animation) {
Float value = (Float) animation.getAnimatedValue();
// do something with value...
}
});
anim.start();

AnimatorSet

如果需要组合多个动画,可以借助AnimatorSet进行统一管理。AnimatorSet类可以将单个的ObjectAnimator组合起来形成动画集,可以同时创建多个特效,例如,一边放大一边变透明化或者按照顺序先放大再透明化等等。通过组合不同的动画属性,可以满足生活中大部分常用的场景。其用法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
ObjectAnimator alphaAnim = ObjectAnimator.ofFloat(view,"Alpha", 0f, 1f)
.setDuration(getResources().getInteger(R.integer.china_date_switch_btn_gone_duration));
ObjectAnimator scaleAnim = ObjectAnimator.ofFloat(view,"scaleY", 0, 1)
.setDuration(getResources().getInteger(R.integer.china_date_switch_btn_gone_duration));
AnimatorSet fadeInAnim = new AnimatorSet();
fadeInAnim.play(alphaAnim).with(scaleAnim);
fadeInAnim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
super.onAnimationStart(animation);
view.setVisibility(View.VISIBLE);
}
});
fadeInAnim.start();

两大神器TypeEvaluator和Interpolation

TypeEvaluator

恐怕不少刚接触ObjectAnimator的人都会想为啥ObjectAnimator后面要跟ofFloat, ofInt和ofObject,ofObject又是个什么东西呢?

如果一个动画变化的属性是数字,例如透明度就是从0到1的,ofFloat会在要求的时间范围内把每个时间点的值计算成一个个的float值,相应的,ofInt就会把属性值计算成Int值,这些都是动画系统实现的方法。那如果现在属性的变化不是时间而是Point类,那动画系统怎么知道如何计算每个时间点的Point值呢,答案是你来告诉动画系统如何计算。只要继承TypeEvaluator类,实现其中的evaluate方法即可:

1
2
3
4
5
6
7
8
public class PointEvaluator implements TypeEvaluator {
public Object evaluate(float fraction, Object startValue, Object endValue) {
Point startPoint = (Point) startValue;
Point endPoint = (Point) endValue;
return new Point(startPoint.x + fraction * (endPoint.x - startPoint.x),
startPoint.y + fraction * (endPoint.y - startPoint.y));
}
}

这样就可以计算两个点之间的值了:

1
2
3
Point p0 = new Point(0, 0);
Point p1 = new Point(100, 200);
ValueAnimator anim = ValueAnimator.ofObject(new PointEvaluator(), p0, p1);
Interpolation

放大,缩小,平移等这样的动画方式非常普通,因为这些动画是线性的,也就是说在动画时间内,属性值的变化是线性变化的。大家有时会看到一些非常炫酷的动画例如,回弹,果冻效果等等,这些效果多是非线性变化的结果,如果想实现这样的效果,就用到了Interpolation(插值器)。

Android已经实现了常用的Interpolation,如:

| Name | Description | | ———————- | ———– | | AccelerateInterpolator | 加速 | | BounceInterpolator | 弹跳 | | DecelerateInterpolator | 减速 |

还有AccelerateDecelerateInterpolator、AnticipateInterpolator、PathInterpolator、OvershootInterpolator、AnticipateOvershootInterpolator 、DecelerateInterpolator 、CycleInterpolator等,这些基本上涵盖了我们使用的范围。

当然,如果上面插值器不满足需求,也可以定制插值器,只需要继承BaseInterpolator并实现TimeInterpolator接口就可以了,例如OvershootInterpolator的实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class OvershootInterpolator extends BaseInterpolator {
private final float mTension;

public OvershootInterpolator() {
mTension = 2.0f;
}

public OvershootInterpolator(float tension) {
mTension = tension;
}

public float getInterpolation(float t) {
// _o(t) = t * t * ((tension + 1) * t + tension)
// o(t) = _o(t - 1) + 1
t -= 1.0f;
return t * t * ((mTension + 1) * t + mTension) + 1.0f;
}
}

这里的getInterpolation方法里是一个插值器函数,如果输入的t直接返回,那这就是一个线性插值器。这个网站看一查看插值器函数生成的曲线,安利给大家。

Android Transition Framework

上面介绍的动画针对的是某一个对象进行动画操作,但是实际应用中,我更多的使用Android的Transition动画来移动某个View。Transition动画与Property动画最大的区别就是:View动的过程中会对其周边的View产生影响。也就是说,如果我想让一个View逐渐变大,那它在变大的过程中不会覆盖在其周边的View上面,而是挤推着周围的View移动,也就是整个Layout都在变化,而这一切都是Transition框架自动实现的,开发者不需要关心实现细节。

后续补充:

https://developer.android.com/training/transitions/

https://developer.android.com/training/transitions/start-activity

https://cloud.tencent.com/info/8fb508a6e6115e59e4f151fbaadd432e.html

参考:

ObjectAnimator 基本使用 http://wiki.jikexueyuan.com/project/android-animation/7.html

Android 属性动画:这是一篇很详细的 属性动画 总结&攻略 https://blog.csdn.net/carson_ho/article/details/72909894

为什么要废弃掉Android之前的动画?https://android-developers.googleblog.com/2011/02/animation-in-honeycomb.html

查看Interpolation曲线:http://inloop.github.io/interpolator/

原来我根本不会用Android Studio

背景

最近在工作中解锁了一些使用Android Studio的技巧,在这里记录一下。

1. 为什么明明我的电脑剩余那么多内存,用Android Studio打开多个工程后就开始卡顿了呢?

有一次在使用Android stuido的时候发现会卡顿无比,滚动鼠标都卡,但我的机器明明配置很高,系统剩余的内存也很多啊。

于是,打开内存指示器,查看Android Studio的内存使用情况:

打开设置 -> Appearance -> Window Options -> Show memory indicator

勾选了Show memory indicator 之后,就可以在Android Studio的右下角看到内存指示器了:

双击指示器可以手动进行GC操作。这里显示的就是Android Studio占用的内存大小(左)和分配给Android Studio使用的最大内存(右)。如果发现占用内存基本上快要等于分配的最大内存的时候,说明需要分配更多的内存给Android Studio了。当时我的机器显示的是1020/1024M,这应该就是其默认分配的内存大小,基本上分配的内存已经快要用完了,这也就是为啥明明电脑内存剩余很多,但是Android Studio却很卡顿的原因。

于是,通过下面步骤来提高分配给Android的内存:

打开菜单Help->Edit Custom VM Options,这时,会在新窗口打开一个studo.vmoptions文件(如果之前没有,会新创建一个),在打开的文件中输入下面代码配置虚拟机堆栈的最大分配内存:

1
-Xmx4096m

这里可以根据自己机器的内存大小,对Android Studio进行配置,配置完成后,重启Android Studio,看到右下角的内存指示器显示的最大分配内存已经发生了变化,就说明生效了。

Read more

基于MainFramer进行远程编译(以Android开发为例)

一、故事背景(可略过)

以前,世界上只有两种电脑:笔记本和台式机。

上帝说,要有高性能的笔记本。于是,就有了MainFramer。

我就遇到了这种情况,上班后公司配的是MacBookPro的笔记本和一个Windows的台式机(PC),我曾尝试过使用MacBook作为主力机工作,MacOS的体验非常优秀,但是唯一的不足就是其在处理大型复杂任务时的速度远不如我那台高配的台式机,编译一次工程的时间差在3分钟左右,而我每天编译上20次就能差出一个小时,有这个时间提前让我下班多好。最重要的是,我只要一点击Build,整个机器就开始满负荷运行,除了温度飙升外,CPU也被占满,这时候开个网页都卡成了幻灯片。

为了提高工作效率,我尝试一直用台式机工作,于是我的MBP吃灰了很久,这么优秀的笔记本放在那里吃灰实在是心疼。最关键的是,台式机让我完全没有工作流的感觉,当我周末无聊想充电的时候,我发现我所有想看的东西都在公司,当我一个个软件打开,一个个网页从历史记录中找到后,我发现我已经没有了学习的欲望。这时候我非常想念用笔记本时那种“合盖走人”后,回家打开盖子发现我所有的思路都还在的感觉。

于是我急切的找一种方法,让简单的任务在笔记本上来做,复杂的任务能够利用台式机完成,并且在体验上做到“无差别”。终于,我在浏览全球最大的同性社交网站时惊喜的发现了mainframer,这是一个工具,可以将编译这件占内存和CPU的事从本地电脑放到远程电脑上来做。

简单的说,你只需要一台本地机器(Local Machine:例如我的性能不咋地的MacBook)和一台远程机器(Remote Machine:性能强悍的台式机或者云主机),通过mainframer,就可以实现在本地机器上写代码,在远程机器上编译代码。你可以在笔记本上写代码,到了需要调试的时候,mainframer会快速同步代码到远程机器并进行编译,并将编译的结果返回到你的笔记本,这一切仿佛都是在你的笔记本上进行的,你可以正常的build和调试程序。这样一来,就可以享受笔记本的便捷,又能享受台式机的高性能了,美滋滋。

下面就是我配置成功后,录制的在MacBookPro上写代码,在Linux发行版Manjaro上进行Build的视频:

传送门

Read more

VIM常用命令

VIM在命令行环境中(比如操作VPS)非常实用,习惯之后对工作效率的提高大有裨益。但是剑一天不用,锈的也是很快的。前几天在终端中偶然发现了命令vimtutor,该教程非常巧妙简洁,整个教程操作一遍只需要半个小时左右,基本的操作就很熟悉了。现在将其小节汇总于下,方便记忆。

浏览命令

  1. 光标在屏幕文本中的移动既可以用箭头键,也可以使用 hjkl 字母键。 h (左移) j (下行) k (上行) l (右移)

  2. 欲进入 Vim 编辑器(从命令行提示符),请输入:vim 文件名 <回车>

  3. 欲退出 Vim 编辑器,请输入 <ESC> :q! <回车> 放弃所有改动。 或者输入 <ESC> :wq <回车> 保存改动。

  4. 在正常模式下删除光标所在位置的字符,请按: x

  5. 欲插入或添加文本,请输入: i 输入欲插入文本 <ESC> 在光标前插入文本 A 输入欲添加文本 <ESC> 在一行后添加文本

特别提示:按下 键会带您回到正常模式或者撤消一个不想输入或部分完整 的命令。

Read more

Mac上双硬盘导致的盘符变化和权限问题引起的Vbox虚拟机启动失败

最近在小米笔记本上安装了黑苹果,从Arch Linux上转到了MacOS High Sierra。说实话,虽然在操作上很多东西还不是很习惯,但是MacOS丰富的软件和漂亮的界面以及合理的逻辑非常讨人喜欢。

很快,我也遇到了一些问题,首先是经常用到的VirtualBox虚拟机启动物理硬盘上的Windows时遇到的问题:

  • 安装了双硬盘的笔记本在启动时设备符号是变化的,有时候是/dev/disk0,有时候则是/dev/disk1,导致保存的镜像文件(vmdk文件)需要重新生成。

  • Mac下只要重新挂载Windows分区所在的硬盘,权限也要重新授权。否则报错:

    1
    2
    3
    4
    VBoxManage: error: VMDK: could not open raw disk file '/dev/disk2'  
    VBoxManage: error: Error code VERR_RESOURCE_BUSY at /Users/vbox/tinderbox/4.3-mac-rel/src/VBox/Storage/VMDK.cpp(3390) in function int vmdkCreateRawImage(VMDKIMAGE*, VBOXHDDRAW*, uint64_t)
    VBoxManage: error: Cannot create the raw disk VMDK: VERR_RESOURCE_BUSY
    VBoxManage: error: The raw disk vmdk file was not created
Read more

Android面试相关知识点总结

Android相关


Activity和Fragment的生命周期

加速Activity启动

  • 精简onCreate中的代码
  • 将耗时操作放到后台线程
  • 优化布局文件( Hierarchy Viewer, Layoutopt)
  • 缓存ListView

Android多线程的几种方式

  • Handler.sendXXXMessage()
  • Handler.post(Runnable)
  • Activity.runOnUIThread(Runnable)
  • View.post(Runnable)
  • AsyncTask
Read more

编程题之数串

题目描述 设有n个正整数,将他们连接成一排,组成一个最大的多位整数。 如:n=3时,3个整数13,312,343,连成的最大整数为34331213。 如:n=4时,4个整数7,13,4,246连接成的最大整数为7424613。 输入描述: 有多组测试样例,每组测试样例包含两行,第一行为一个整数N(N<=100),第二行包含N个数(每个数不超过1000,空格分开)。 输出描述: 每组数据输出一个表示最大的整数。

1
2
3
4
5
6
7
8
9
10
11
示例1
输入

2
12 123
4
7 13 4 246
输出

12312
7424613
Read more

摆动排序-归并排序-归并排序

排序

- 摆动排序

给你一个没有排序的数组,请将原数组就地重新排列满足如下性质:

nums[0] <= nums[1] >= nums[2] <= nums[3]....

答案:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class Solution {
/**
* @param nums a list of integer
* @return void
*/
public void wiggleSort(int[] nums) {
for(int i=1; i<nums.length; i++){
if ((i%2==1 && nums[i-1]>nums[i])||
(i%2==0 && nums[i-1]<nums[i]))
swap(nums, i-1, i);
}

}

/**
* Swap two values
* */
public void swap(int[] nums, int i, int j) {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}

}
Read more

数据结构之二叉树相关


二叉树的相关术语:

树的结点:包含一个数据元素及若干指向子树的分支; 孩子结点:结点的子树的根称为该结点的孩子; 双亲结点:B 结点是A 结点的孩子,则A结点是B 结点的双亲; 兄弟结点:同一双亲的孩子结点; 堂兄结点:同一层上结点; 祖先结点: 从根到该结点的所经分支上的所有结点子孙结点:以某结点为根的子树中任一结点都称为该结点的子孙 结点层:根结点的层定义为1;根的孩子为第二层结点,依此类推; 树的深度:树中最大的结点层 结点的度:结点子树的个数 树的度: 树中最大的结点度。 叶子结点:也叫终端结点,是度为 0 的结点; 分枝结点:度不为0的结点; 有序树:子树有序的树,如:家族树; 无序树:不考虑子树的顺序; 参考

Read more
Your browser is out-of-date!

Update your browser to view this website correctly.&npsb;Update my browser now

×