PC和Android模拟器之间虚拟串口通信

前言

很多时候我们在做串口通信的时候需要去模拟串口来调试,这样可以极大的方便我们的工作,不然的话可能需要连接硬件设备,比较麻烦。一般情况下我们先在电脑上模拟串口后初步调试,最后阶段在硬件设备上实际调试。

工具介绍

Virtual Serial Port Driver

Virtual Serial Port Driver

该软件提供虚拟串行端口的仿真,并通过虚拟零调制解调器电缆对可用的串行端口进行配对。与此软件配对的两个应用程序可以交换数据。每个端口上的每个数据都显示在计算机的设备管理器中以便查看,同时COM端口模拟其预期设置和运行进程。用户可以创建虚拟端口,而不必担心串行端口不足和物理硬件拥挤。该软件的下一个优势是能够与ActiveX、DDL和核心级实用程序等技术集成。

官网地址:https://www.virtual-serial-port.org/

Modbus的ASCII和RTU通信

Modbus介绍

Modbus 协议是应用于电子控制器上的一种通用语言。通过此协议,控制器相互之间、控制器经由网络(例如以太网)和其它设备之间可以通信。Modbus协议定义了一个控制器能认识使用的消息结构,而不管它们是经过何种网络进行通信的。它描述了一控制器请求访问其它设备的过程,如果回应来自其它设备的请求,以及怎样侦测错误并记录。它制定了消息域格局和内容的公共格式。

Modbus 是一个请求/应答协议。也叫做 SlaveMasterServerClient

同一种设备在不同领域的不同叫法,Slave和Server意思相同,Master和Client意思相同。

  • Slave:工业自动化用语;响应请求;
  • Master:工业自动化用语;发送请求;
  • Server:IT用语;响应请求;
  • Client:IT用语;发送请求;

协议分类

ModBus协议是应用层报文传输协议(OSI模型第7层),它定义了一个与通信层无关的协议数据单元(PDU),即PDU=功能码+数据域

Modbus通信栈

Android中的串口通信

串口通讯

在计算机之间、计算机内部各部分之间,通信可以以串行和并行的方式进行。一个并行连接通过多个通道(例如导线、印制电路布线和光纤)在同一时间内传播多个数据流;而串行在同一时间内只连接传输一个数据流

虽然串行连接单个时钟周期能够传输的数据比并行数据更少,前者传输能力看起来比后者要弱一些,实际的情况却常常是,串行通信可以比并行通信更容易提高通信时钟频率,从而提高数据的传输速率。

串口通讯和并行通讯的区别

可以从上图看到,并行通讯可以一次传输8字节的数据,而串口一次只传输一个字节。但是通常串行通信都凭借其更低廉的部署成本成为更佳的选择,尤其是在远距离传输中。许多集成电路都具有串行通信接口来减少引脚数量,从而节约成本。

串口通讯的接口标准有很多,最常见的为RS-232、RS-485和USB等,下面我们看一下RS-232的接口标准。

串口通讯示意图

Handler和HandlerThread

Hander

Hander的主要作用有两个:

  1. 延迟处理消息。
  2. 在其他线程处理消息。

这里的消息可以理解为MessageRunnable,通过如下方法来调度消息。

方法作用
post(Runnable)将Runnable对象添加到消息队列
postAtTime(java.lang.Runnable, long)加入消息队列,在特定时间执行Runnable对象
postDelayed(Runnable, Object, long)加入消息队列,延迟执行
sendEmptyMessage(int)仅仅发送what值消息
sendMessage(Message)将Message对象加入队列
sendMessageAtTime(Message, long)同理
sendMessageDelayed(Message, long)同理

Runnable实际上是将该Runnable匿名对象排入队列,在其他线程执行该消息,这里的其他线程可以理解为MessageQueue所在的线程。

Google官方架构组件Lifecycle和LiveData

前言

在Google 2017年的IO大会上面发布了一些可以帮助开发人员创建更容易维护和更强大的应用程序,Lifecycle就是其中的一个,它可以帮助我们更好的处理Android组件和声明周期相关的问题。

Lifecycle

Lifecycle是一个类,它持有关于组件(如 Activity 或 Fragment)生命周期状态的信息,并且允许其他对象观察此状态。

引入Lifecycle扩展库

1
2
implements "android.arch.lifecycle:runtime:${architectureComponentsVersion}"
implements "android.arch.lifecycle:extensions:${architectureComponentsVersion}"

Android结构设计系列[2]--解耦合

声明:

本文是对Mark Allison系列博客的翻译和学习笔记,感谢作者提供的demo和这么好的博客。

在上一篇《Android结构设计系列[1]–初识工程》中我们认识了我们显示天气的APP,接下来将开始我们的结构优化。

在优化项目结构之前我们得先知道什么样的工程才是结构合理的工程。在最早的一篇博文中我对这个问题进行了简要归纳,请参考《六大设计原则浅析》,符合这些设计原则的工程就是一个结构合理的工程,我们要实现这样的结构得先从耦合性方面考虑,第一步我们先做分离。

逻辑分离

接下来我们回顾一下上一篇中的工程目录结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
src
│ Converter.kt #转换工具类
│ WeatherStationApplication.kt #自定义的Application

├─model
│ Common.kt #天气数据具体的Json实体类
│ Current.kt #天气数据接口接收实体类

├─net
│ OpenWeatherMap.kt #Retrofit的Api Service定义接口

└─ui
CurrentWeatherFragment.kt #天气显示Fragment
MainActivity.kt #主界面
NoPermissionFragment.kt #无权限fragment
PreferencesFragment.kt #设置fragment

从整个结构和上一篇的分析中会发现大部分逻辑都集中在CurrentWeatherFragment,包括获取位置信息、初始化网络请求框架、请求数据、绑定显示数据。获取位置信息的方式有很多种,部分手机并不支持系统获取定位,这个时候我们需要更换定位系统,则会发现我们的定位是和逻辑混合在一起,不容易拆解而且更加麻烦的是不容易进行单元测试。接下来我们将定位功能先拆分出来。

Android结构设计系列[1]--初识工程

声明:

本文是对Mark Allison系列博客的翻译和学习笔记,感谢作者提供的demo和这么好的博客。

前言

从标题上想必大家已经猜出来了,从本篇开始将是一个系列的Android工程结构设计博文,我们将从一个简单的获取天气并展示的APP开始,一步步的重构并研究如何更好的设计整个工程的结构。本系列中一部分知识点在以前的博文中可以找到相关知识,另一部则是新的框架和特性,如果遇到会详细说明。

说明:在本系列中我会认为大家能熟练使用Kotlin开发Android项目,并且会使用Retrofit、RxJava等主流框架,这些技术会从一开始就会出现在源码中。

显示天气

本案例中的天气数据来自 OpenWeatherApp API,在该页面注册后会发送一份邮件包含一个API Key。

Android中的DownloadManager使用

前言

在Android开发中经常会用到将一个文件下载到本地存储卡,这个过程看起来很容易,就是一个网络请求过程而已,但是有的时候我们需要把下载的内容存储到一个可以公共访问的位置,供其他应用共享,这个时候我们可以使用Android官方提供的一个DownloadManage来很方便的实现。事实上DownloadManage自API 9就已经存在了,中间官方只做了一些小的调整。

下载文件

下面通过一个下载图片的小Demo来一步步理解DownloadManager的使用和涉及到的一些内在知识,类的基本关系如下。

Demo结构

接下来开始一个简单的UI实现,放一个按钮并添加点击事件。

1
2
3
4
5
6
7
8
9
10
11
12
13
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent">

<Button
android:id="@+id/download"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/download"
android:layout_centerInParent="true"/>
</RelativeLayout>

Android中自定义键盘和输入法

前言

关于自定义键盘搜索了一下,网上基本上是通过android.inputmethodservice.Keyboard实现的,但是打开Google文档却发现在Android Q中这个类将被废弃。

This class is deprecated because this is just a convenient UI widget class that application developers can re-implement on top of existing public APIs. If you have already depended on this class, consider copying the implementation from AOSP into your project or re-implementing a similar widget by yourselves.

通过Keyboard实现自定义是很容易的,只需要自定义键盘xml即可:

1
2
3
4
5
6
7
8
9
10
11
<Keyboard
android:keyWidth="%10p"
android:keyHeight="50px"
android:horizontalGap="2px"
android:verticalGap="2px" >
<Row android:keyWidth="32px" >
<Key android:keyLabel="A" />
...
</Row>
...
</Keyboard>

这种自定义键盘的方式存在着很多缺点(更准确的说应该是很多不足):

  1. 在Android Pad上面的支持有问题。
  2. 不能够实现动态更改键盘顺序和位置,或者动态控制和隐藏部分键。

Android系统启动过程

参考链接:

《深入理解Android 卷I》
《Linux 的启动流程》
《Android系统架构开篇》

引言

Google官方提供的经典分层架构图,从下往上依次分为Linux内核、HAL、系统Native库和Android运行时环境、Java框架层以及应用层这5层架构,其中每一层都包含大量的子模块或子系统。

Android系统架构

这幅图很清晰的展现了Android系统从下往上的层次关系,这种关系恰好也是整个系统启动大过程的缩影。

init是Linux系统中用户空间的第一个进程,要搞清楚Android的启动过程,我们先来看一下Linux系统的启动过程。

Linux启动过程

Linux启动过程

第一步:加载内核

操作系统接管硬件以后,首先读入 /boot 目录下的内核文件

第二步:启动初始化进程

内核文件加载以后,就开始运行第一个程序 /sbin/init,它的作用是初始化系统环境。

由于init是第一个运行的程序,它的进程编号(pid)就是 1。其他所有进程都从它衍生,都是它的子进程。

通过MediaScanner理解JNI原理

参考链接:

《深入理解Android 卷I》

什么是JNI

JNI是Java Native Interface的缩写(Java本地调用),Java程序中的函数可以调用Native语言写的函数(一般指的是C/C++编写的函数),Native语言写的函数可以调用Java层的函数。

什么是JNI

Java语言的跨平台是因为在不同平台上可以运行Java虚拟机,而虚拟机是跑在具体平台上的,而本质上Java是通过JNI技术实现的跨平台,很多基层的模块在Java语言诞生之前已经有了比较优秀的实现,为了避免重复造轮子所以我们要使用JNI技术来使用已有的模块。JNI技术与Java应运而生,它也是推动Java快速发展的真正原因。

Android开发中Kotlin的扩展库及实现Parcelable

参考链接:

《Kotlin文档–Kotlin Android 扩展》
《Kotlin Android扩展和findViewById说再见》

在使用Kotlin开发Android中我们可以使用安卓扩展库来方便Android开发。

1
2
3
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions' //扩展库

Kotlin开发Android的奇技淫巧记录

参考链接:

《聊一聊Kotlin扩展函数run,with,let,also和apply的使用和区别》

前面几篇我们了解了kotlin的语法和概念的东西,接下来我们在实际使用中看看kotlin带给我们的惊喜。

扩展函数的利用

现象

先来看一段代码:

1
2
3
val avaliableTime: String?
avaliableTime = R.string.avaliable_time.resToString("3年")
println(avaliableTime)

其中 avaliable_time 资源的定义如下

1
<string name="avaliable_time">有效期%s</string>

最终打印结果为:有效期3年

上面这个特点就是Kotlin扩展函数带给我们的福利。

Android热修复技术窥探

参考链接:

《Android热修复技术,你会怎么选?》
《Android热修复技术选型——三大流派解析》
《阿里云热修复使用文档》
《热修复——深入浅出原理与实现》
《Android Hook技术防范漫谈》
《深入探索Android热修复技术原理》

什么是热修复

关于热修复这个名词,并不陌生。相信大家都有过更新window补丁的经历,通过补丁可以动态修复系统的漏洞,只不过这个过程对用户而言是可选及自行操作。

Android热修复过程

那么关于Android平台的热修复技术,简单来说,就是通过下发补丁包,让已安装的客户端动态更新,让用户可以不用重新安装APP,就能够修复软件缺陷的一种技术。

随着热修复技术的发展,不仅可以修复代码,同时可以修复资源文件及SO库。

Android历史版本变迁

参考链接:

《最强Android书:架构大剖析》
《Android Version History》

截止目前,Android 9 Pie已发布, 官网所列出的版本如下。

产品代号Android版本API
Pie928
Oreo8.026 or 27
Nougat7.1 and 7.024 or 25
Marshmallow6.023
Lollipop5.1 and 5.021 or 22
KitKat4.4-4.4.419 or 20

截止2018 年 10 月 26 日各个版本的使用用户数量统计如下:

Android各个版本使用统计

Android历史版本

Android历史版本

Cupcake(杯子饼干)

Cupcake

其实Android 1.5版本并不是第一个Android版本,但是这个版本之前的都没有代号,这就说明了这个版本的特殊性和重要性。

最初的Android Cupcake使用的是第三方的PC样式的键盘方式,拥有小部件(Widgets),可以直接上传资料到YouTobe和Picasa.

这个版本正如它的名字一样,是一个很紧凑的版本(你想,将一个蛋糕放入杯子中是不是这个蛋糕很精细紧凑)。

Donut(甜甜圈)

Donut

Android 1.6版本,代号“Donut 甜甜圈”在2009年9月发布,它解决了系统会自动重启的系统漏洞,更新了图形绘制和视频等功能,而且引入了很多搜索功能。

此版本第一次兼容多种大屏幕尺寸设备,第一次搭载google的转弯导航功能。

Kotlin中的object关键字

参考链接

《知乎-kotlin学习之路》
《Kotlin中文文档》

Kotlin中使用object关键字来代替Java中的匿名内部类实现。

在Java中很多时候我们需要一个一次性对象,可以使用匿名内部类来实现,如下:

1
2
3
4
5
6
7
Thread thread = new Thread(){

@Override
public void run(){
System.out.println("hello world");
}
}

在Kotlin中也支持同样的写法:

1
2
3
4
5
val thread: Thread = object : Thread(){
override fun run(){
println("hello world")
}
}

Kotlin的数据类型和集合

参考链接

《Kotlin实战》

基本类型

在Kotlin中并不区分基本数据类型和包装类型,例如:

1
2
3
4
5
6
val i: Int = 1
val list: List<Int> = listOf(1, 2, 3)

fun showProgress(progress: Int){
val percent = progress.coerceIn(0, 100)
}

大多数情况下Kotlin的Int类型会被编译成Java的基本数据类型,用作泛型类型参数的基本类型会被编译成Java的包装类型。

在Kotlin中的可空类型不能用Java的基本类型表示(例如:Int?、Boolean?),这个时候会被编译成对应的Java包装类型。

1
var list: List<Int> = listOf(1, 2, 3)

上面代码的listOf集合类的参数是泛型,所以会编译成java的包装类型,所以要高效的存储基本类型建议用数组来存储。

Kotlin的可空性

参考链接

《Kotlin实战》

可空性是Kotlin的一个重要特性,可以帮助我们避免发生NullPointerException.

可空类型

1
2
3
int strLen(String s){
return s.length();
}

上面的Java代码如果我们传入空参数就会导致NullPointerException.

但是,和上面等价含义的Kotlin语句在编译期就能标记出错误,如下:

1
2
3
4
fun strLen(s: String) = s.length

>>> strLen(null)
ERROR: Null can not be a value of non-null type String

函数参数被声明为String类型,所以必须包含一个非null的String实例,这样在Kotlin中就保证了不会在运行时抛出NullPointerException.

Kotlin中的by关键字

参考链接

《Kotlin - By 关键字介绍》
《Kotlin实战》
《Kotlin中文文档》
《java_my_life的博客》

装饰器模式

装饰器模式又名包装模式,来以对客户透明的方式(客户端并不觉得修饰前后的区别)扩展对象的功能,是继承关系的一种替代方案。

在装饰模式中的角色有:

  • 抽象构件(Component)角色:给出一个抽象接口,以规范准备接收附加责任的对象。
  • 具体构件(ConcreteComponent)角色:定义一个将要接收附加责任的类。
  • 装饰(Decorator)角色:持有一个构件(Component)对象的实例,并定义一个与抽象构件接口一致的接口。
  • 具体装饰(ConcreteDecorator)角色:负责给构件对象“贴上”附加的责任。

Lambda编程

参考链接

《知乎:Lambda 表达式》
《Kotlin实战》
《Kotlin中文文档》

Lambda表达式本质上就是可以传递给其他函数一小段代码。

有了Lambda可以轻松地把通用代码结构抽取成函数库,Kotlin标准库大量使用了它。

什么是Lambda

我们知道,对于一个Java变量,我们可以赋给其一个“值”。如果你想把“一块代码”赋给一个Java变量,应该怎么做呢?

在Java 8之前,这个是做不到的。但是Java 8问世之后,利用Lambda特性,就可以做到了。

1
2
3
aBlockOfCode = public void doSomeShit(String s){
System.out.println(s);
}

简便写法

1、public和函数名是多余的,因为已经赋值给了aBlockOfCode.
2、编译器可以自动判断参数类型和返回类型。
3、只有一行可以省略大括号。

1
aBlockOfCode = (s) -> System.out.println(s);

这样我们就将一个代码块成功赋值给了变量,那么aBlockOfCode的类型是什么呢?

Android获取本地视频及其缩略图

ContentProvider

在获取本地视频前我们先对Android四大组件之一的ContentProvider进行回顾。

问题1:ContentProvider的作用

用户应用程序之间共享数据(比如我们要获取共享数据系统相册和系统视频),ContentProvider是程序间共享数据的一种协议的定义。
如果我们要将A应用的数据共享给B应用,就需要A应用重写ContentProvider来具体实现这种协议。

ContentProvider的作用简单的说就是定义一种通用的数据暴漏方式。

ContentProvider是一个抽象类,重写该类需要实现的方法如下:

  • onCreate() which is called to initialize the provider
  • query(Uri, String[], String, String[], String) which returns data to the caller
  • insert(Uri, ContentValues) which inserts new data into the content provider
  • update(Uri, ContentValues, String, String[]) which updates existing data in the content provider
  • delete(Uri, String, String[]) which deletes data from the content provider
  • getType(Uri) which returns the MIME type of data in the content provider

Android实现的一个点赞动画

摘要

使用Canvas和状态模式实现一个点赞效果

点赞动画效果

关键步骤

1. 获取Bitmap对象和Bitmap对象释放。

创建

1
BitmapFactory.decodeResource(getResources(), R.drawable.encourage_gif_big);

回收

1
2
3
4
5
if(bitmap != null && !bitmap.isRecycled()){   
bitmap.recycle();
bitmap = null;
}
System.gc();

如果图片过大可以压缩

1
2
3
4
5
6
//压缩,用于节省BITMAP内存空间--解决BUG的关键步骤    
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inSampleSize = 2; //这个的值压缩的倍数(2的整数倍),数值越小,压缩率越小,图片越清晰

//返回原图解码之后的bitmap对象
bitmap = BitmapFactory.decodeResource(Context, ResourcesId, opts);

2. 创建画笔,设置画笔。

1
2
3
mBitmapPaint = new Paint();
mBitmapPaint.setAntiAlias(true);
mBitmapPaint.setAlpha(255);

3. canvas绘制Bitmap

1
2
3
4
float scale = 1 - (1f - END_SCALE) / TOTAL_TIME * currentTime;
Matrix matrix = new Matrix();
matrix.postScale(scale, scale, mWidth / 2, mHeight / 2);
canvas.drawBitmap(mLikesBitmap, matrix, mBitmapPaint);

4. 分析动画状态,分解状态

动画状态

将动画过程分解成几个阶段,然后定义基类(模板方法)

5. 计算各个状态的变化过程,用总时间等分绘制。

1
float scale = 1 - (1f - END_SCALE) / TOTAL_TIME * currentTime;

关键点

  1. 简单自定义View实现

重写onDraw()

  1. 状态模式的使用

分解状态,将复杂问题拆分解决的思路。

Dagger2入门学习之MVP项目整合(下)

上一篇Dagger2入门学习之MVP项目整合(上)的最后我们列举了Dagger的关键注释,其中@Singleton和@Scope还没有接触,接下来我们来先看看这两个标签的使用。

@Singleton

类似于SharedPreferences对象,我们可能在整个App的生命周期中只需要一个单例,而不需要每次都通过application.getSharedPreferences(“spfile”, Context.MODE_PRIVATE)获得新的对象,那么怎么办呢,我们只需要在你需要单例的对象提供方法上加一个注解@Singleton ,类似这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Module
public class AppModule {

private MyApplication application;

public AppModule(MyApplication application) {
this.application = application;
}

//全局单例SharedPreferences
@Provides
@Singleton
SharedPreferences provideSharedPreferences() {
return application.getSharedPreferences("spfile", Context.MODE_PRIVATE);
}

@Provides
MyApplication provideApplication() {
return application;
}
}

只需要一个@Singleton,无论我们在多少个Activity容器中通过@Inject获取这个SharedPreferences对象的实例,该对象都是同一个对象,从而实现了全局单例的效果。

Dagger2入门学习之MVP项目整合(上)

Dagger基础回顾

在前面一篇Dagger2基础传送门我们得出了一个结论。

  1. 若一个类(Xx)的构造函数被@inject标注,则该类编译时会产生Xx_Factory.
  2. 若一个类(Xx)的成员变量被@inject标注,则该类编译时会产生Xx_MembersInjector.
  3. @Component标注的接口(Xx)在编译时生成DaggerXx,负责将上面两个联系起来。

下面我们通过前面提到的这个例子再来回顾一下这个结论

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* Created by 水寒 on 2017/11/16.
*/

public class Province {

@Inject
public City city;

@Inject
public Province(City city) {
this.city = city;
}

public String showAddress() {
return "四川省" + city.show();
}
}

Dagger2会在编译过程中生成对应的依赖项,这些依赖项在Android Studio该路径下,如图所示:

Dagger依赖生成文件目录

Android 浅色状态栏设置

前言

转载说明:本文转载自Loyea 的个人博客

我们都知道,安卓可以自定义状态栏是从 API19(4.4) 开始的,Google 给 KitKat 引入了 translucentStatusBar 特性。从此,安卓也可以像 iOS 一样自定义状态栏的颜色,甚至可以将布局布到状态栏后面。然而,一如往常谷歌出的东西都是坑的尿性,谷歌却没考虑到将状态栏设置为浅色后,状态栏上的文字和图标辨识困难的问题。(这不叫黑,这叫爱的深沉)

直到 Google 在 2015 年的 Google I/O 大会上推出了一个安卓状态栏的新特性:LightStatusBarWindow,即所谓的浅色状态栏模式。从 API19 到 API23 过了整整四个大版本,这才解决了这个问题。没错,重要的东西总是晚来一步。

瞎扯淡

然而,早在谷歌之前,国内的魅族与小米早已在自家的 Rom 中添加了浅色状态栏的功能。最低甚至支持 4.4 。但是很多安卓开发者并不知道此事,以至于很多 app 使用了浅色的状态栏导致用户无法看清状态栏上的文字图标。

浅色状态栏

左图是数字尾巴,正确使用了浅色状态栏模式。右图是某知名P2P app,未使用浅色状态栏模式,右上角的充电图标证明了该 app 并不是全屏状态而是的确没用浅色状态栏

Android Studio3.0依赖方式

Android Studio3.0正式版已经出来了,相比2.x的版本,编译速度提高了不少。
当我们使用AS3.0新建项目时会发现,默认的依赖由之前的compile更改为implementation了。

Android studio版本更新至3.0,更新中,连带着com.android.tools.build:gradle
工具也升级到了3.0.0,在3.0.0中使用了最新的Gralde 4.0 里程碑版本作为gradle的编译版本,该版本gradle编译速度有所加速,更加欣喜的是,完全支持Java8。当然,对于Kotlin的支持,在这个版本也有所体现,Kotlin插件默认是安装的。

下面我们来看看他们之前的差异:

2.x版本的依赖方式

在com.android.tools.build:gradle 3.0 以下版本依赖在gradle 中的声明写法

1
compile fileTree(dir: 'libs', include: ['*.jar'])

2.x中支持的依赖方式有:

  • Compile
  • Provided
  • APK
  • Test compile
  • Debug compile
  • Release compile

3.0版本的依赖方式

在3.0后的写法为

1
implementation fileTree(dir: 'libs', include: ['*.jar'])

1
api fileTree(dir: 'libs', include: ['*.jar'])

3.0中支持的依赖方式有:

  • API
  • Compile only
  • Runtime only
  • Unit Test implementation
  • Test implementation
  • Debug implementation
  • Release implementation

可以看到在Android studio3.0中,compile依赖关系已被弃用,被implementation和api替代,provided被compile only替代,apk被runtime only替代,剩下的看名字就知道了。

Activity启动模式与任务栈(Task)全面深入记录(下)

通过上一篇文件的分析,我们对Activity的启动模式有了比较清晰的了解后,本篇我们将继续对Activity启动模式的相关参数和任务栈分析,接下来我们就继续上一篇的问题,如何通过taskAffinity属性在同一个应用中创建多个任务栈进行探究。

任务栈之taskAffinity属性

TaskAffinity特点如下:

  • TaskAffinity 参数标识着Activity所需要的任务栈的名称,默认情况下,一个应用中所有Activity所需要的任务栈名称都为该应用的包名。
  • TaskAffinity 属性一般跟singleTask模式或者跟allowTaskReparenting属性结合使用,在其他情况下没有实际意义。
  • TaskAffinity属性的值不能与当前应用包名相同,否则其值跟作废没两样。

Activity启动模式与任务栈(Task)全面深入记录(上)

任务栈简单入门

最近又把两本进阶书看了一遍,但总感觉好记性不如烂笔头,所以还是决定通过博客记录一下,我们将分两篇来全面深入地记录Activity 启动模式与任务栈的内容。

android任务栈简单了解

  1. android任务栈又称为Task,它是一个栈结构,具有后进先出的特性,用于存放我们的Activity组件。

  2. 我们每次打开一个新的Activity或者退出当前Activity都会在一个称为任务栈的结构中添加或者减少一个Activity组件,因此一个任务栈包含了一个activity的集合, android系统可以通过Task有序地管理每个activity,并决定哪个Activity与用户进行交互:只有在任务栈栈顶的activity才可以跟用户进行交互。

  3. 在我们退出应用程序时,必须把所有的任务栈中所有的activity清除出栈时,任务栈才会被销毁。当然任务栈也可以移动到后台, 并且保留了每一个activity的状态. 可以有序的给用户列出它们的任务, 同时也不会丢失Activity的状态信息。

  4. 需要注意的是,一个App中可能不止一个任务栈,某些特殊情况下,单独一个Actvity可以独享一个任务栈。还有一点就是一个Task中的Actvity可以来自不同的App,同一个App的Activity也可能不在一个Task中。

嗯,目前android任务栈的概念我们就大概了解到这。下面我们主要还是来聊聊android的4种启动模式。

FileProvider

前言

在Android中经常会遇到存储和访问文件,一般情况下我们会使用Context#openFileOutput()或者Context#getCacheDir()来获得文件存储路径,但是这两种方式存储的文件只能在APP内部访问,不能共享给其他APP访问。这个时候我们就需要将文件存储在外部存储卡上面,使用Environment#getExternalStorageDirectory()或者Environment#getDownloadCacheDirectory(),但是这样带来了两个潜在的问题。

  1. 所有应用都可以访问该数据,造成安全问题,我们只希望部分应用可访问。
  2. 为了读写该文件APP需要有READ_EXTERNAL_STORAGEWRITE_EXTERNAL_STORAGE权限,需要访问的其他APP也需要READ_EXTERNAL_STORAGE权限才能读取。对于内容的提供者我们不能确保访问的应用程序就一定有READ_EXTERNAL_STORAGE权限 。

因此使用file://... URI来共享文件并不好,替代方案就是定义一个ContentProvider,使用content://... URI来共享文,而FileProvider是对ContentProvider的进一步封装,专门用于文件共享。

FileProvider是什么

FileProvider是ContentProvider的一个特殊子类,它通过创建一个 content:// Uri 来使应用程序相关的文件实现安全共享:file:/// Uri.

之前我们在使用URL来访问内容的时候可以使用 Intent.setFlags() 来设置一些临时访问权限,这些Google认为是不安全的,所以从Android7.0开始执行了“StrictMode API 政策禁”,来使用FileProvider来解决这个访问权限问题。

对接网易云信UIKit遇到的那些坑

这两天在对接网易云信的IM和实时音视频,为了速度所以使用了网易提供的IM界面库UIKit,对接一切都比较顺利,过程中遇到了一个发图片的问题(java.io.IOException: open failed: EACCES (Permission denied))

网易云信uikit--java.io.IOException

我们来看看到底是怎么回事?

具有立体感的Material风格循环滚动Banner

摘要

最近在项目中要实现如下效果,在GitHub上搜了一下找到一个很不错的案例,但是没有实现自动循环,所以我决定来在该项目基础上修改一番,下图是我实现的两个效果。

一场APP界面

滑动动画

GitHub项目地址:https://github.com/yarolegovich/DiscreteScrollView

使用CoordinatorLayouts实现的首页炫酷效果

摘要

介绍CoordinatorLayout和AppBarLayout的各自用法以及嵌套使用原理并实现如下炫酷效果

CoordinatorLayout

CoordinatorLayout

Android Studio 3.0 Release新功能

Android Studio 3.0的Release版本终于发布了,赶快去更新吧

Mac Os的朋友注意了,在你更新旧版本的Android Studio的时候可能会遇到一个更新错误对话框,提示“Some conflicts were found in the installation area”。你忽略此错误就可以了并单击取消即可继续安装。

最新Gradle 3.0.0插件

最新的Gradle3.0.0插件改进和提升了很多功能,主要是提高了对具有大量modules的项目的构建性能,如果你的项目有大量的modules你可以尝试一下下面这些改变。

这个版本还包含下面特性

Kotlin的支持

google2017年的IO大会上Kotlin编程语言在Android上被正式支持。所以在这个版本中,Android Studio包含了Android开发的Kotlin语言支持。

你可以采用混合的方式,可以将一部分Java代码通过( Code > Convert Java File to Kotlin File)快捷键来转换成kotlin的代码,你也可以创建一个完全kotlin的工程。

Convert Java File to Kotlin File

Java 8语言特性支持

你现在可以使用某些Java 8语言功能,并使用Java 8来书写你的java代码了,Jack不再是必须的,你应该禁用掉Jack.

Android Studio 3.0配置Java 8

Android分析器

最新的Android分析器replaces the Android Monitor tool提供了一套新的工具来实时测量您的应用程序的CPU,内存和网络使用情况

通过View > Tool Windows > Android Profiler 打开面板

replaces the Android Monitor tool

CPU分析

关于详细的CPU使用情况分析传送门

replaces the Android Monitor tool

内存分析

可以帮助你找出内存泄漏问题,你查看实时内存变化,可以跟踪内存分配和回收情况,内存分析详细传送门

replaces the Android Monitor tool

网络请求分析

Network Profiler允许您监视应用程序的网络活动,检查每个网络请求的有效负载,并链接回生成网络请求的代码。

关于更多内存分析请看传送门

replaces the Android Monitor tool

PhysicsBasedAnimation学习

概述

Google I/O ‘17推出了许多新的特性,在动画这一块又有新的API供开发者使用,具体视频请见Android Animations Spring to Life (Google I/O ‘17),主要介绍了Physics-based Animations,在动画API中引入了DynamicAnimation,并介绍了它的两个子类FlingAnimation和SpringAnimation的使用,开发者可以使用新的API创建更加动态化的动画。

Spring Animation

Spring Animation

FlingAnimation

FlingAnimation

Dagger2入门学习记录

最近在重新搭建android工程听到dagger2这个框架,然后去Github上看了一下,天啊!2w多的star,呃,是应该看一下这玩意是个什么东西了,竟然这么火。

百度了一下大概看了一下其他关于dagger的文章大概知道这玩意是干啥的了。

Dagger2是Dagger的升级版,是一个依赖注入框架,现在由Google接手维护。

我们要搞清楚这个框架怎么用必须先知道什么是依赖注入和依赖注入的好处。

什么是依赖注入

依赖注入是面向对象编程的一种设计模式,其目的是为了降低程序耦合,这个耦合就是类之间的依赖引起的。

举个例子:我们在写面向对象程序时,往往会用到组合,即在一个类中引用另一个类,从而可以调用引用的类的方法完成某些功能,就像下面这样.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class ClassA {
...
ClassB b;
...
public ClassA() {
b = new ClassB();
}

public void do() {
...
b.doSomething();
...
}
}

这个时候就产生了依赖问题,ClassA依赖于ClassB,必须借助ClassB的方法,才能完成一些功能。这样看好像并没有什么问题,但是我们在ClassA的构造方法里面直接创建了ClassB的实例,问题就出现在这,在ClassA里直接创建ClassB实例,违背了单一职责原则,ClassB实例的创建不应由ClassA来完成;其次耦合度增加,扩展性差,如果我们想在实例化ClassB的时候传入参数,那么不得不改动ClassA的构造方法,不符合开闭原则。

Android Transition学习笔记

概述

Android 4.4.2 (API level 19)引入Transition框架,之后很多APP上都使用该框架做出很酷炫的效果,如 Google Play Newsstand app

Google Play Newsstand app

在app中适当得使用上Transition能带来较好的用户体验,视频中介绍了该框架的基本使用以及其中核心的一些类和方法,只有学会这些基本的API才能在之后的Activity/Fragment过渡定制一些自己想要的效果。

Android Studio 实用小技巧

概述

一般的什么快捷键,技巧的文章也有很多。我也看过很多。下面这些事我在来自国外大神发布的:Android Studio Tips of the Day (https://plus.google.com/u/0/collection/wtO0PB) 查看到的,而且对于我来说有帮助的及没用过的。

Android Studio 快捷键

Android Studio Tips of the Day (https://plus.google.com/u/0/collection/wtO0PB) 里面一共有八十几个。大家可以去查看完整的。而且是持续更新状态中。很有用(记得安全上网,翻墙哦。)

Android属性动画Interpolator和ViewPropertyAnimator的用法

本篇文章中使用的代码是建立在上篇文章基础之上的,如果你还没有阅读过前面的文章,建议先去参考阅读一下 Android中的属性动画基础用法Android中的属性动画高级用法

Interpolator的用法

Interpolator这个东西很难进行翻译,直译过来的话是补间器的意思,它的主要作用是可以控制动画的变化速率,比如去实现一种非线性运动的动画效果。那么什么叫做非线性运动的动画效果呢?就是说动画改变的速率不是一成不变的,像加速运动以及减速运动都属于非线性运动。

不过Interpolator并不是属性动画中新增的技术,实际上从Android 1.0版本开始就一直存在Interpolator接口了,而之前的补间动画当然也是支持这个功能的。只不过在属性动画中新增了一个TimeInterpolator接口,这个接口是用于兼容之前的Interpolator的,这使得所有过去的Interpolator实现类都可以直接拿过来放到属性动画当中使用,那么我们来看一下现在TimeInterpolator接口的所有实现类,如下图所示:

Interpolator的用法

可以看到,TimeInterpolator接口已经有非常多的实现类了,这些都是Android系统内置好的并且我们可以直接使用的Interpolator。每个Interpolator都有它各自的实现效果,比如说AccelerateInterpolator就是一个加速运动的Interpolator,而DecelerateInterpolator就是一个减速运动的Interpolator。

Android中的属性动画高级用法

阅读本篇文章需要你对属性动画有一定的了解,并且掌握属性动画的基本用法,如果你还对属性动画不够了解的话,建议先去阅读 Android中的属性动画基本用法

ValueAnimator的高级用法

在上一篇文章中ValueAnimator.ofFloat()方法就是实现了初始值与结束值之间的平滑过度,那么这个平滑过度是怎么做到的呢?其实是系统内置了一个FloatEvaluator,它通过计算告知动画系统如何从初始值过度到结束值,我们来看一下FloatEvaluator的代码实现:

1
2
3
4
5
6
public class FloatEvaluator implements TypeEvaluator {  
public Object evaluate(float fraction, Object startValue, Object endValue) {
float startFloat = ((Number) startValue).floatValue();
return startFloat + fraction * (((Number) endValue).floatValue() - startFloat);
}
}

可以看到,FloatEvaluator实现了TypeEvaluator接口,然后重写evaluate()方法。evaluate()方法当中传入了三个参数,第一个参数fraction非常重要,这个参数用于表示动画的完成度的,我们应该根据它来计算当前动画的值应该是多少,第二第三个参数分别表示动画的初始值和结束值。那么上述代码的逻辑就比较清晰了,用结束值减去初始值,算出它们之间的差值,然后乘以fraction这个系数,再加上初始值,那么就得到当前动画的值了。

Android中的属性动画基础用法

补间动画的缺陷

Android3.0开始引入了属性动画(property animation),有人说属性动画弥补了之前的补间动画和逐帧动画的缺陷,到底是什么缺陷呢?在开始补间动画之前我们先来了解一下这两大缺陷。

  • 无法完成移动、缩放、旋转和淡入淡出操作之外的其他动画。
  • 动画只能作用到View上,不能脱离View存在(否则没意义)。

Android常见异常处理

什么是异常

Exception是指在程序运行过程中所出现的不可预测的可处理可恢复的问题,这些错误会干扰到指令的正常执行,从而造成程序的异常退出或者意外终止。比如:FileNotFountException、NullPointException.

Error是指程序运行过程中较为严重的不可挽回的问题,大多数错误与代码编写者执行的操作无关,而表示代码运行时 JVM(Java 虚拟机)出现的问题。比如OutOfMemeryError,一旦出现错误程序就要挂。

异常分类

MVP架构的Android基础框架

说明

这是我开源的一个基于MVP架构的Android开发基础框架,源码开放在gitlab上。

仓库地址:https://gitlab.com/lxqxsyu/TestKotlin

框架介绍

MVP架构,Retrofit+Rxjava+Okhttp网络请求,可切换Glide和Fresco图片框架,封装基础刷新分页加载,部分功能后期会有所改进。

框架整体结构

框架整体结构

Android和iOS的UI要设计一致吗?

概述

我个人偏向于遵守各自平台规范,你可能就有疑问了,不一致岂不是设计要增加很多工作量吗?这个疑问确实戳中了一个点,但是不是这个问题的要害,我们先来假设UI要求完全一致和不一致两种情况。

iOS的界面UI风格

Android 6.0/7.0权限问题

Android6.0动态权限控制

Android6.0系统

在Android6.0(M)之前,在用户安装应用的时候会产生一个权限列表,只有用户允许这些权限后,应用才可以正常的安装,这就会产生一个问题,这些权限对用户是不具有感知性的,也就是说用户都不知道你要这些权限干什么,我明明装的是一个阅读类型的应用,你却要我拨打电话的权限,你想干嘛呢?当然绝大部分的开发者是善意的,但也避免不了一些特殊人群利用这些“漏洞”做一些不好的事情。

而在Android6.0(M)之后,用户是可以不管权限直接安装应用的,当应用需要调用某些权限的时候,会给予用户一个通知与说明,我要这些权限干什么,这样下来可以让用户有更加清醒的权限分配意识,也在一定程度上更加人性化的保护了用户的隐私,避免了“权限一刀切”。

Android文件存储

Android文件存储

首先我们打开DDMS,有一个File Explorer,如下:

File Explorer

这里有三个文件夹需要我们重视,一个是data,一个是mnt,一个是storage,我们下面就详细说说这三个文件夹。

内部存储(Internal Storage)

data文件夹就是我们常说的内部存储,当我们打开data文件夹之后(没有root的手机不能打开该文件夹),里边有两个文件夹值得我们关注,如下:

Internal Storage

从响应式编程谈RxJava

参考链接:

《简书上Season_zlc的RxJava2.0系列》(https://www.jianshu.com/c/299d0a51fdd4)
《Github-RxJava》(https://github.com/ReactiveX/RxJava)
《Github-RxAndroid》(https://github.com/ReactiveX/RxAndroid)
《RxJava2.0 Doc》(http://reactivex.io/RxJava/2.x/javadoc/)
《Wiki-diffrent in 2.0》(https://github.com/ReactiveX/RxJava/wiki/What's-different-in-2.0)

响应式编程

响应式编程是一种基于异步数据流概念的编程模式

响应式编程关键性概念就是事件,在某种程度上,这并不是什么新东西。事件总线(Event buses)或咱们常见的单击事件就是一个异步事件流,你可以观察这个流,也可以基于这个流做一些自定义操作(原文:side effects,副作用,本文皆翻译为自定义操作)。响应式就是基于这种想法。你能够创建所有事物的数据流,而不仅仅只是单击和悬停事件数据流。 流廉价且无处不在,任何事物都可以当作一个流:变量、用户输入、属性、缓存、数据结构等等。比如,假设你的微博评论就是一个跟单击事件一样的数据流,你能够监听这个流,并做出响应。

最重要的是,有一堆的函数能够创建(create)任何流,也能将任何流进行组合(combine)和过滤(filter)。 这正是“函数式”的魔力所在。一个流能作为另一个流的输入(input),甚至多个流也可以作为其它流的输入。你能合并(merge)两个流。你还能通过过滤(filter)一个流得到那些你感兴趣的事件。你能将一个流中的数据映射(map)到一个新的流中。

响应式编程流模型

Android中的SVG

SVG是什么

Android 5.0(Lollipop, API 21)后,新增了 <vector> 标签,以 VectorDrawable 的形式支持 SVG 类型矢量图形(SVG本质为XML标记描述的图形)。

Vector图像刚发布的时候,是只支持Android 5.0+的,对于Android pre-L的系统来说,并不能使用,所以,可以说那时候的Vector并没有什么卵用。不过自从AppCompat 23.2之后,Google对p-View的Android系统也进行了兼容,也就是说,Vector可以使用于Android 2.1以上的所有系统,只需要引用com.android.support:appcompat-v7:23.2.0以上的版本就可以了,这时候,Vector应该算是迎来了它的春天。

SVG:可缩放矢量图形是基于可扩展标记语言(标准通用标记语言的子集),用于描述二维矢量图形的一种图形格式。它由万维网联盟制定,是一个开放标准。SVG 使用 XML 格式定义图形

与其他图像格式相比,使用 SVG 的优势在于:

  • 可被非常多的工具读取和修改(比如记事本)
  • 与 JPEG 和 GIF 图像比起来,尺寸更小,且可压缩性更强。
  • 是可伸缩的
  • 图像可在任何的分辨率下被高质量地打印
  • 可在图像质量不下降的情况下被放大
  • 图像中的文本是可选的,同时也是可搜索的(很适合制作地图)
  • 可以与 Java 技术一起运行
  • 是开放的标准
  • 文件是纯粹的 XML
  • 成熟、稳定,前端已经非常广泛的进行使用了

理解Android中的JNI

什么是JNI

JNI是Java Native Interface的缩写(Java本地调用),Java程序中的函数可以调用Native语言写的函数(一般指的是C/C++编写的函数),Native语言写的函数可以调用Java层的函数。

JNI结构示意图

为什么要有JNI

Java语言的跨平台是因为在不同平台上可以运行Java虚拟机,而虚拟机是跑在具体平台上的,而本质上Java是通过JNI技术实现的跨平台,很多基层的模块在Java语言诞生之前已经有了比较优秀的实现,为了避免重复造轮子所以我们要使用JNI技术来使用已有的模块。

Ajax Android AndroidStudio Animation Anroid Studio AppBarLayout Banner Buffer Bulma ByteBuffer CDN CMYK COM1 COM2 CSS Camera Raw, 直方图 Chrome ContentProvider CoordinatorLayout C语言 DML DOM Dagger Dagger2 Darktable Demo Document DownloadManage Element Error Exception Extensions File FileProvider Fresco Git GitHub GitLab Gradle Groovy HTML5 Handler HandlerThread Hexo Hybrid IDEA IO ImageMagick IntelliJ Intellij Interpolator JCenter JNI JS Java JavaScript JsBridge Kotlin Lab Lambda Lifecycle Linux Looper MVC MVP Maven MessageQueue Modbus Momentum MySQL NDK NIO NexT Next Nodejs ObjectAnimator Oracle VM Permission PhotoShop Physics Python RGB RS-232 RTU Retrofit Runnable RxAndroid RxJava SE0 Spring SpringBoot Statubar Task Theme Thread Tkinter UI UIKit UML VS Code ValueAnimator ViewPropertyAnimator Web Web前端 Workbench api apk by关键字 compileOnly css databases demo hexo hotfix html iOS icarus implementation init jQuery javascript launchModel logo merge mvp offset photos pug query rxjava2 scss servlet shell svg tkinter tomcat transition unicode utf-8 vector virtual box 七牛 下载 中介者模式 串口 主题 事件 享元模式 仓库 代理模式 位运算 依赖注入 修改,tables 光和色 内核 函数 函数式编程 分支 分析 创建 删除 动画 单例模式 压缩图片 发布 可空性 合并 同向性 后期 启动模式 命令 命令模式 响应式 响应式编程 图层 图床 图片压缩 图片处理 图片轮播 地球 域名 基础 增加 备忘录模式 外观模式 多线程 大爆炸 天气APP 太白山 奇点 字符集 存储引擎 宇宙 实践 属性 属性动画 工具 工厂模式 年终总结 异常 弱引用 恒星 打包 技巧 插件 摄影 操作系统 攻略 故事 数据库 数据类型 文件 新功能 旅行 旋转木马 时序图 时空 时间简史 曲线 杂谈 权限 架构 查询 标签选择器 样式 核心 框架 案例 桥接模式 模块化 模板引擎 模板方法模式 泛型 浅色状态栏 源码 瀑布流 热修复 版本 版本控制 状态栏 状态模式 生活 留言板 相册 相对论 知识点 码云 磁盘 科学 笔记 策略模式 类图 系统,发行版, GNU 索引 组件 组合模式 结构 编码 网易云信 网格布局 网站广播 网站通知 网络 美化 膨胀的宇宙 自定义 自定义View 自定义插件 蒙版 虚拟 补码 表单 装饰模式 西安 观察者模式 规范 视图 视频 解耦器模式 设计 设计原则 设计模式 访问者模式 语法 责任链模式 贪吃蛇 转换 软件工程 软引用 运算符 迭代子模式 适配器模式 选择器 通信 通道 配置 锐化 错误 键盘 闭包 降噪 面向对象 项目构建 黑洞
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×