Android 5.0行為變更
API級(jí)別:21
Android Runtime(ART)
在 Android 5.0 中,ART 運(yùn)行時(shí)取代 Dalvik 成為平臺(tái)默認(rèn)設(shè)置。Android 4.4 中已引入處于實(shí)驗(yàn)階段的 ART 運(yùn)行時(shí)。
有關(guān) ART 的新功能概述,請(qǐng)參閱 ART 簡(jiǎn)介。部分主要的新功能包括: 預(yù)先 (AOT) 編譯,改進(jìn)的垃圾回收 (GC),改進(jìn)的調(diào)試支持。
ART與Dalvik的區(qū)別
程序運(yùn)行的過(guò)程中,Dalvik虛擬機(jī)在不斷的進(jìn)行將字節(jié)碼編譯成機(jī)器碼的工作。ART引入了AOT這種預(yù)編譯技術(shù),在應(yīng)用程序安裝的過(guò)程中,ART就已經(jīng)將所有的字節(jié)碼重新編譯成了機(jī)器碼。應(yīng)用程序運(yùn)行過(guò)程中無(wú)需進(jìn)行實(shí)時(shí)的編譯工作,只需要進(jìn)行直接調(diào)用.因此,ART極大的提高了應(yīng)用程序的運(yùn)行效率,同時(shí)也減少了手機(jī)的電量消耗,提高了移動(dòng)設(shè)備的續(xù)航能力,在垃圾回收等機(jī)制上也有了較大的提升。
相對(duì)于Dalvik虛擬機(jī)模式,ART模式下Android應(yīng)用程序的安裝需要消耗更多的時(shí)間,同時(shí)也會(huì)占用更大的儲(chǔ)存空間(指內(nèi)部?jī)?chǔ)存,用于儲(chǔ)存編譯后的代碼),但節(jié)省了很多Dalvik虛擬機(jī)用于實(shí)時(shí)編譯的時(shí)間。

大多數(shù) Android 應(yīng)用無(wú)需任何更改就可以在 ART 下工作。不過(guò),部分適合 Dalvik 的技術(shù)并不適用于 ART。如需了解有關(guān)最重要問(wèn)題的信息,請(qǐng)參閱在 Android Runtime (ART) 上驗(yàn)證應(yīng)用行為。如存在以下情況,應(yīng)特別注意:
- 您的應(yīng)用使用 Java 原生接口 (JNI) 運(yùn)行 C/C++ 代碼。
- 您使用生成非標(biāo)準(zhǔn)代碼的開發(fā)工具(例如,一些代碼混淆工具)。
- 您使用與壓縮垃圾回收不兼容的技術(shù)。
Material Design 樣式
- 概念:融合卡片式,立體式的設(shè)計(jì)風(fēng)格,強(qiáng)調(diào)層次感,動(dòng)畫,陰影等元素
- 國(guó)內(nèi)翻譯介紹:查看 http://design.1sters.com
- 官網(wǎng)介紹:http://developer.android.com/training/material
- 演示Android5.0 Demo
- Android UI樣式風(fēng)格發(fā)展:2.3版本(黃色丑陋版)->4.0(Holo)->5.0(MaterialDesign)
動(dòng)態(tài)替換Theme
修改狀態(tài)欄,ActionBar,界面背景,NavigationBar的顏色。讓Activity使用自定義的Theme。
<style name="AppTheme" parent="@android:style/Theme.Material">
<!--狀態(tài)欄顏色-->
<item name="android:colorPrimaryDark">#f00</item>
<!--ActionBar顏色-->
<item name="android:colorPrimary">#ff0</item>
<!--界面背景顏色-->
<item name="android:windowBackground">@color/colorWindowBackground</item>
<!--導(dǎo)航欄顏色-->
<item name="android:navigationBarColor">#00f</item>
</style>
動(dòng)態(tài)替換Theme的步驟:
1.定義至少2套theme
2.調(diào)用setTheme方法設(shè)置當(dāng)前的theme,但是該方法要在setContentView之前,如:
setTheme(mTheme);
setContentView(R.layout.activity_main);
設(shè)置了Theme,需要finish當(dāng)前Activity,然后重啟當(dāng)前Activity,讓Theme生效
Intent intent = getActivity().getIntent();
getActivity().finish();//結(jié)束當(dāng)前的Activity
getActivity().overridePendingTransition(0,0);//不要?jiǎng)赢?startActivity(intent);
Palette的使用
使用Palette可以讓我們從一張圖片中拾取顏色,將拾取到的顏色賦予ActionBar,StatusBar以及背景色可以讓界面色調(diào)實(shí)現(xiàn)統(tǒng)一,使用Palette需要添加以下依賴:
compile 'com.android.support:palette-v7:23.0.0+'
Palette提供的API
傳入Bitmap即可獲取Palette對(duì)象,以下是同步和異步使用方式:
//同步獲取,需要在子線程中使用
Palette palette = Palette.from(drawable.getBitmap()).generate();
//異步獲取,可以在主線程中使用
Palette.from(drawable.getBitmap()).generate(new Palette.PaletteAsyncListener() {
@Override
public void onGenerated(Palette palette) {
//...
}
});
得到Palette對(duì)象后,獲取其中的顏色,顏色對(duì)應(yīng)如下:

使用palette獲取指定顏色:
palette.getLightMutedColor(defaultColor);
也可以先獲取采樣對(duì)象Swatch,從Swatch中獲取我們需要的顏色:
//獲取有活力顏色的采樣對(duì)象
Palette.Swatch vibrantSwatch = palette.getVibrantSwatch();
采樣對(duì)象Swatch提供了以下方法來(lái)獲取顏色:
//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
//一般會(huì)將getRgb設(shè)置給控件背景色,getBodyTextColor()設(shè)置給文字顏色
textView.setBackgroundColor(vibrantSwatch.getRgb());
textView.setTextColor(vibrantSwatch.getBodyTextColor());
CardView的使用
CardLayout擁有高度和陰影,以及輪廓裁剪,圓角等功能。
各屬性說(shuō)明:
- 設(shè)置圓角:card_view:cardCornerRadius="10dp"
- 設(shè)置高度:card_view:cardElevation="10dp"
- 設(shè)置內(nèi)邊距:card_view:contentPadding="10dp"
- 設(shè)置背景色: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'
- 設(shè)置LayoutManager:控制RecyclerView如何顯示布局,系統(tǒng)提供3個(gè)布局管理器:
- LinearLayoutManager:線性布局,有橫向和豎直方向顯示
- GridLayoutManager:網(wǎng)格布局,有橫向和豎直方向顯示
- StaggeredGridLayoutManager: 瀑布流布局,有橫向和豎直方向顯示
- 然后給RecyclerView設(shè)置Adapter<RecyclerView.ViewHolder>
- 設(shè)置點(diǎn)擊事件,由于RecyclerView沒有setOnItemClickListener,只能在Adapter中給View設(shè)置Click事件。
ToolBar的使用
它用來(lái)代替ActionBar,但是比ActionBar更加靈活,相當(dāng)于可以寫在布局文件中的ActionBar;與DrawerLayout的使用的時(shí)候,DrawerLayout可以覆蓋在ToolBar上,并且ToolBar和ActionBar不能同時(shí)使用
使用ToolBar的步驟:
先隱藏ActionBar,可以繼承一個(gè)不帶ActionBar的Theme,如:
style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar"
然后在Activity中設(shè)置ToolBar替代ActionBar:
setSupportActionBar(toolBar);
最后設(shè)置ToolBar的顯示內(nèi)容:
toolBar.setTitle("ToolBar");//設(shè)置標(biāo)題
toolBar.setNavigationIcon(iconRes);//設(shè)置圖標(biāo)
toolBar.setOnMenuItemClickListener();//設(shè)置Menu Item點(diǎn)擊
Android 6.0行為變更
API級(jí)別:23
運(yùn)行時(shí)權(quán)限
對(duì)于以 Android 6.0(API 級(jí)別 23)或更高版本為目標(biāo)平臺(tái)的應(yīng)用,請(qǐng)務(wù)必在運(yùn)行時(shí)檢查和請(qǐng)求權(quán)限。其中:
- 新的方法checkSelfPermission()可以用來(lái)判斷你的應(yīng)用是否被授予了權(quán)限。
- 而requestPermissions()可請(qǐng)求權(quán)限。
//判斷是否授予某個(gè)權(quán)限
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;
}
//動(dòng)態(tài)請(qǐng)求權(quán)限
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 版移除了對(duì) Apache HTTP 客戶端的支持。如果您的應(yīng)用使用該客戶端,并以 Android 2.3(API 級(jí)別 9)或更高版本為目標(biāo)平臺(tái),請(qǐng)改用 HttpURLConnection 類。此 API 效率更高,因?yàn)樗梢酝ㄟ^(guò)透明壓縮和響應(yīng)緩存減少網(wǎng)絡(luò)使用,并可最大限度降低耗電量。要繼續(xù)使用 Apache HTTP API,您必須先在 build.gradle 文件中聲明以下編譯時(shí)依賴項(xiàng):
android {
useLibrary 'org.apache.http.legacy'
}
6.0新控件
使用需要依賴design類庫(kù):
compile 'com.android.support:design:23.0.0+'
TextInputLayout的使用
先在TextInputLayout中包裹一個(gè)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添加文本變化監(jiān)聽器:
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) {
}
});
實(shí)現(xiàn)效果:

CoordinatorLayout的使用
CoordinatorLayout作為“super-powered FrameLayout”基本實(shí)現(xiàn)兩個(gè)功能:
- 作為頂層布局
- 調(diào)度協(xié)調(diào)子布局
與FloatingActionButton結(jié)合使用
定義布局:
<?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) {
//這里的單擊事件代表點(diǎn)擊消除Action后的響應(yīng)事件
}
})
.show();
}
});
實(shí)現(xiàn)效果:

與AppBarLayout結(jié)合使用
定義布局:
<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級(jí)別:24
新的Notification
Android N 添加了很多新的notifications API,進(jìn)行了又一次的設(shè)計(jì),引入了新的風(fēng)格。
- 模板更新: 開發(fā)人員將能夠充分利用新模板,僅僅需進(jìn)行少量的代碼調(diào)整。
- 消息樣式自己定義: 新增自己定義樣式、消息回復(fù)、消息分組等更加靈活。
- 捆綁通知: 系統(tǒng)能夠?qū)⑾⒔M合在一起(比如,按消息主題)并顯示組。用戶能夠適當(dāng)?shù)剡M(jìn)行 Dismiss 或 Archive 等操作。
- 直接回復(fù): 對(duì)于實(shí)時(shí)通信應(yīng)用。Android 系統(tǒng)支持內(nèi)聯(lián)回復(fù),以便用戶能夠直接在通知界面中高速回復(fù)短信。
- 自己定義視圖: 兩個(gè)新的 API ,在通知中使用自己定義視圖時(shí)能夠充分利用系統(tǒng)裝飾元素,如通知標(biāo)題和操作。
Project Svelte:后臺(tái)優(yōu)化
Project Svelte在持續(xù)改善,以最大程度降低生態(tài)系統(tǒng)中一系列 Android 設(shè)備中系統(tǒng)和應(yīng)用使用的 RAM。在 Android N 中,Project Svelte 注重優(yōu)化在后臺(tái)中運(yùn)行應(yīng)用的方式。
Android N 刪除了三項(xiàng)隱式廣播(CONNECTIVITY_ACTION、ACTION_NEW_PICTURE 和ACTION_NEW_VIDEO) 。以幫助優(yōu)化內(nèi)存使用和電量消耗。
權(quán)限更改
隨著Android版本號(hào)越來(lái)越高,Android對(duì)隱私的保護(hù)力度也越來(lái)越大。
從Android6.0引入的動(dòng)態(tài)權(quán)限控制(Runtime Permissions)到Android7.0的“私有文件夾被限制訪問(wèn)”,“StrictMode API 政策”。這些更改在為用戶帶來(lái)更加安全的操作系統(tǒng)的同一時(shí)候也為開發(fā)人員帶來(lái)了一些新的任務(wù)。怎樣讓你的APP能夠適應(yīng)這些改變而不是cash,是擺在每一位Android開發(fā)人員身上的責(zé)任。
文件夾被限制訪問(wèn),應(yīng)用間共享文件
在Android7.0系統(tǒng)上。Android 框架強(qiáng)制運(yùn)行了 StrictMode API 政策禁止向你的應(yīng)用外公開 file:// URI。
假設(shè)一項(xiàng)包含文件 file:// URI類型 的 Intent 離開你的應(yīng)用,應(yīng)用失敗,并出現(xiàn) FileUriExposedException 異常,如調(diào)用系統(tǒng)相機(jī)拍照,或裁切照片。
解決方法:
第一步:在manifest清單文件里注冊(cè)provider
<!-- exported:要求必須為false,為true則會(huì)報(bào)安全異常。 -->
<!-- grantUriPermissions:true,表示授予 URI 臨時(shí)訪問(wèn)權(quán)限。 -->
<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)文件夾下創(chuàng)建一個(gè)xml文件夾,然后創(chuàng)建一個(gè)名為“filepaths”(名字能夠隨便起,僅僅要和在manifest注冊(cè)的provider所引用的resource保持一致就可以)的資源文件。內(nèi)容例如以下:
<?xml version="1.0" encoding="utf-8"?>
<paths>
<!-- root-path 手機(jī)存儲(chǔ)根目錄 -->
<!-- external-path:sd ;path:你的應(yīng)用保存文件的根目錄;name隨便定義-->
<external-path path="" name="camera_photos" />
</paths>
第三步:使用FileProvider
上述準(zhǔn)備工作做完之后,如今我們就能夠使用FileProvider了。
以調(diào)用系統(tǒng)相機(jī)拍照為例,我們須要將上述拍照代碼改動(dòng)為例如以下:
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);//通過(guò)FileProvider創(chuàng)建一個(gè)content類型的Uri
Intent intent = new Intent();
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); //加入這一句表示對(duì)目標(biāo)應(yīng)用暫時(shí)授權(quán)該Uri所代表的文件
intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);//設(shè)置Action為拍照
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);//將拍取的照片保存到指定URI
startActivityForResult(intent,1000);