Android 5.0 6.0 7.0 新特性
Android 5.0行为变更
API级别:21
Android Runtime(ART)
在 Android 5.0 中,ART 运行时取代 Dalvik 成为平台默认设置。Android 4.4 中已引入处于实验阶段的 ART 运行时。
有关 ART 的新功能概述,请参阅 ART 简介。部分主要的新功能包括: 预先 (AOT) 编译,改进的垃圾回收 (GC),改进的调试支持。
ART与Dalvik的区别
程序运行的过程中,Dalvik虚拟机在不断的进行将字节码编译成机器码的工作。ART引入了AOT这种预编译技术,在应用程序安装的过程中,ART就已经将所有的字节码重新编译成了机器码。应用程序运行过程中无需进行实时的编译工作,只需要进行直接调用.因此,ART极大的提高了应用程序的运行效率,同时也减少了手机的电量消耗,提高了移动设备的续航能力,在垃圾回收等机制上也有了较大的提升。
相对于Dalvik虚拟机模式,ART模式下Android应用程序的安装需要消耗更多的时间,同时也会占用更大的储存空间(指内部储存,用于储存编译后的代码),但节省了很多Dalvik虚拟机用于实时编译的时间。
大多数 Android 应用无需任何更改就可以在 ART 下工作。不过,部分适合 Dalvik 的技术并不适用于 ART。如需了解有关最重要问题的信息,请参阅在 Android Runtime (ART) 上验证应用行为。如存在以下情况,应特别注意:
- 您的应用使用 Java 原生接口 (JNI) 运行 C/C++ 代码。
- 您使用生成非标准代码的开发工具(例如,一些代码混淆工具)。
- 您使用与压缩垃圾回收不兼容的技术。
Material Design 样式
- 概念:融合卡片式,立体式的设计风格,强调层次感,动画,阴影等元素
- 国内翻译介绍:查看 http://design.1sters.com
- 官网介绍:http://developer.android.com/training/material
- 演示Android5.0 Demo
- Android UI样式风格发展:2.3版本(黄色丑陋版)->4.0(Holo)->5.0(MaterialDesign)
动态替换Theme
修改状态栏,ActionBar,界面背景,NavigationBar的颜色。让Activity使用自定义的Theme。
<style name="AppTheme" parent="@android:style/Theme.Material">
<!--状态栏颜色-->
<item name="android:colorPrimaryDark">#f00</item>
<!--ActionBar颜色-->
<item name="android:colorPrimary">#ff0</item>
<!--界面背景颜色-->
<item name="android:windowBackground">@color/colorWindowBackground</item>
<!--导航栏颜色-->
<item name="android:navigationBarColor">#00f</item>
</style>
动态替换Theme的步骤:
1.定义至少2套theme
2.调用setTheme方法设置当前的theme,但是该方法要在setContentView之前,如:
setTheme(mTheme);
setContentView(R.layout.activity_main);
设置了Theme,需要finish当前Activity,然后重启当前Activity,让Theme生效
Intent intent = getActivity().getIntent();
getActivity().finish();//结束当前的Activity
getActivity().overridePendingTransition(0,0);//不要动画
startActivity(intent);
Palette的使用
使用Palette可以让我们从一张图片中拾取颜色,将拾取到的颜色赋予ActionBar,StatusBar以及背景色可以让界面色调实现统一,使用Palette需要添加以下依赖:
compile 'com.android.support:palette-v7:23.0.0+'
Palette提供的API
传入Bitmap即可获取Palette对象,以下是同步和异步使用方式:
//同步获取,需要在子线程中使用
Palette palette = Palette.from(drawable.getBitmap()).generate();
//异步获取,可以在主线程中使用
Palette.from(drawable.getBitmap()).generate(new Palette.PaletteAsyncListener() {
@Override
public void onGenerated(Palette palette) {
//...
}
});
得到Palette对象后,获取其中的颜色,颜色对应如下:
颜色对应.jpg
使用palette获取指定颜色:
palette.getLightMutedColor(defaultColor);
也可以先获取采样对象Swatch,从Swatch中获取我们需要的颜色:
//获取有活力颜色的采样对象
Palette.Swatch vibrantSwatch = palette.getVibrantSwatch();
采样对象Swatch提供了以下方法来获取颜色:
//swatch.getPopulation(): the amount of pixels which this swatch represents.
//swatch.getRgb(): the RGB value of this color.
//swatch.getHsl(): the HSL value of this color,即色相,饱和度,明度.
//swatch.getBodyTextColor(): the RGB value of a text color which can be displayed on top of this color.
//swatch.getTitleTextColor(): the RGB value of a text color which can be displayed on top of this color
//一般会将getRgb设置给控件背景色,getBodyTextColor()设置给文字颜色
textView.setBackgroundColor(vibrantSwatch.getRgb());
textView.setTextColor(vibrantSwatch.getBodyTextColor());
CardView的使用
CardLayout拥有高度和阴影,以及轮廓裁剪,圆角等功能。
各属性说明:
- 设置圆角:card_view:cardCornerRadius="10dp"
- 设置高度:card_view:cardElevation="10dp"
- 设置内边距:card_view:contentPadding="10dp"
- 设置背景色:card_view:cardBackgroundColor="?android:attr/colorPrimary"
RecyclerView的使用
- https://developer.android.com/intl/zh-tw/training/material/lists-cards.html
- 先添加依赖 compile 'com.android.support:recyclerview-v7:23.1.1'
- 设置LayoutManager:控制RecyclerView如何显示布局,系统提供3个布局管理器:
- LinearLayoutManager:线性布局,有横向和竖直方向显示
- GridLayoutManager:网格布局,有横向和竖直方向显示
- StaggeredGridLayoutManager: 瀑布流布局,有横向和竖直方向显示
- 然后给RecyclerView设置Adapter<RecyclerView.ViewHolder>
- 设置点击事件,由于RecyclerView没有setOnItemClickListener,只能在Adapter中给View设置Click事件。
ToolBar的使用
它用来代替ActionBar,但是比ActionBar更加灵活,相当于可以写在布局文件中的ActionBar;与DrawerLayout的使用的时候,DrawerLayout可以覆盖在ToolBar上,并且ToolBar和ActionBar不能同时使用
使用ToolBar的步骤:
先隐藏ActionBar,可以继承一个不带ActionBar的Theme,如:
style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar"
然后在Activity中设置ToolBar替代ActionBar:
setSupportActionBar(toolBar);
最后设置ToolBar的显示内容:
toolBar.setTitle("ToolBar");//设置标题
toolBar.setNavigationIcon(iconRes);//设置图标
toolBar.setOnMenuItemClickListener();//设置Menu Item点击
Android 6.0行为变更
API级别:23
运行时权限
对于以 Android 6.0(API 级别 23)或更高版本为目标平台的应用,请务必在运行时检查和请求权限。其中:
- 新的方法checkSelfPermission()可以用来判断你的应用是否被授予了权限。
- 而requestPermissions()可请求权限。
//判断是否授予某个权限
public static boolean hasPermission(@NonNull Context context, @NonNull String... permissions) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
return true;
}
for (String permission : permissions) {
boolean hasPermission = (ContextCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED);
if (!hasPermission) {
return false;
}
}
return true;
}
//动态请求权限
public static void requestPermissions(Object o, int requestCode, String... permissions) {
if (o instanceof Activity) {
ActivityCompat.requestPermissions(((Activity) o), permissions, requestCode);
} else if (o instanceof android.support.v4.app.Fragment) {
((android.support.v4.app.Fragment) o).requestPermissions(permissions, requestCode);
}
}
取消支持Apache HTTP客户端
Android 6.0 版移除了对 Apache HTTP 客户端的支持。如果您的应用使用该客户端,并以 Android 2.3(API 级别 9)或更高版本为目标平台,请改用 HttpURLConnection 类。此 API 效率更高,因为它可以通过透明压缩和响应缓存减少网络使用,并可最大限度降低耗电量。要继续使用 Apache HTTP API,您必须先在 build.gradle 文件中声明以下编译时依赖项:
android {
useLibrary 'org.apache.http.legacy'
}
6.0新控件
使用需要依赖design类库:
compile 'com.android.support:design:23.0.0+'
TextInputLayout的使用
先在TextInputLayout中包裹一个EditText,如:
<android.support.design.widget.TextInputLayout
android:textColorHint="#fff"
android:id="@+id/username"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<EditText
android:textColor="#fff"
android:id="@+id/edt_user"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="user" />
</android.support.design.widget.TextInputLayout>
然后给EditText添加文本变化监听器:
editText.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
String name = username.getEditText().getText().toString();
//例如用户名必须包含 字母a
if (!name.contains("a")) {
username.setError("Not a valid user name!");
}else {
username.setErrorEnabled(false);
}
}
@Override
public void afterTextChanged(Editable s) {
}
});
实现效果:
TextInputLayout输入框效果图.gif
CoordinatorLayout的使用
CoordinatorLayout作为“super-powered FrameLayout”基本实现两个功能:
- 作为顶层布局
- 调度协调子布局
与FloatingActionButton结合使用
定义布局:
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end|bottom"
android:layout_margin="16dp"
android:src="@drawable/ic_done" />
</android.support.design.widget.CoordinatorLayout>
activity:
findViewById(R.id.fab).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Snackbar.make(view,"FAB",Snackbar.LENGTH_LONG)
.setAction("cancel", new View.OnClickListener() {
@Override
public void onClick(View v) {
//这里的单击事件代表点击消除Action后的响应事件
}
})
.show();
}
});
实现效果:
与AppBarLayout结合使用
定义布局:
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/main_content"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.AppBarLayout
android:id="@+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
app:layout_scrollFlags="scroll|enterAlways" />
<android.support.design.widget.TabLayout
android:id="@+id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</android.support.design.widget.AppBarLayout>
<android.support.v4.view.ViewPager
android:id="@+id/viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end|bottom"
android:layout_margin="@dimen/fab_margin"
android:src="@drawable/ic_done" />
</android.support.design.widget.CoordinatorLayout>
效果:
具体还有很多用法,这里不一一介绍,参考: CoordinatorLayout的使用
Android 7.0行为变更
API级别:24
新的Notification
Android N 添加了很多新的notifications API,进行了又一次的设计,引入了新的风格。
- 模板更新: 开发人员将能够充分利用新模板,仅仅需进行少量的代码调整。
- 消息样式自己定义: 新增自己定义样式、消息回复、消息分组等更加灵活。
- 捆绑通知: 系统能够将消息组合在一起(比如,按消息主题)并显示组。用户能够适当地进行 Dismiss 或 Archive 等操作。
- 直接回复: 对于实时通信应用。Android 系统支持内联回复,以便用户能够直接在通知界面中高速回复短信。
- 自己定义视图: 两个新的 API ,在通知中使用自己定义视图时能够充分利用系统装饰元素,如通知标题和操作。
Project Svelte:后台优化
Project Svelte在持续改善,以最大程度降低生态系统中一系列 Android 设备中系统和应用使用的 RAM。在 Android N 中,Project Svelte 注重优化在后台中运行应用的方式。
Android N 删除了三项隐式广播(CONNECTIVITY_ACTION、ACTION_NEW_PICTURE 和ACTION_NEW_VIDEO) 。以帮助优化内存使用和电量消耗。
权限更改
随着Android版本号越来越高,Android对隐私的保护力度也越来越大。
从Android6.0引入的动态权限控制(Runtime Permissions)到Android7.0的“私有文件夹被限制訪问”,“StrictMode API 政策”。这些更改在为用户带来更加安全的操作系统的同一时候也为开发人员带来了一些新的任务。怎样让你的APP能够适应这些改变而不是cash,是摆在每一位Android开发人员身上的责任。
文件夹被限制訪问,应用间共享文件
在Android7.0系统上。Android 框架强制运行了 StrictMode API 政策禁止向你的应用外公开 file:// URI。
假设一项包含文件 file:// URI类型 的 Intent 离开你的应用,应用失败,并出现 FileUriExposedException 异常,如调用系统相机拍照,或裁切照片。
解决方法:
第一步:在manifest清单文件里注冊provider
<!-- exported:要求必须为false,为true则会报安全异常。 -->
<!-- grantUriPermissions:true,表示授予 URI 临时访问权限。 -->
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.huayun.onenotice.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/filepaths" />
</provider>
第二步:指定共享的文件夹
为了指定共享的文件夹我们须要在资源(res)文件夹下创建一个xml文件夹,然后创建一个名为“filepaths”(名字能够随便起,仅仅要和在manifest注冊的provider所引用的resource保持一致就可以)的资源文件。内容例如以下:
<?xml version="1.0" encoding="utf-8"?>
<paths>
<!-- root-path 手机存储根目录 -->
<!-- external-path:sd ;path:你的应用保存文件的根目录;name随便定义-->
<external-path path="" name="camera_photos" />
</paths>
第三步:使用FileProvider
上述准备工作做完之后,如今我们就能够使用FileProvider了。
以调用系统相机拍照为例,我们须要将上述拍照代码改动为例如以下:
File file=new File(Environment.getExternalStorageDirectory(), "/temp/"+System.currentTimeMillis() + ".jpg");
if (!file.getParentFile().exists())file.getParentFile().mkdirs();
Uri imageUri = FileProvider.getUriForFile(context, "com.jph.takephoto.fileprovider", file);//通过FileProvider创建一个content类型的Uri
Intent intent = new Intent();
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); //加入这一句表示对目标应用暂时授权该Uri所代表的文件
intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);//设置Action为拍照
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);//将拍取的照片保存到指定URI
startActivityForResult(intent,1000);