Android瘋狂講義前10章知識點總結

Android瘋狂講義前10章知識點總結

/-------------------------10-31號晚上學習筆記----------------------------/
在設置了最小支持版本爲18及以上的時候,需要將獲得actionBar組件的包引用改爲
import androidx.appcompat.app.ActionBar; 即可。

2.11.3:啓用程序圖標導航:
已實現

2.11.4:添加ActionView組件:

有些時候只可以使用監聽事件處理機制

3.2基於監聽的事件處理:
控制飛機移動實例實現:
邏輯:{
1.先創建一個飛機畫圖的view類
2.然後再mainActivity中創建一個內部類作爲監聽器
3.爲飛機的view對象設置監聽器實現對用戶手勢的監聽
}





實現對於事件監聽的監聽器的設置方式:{
內部類
外部類(該監聽器主要被很多GUI界面共享)
mainActivity實現監聽器接口
使用Lambda表達式實現監聽器
}




如果確實有多個監聽器需要同一個業務邏輯組件,那麼我們可以將這些業務邏輯
使用業務邏輯組件進行定義

3.2.5中Activity本身作爲事件監聽器類{
該種方法出現的問題:{
1.會造成程序結構的混亂(因爲Activity類主要是用來初始化頁面)
2.會覺得比較怪異
}
}




3.2.6 Lambda表達式作爲事件監聽器類:{
使用原因:
大部分的事件監聽器沒有複用價值(因爲可以複用的都設置爲事務邏輯組件)

實際上Lambda表達式時目前使用最爲廣泛的監聽器的實現形式:{
實現形式:
textView.setOnClickListener(view -> show.setText(“xxx”));

}

}

直接綁定到標籤:{

}

基於回調的事件處理:{
機制可以通過自定義View來實現,自定義View時重寫該view的事件處理方法即可
此時的事件處理還是事件源本身來進行的
}


基於監聽的事件處理中,事件源和事件處理是分開的。

3.3.2-基於回調的事件傳播:{
如果事件處理的返回值是:true 表示該事件不會進行傳播;
如果事件處理的返回值是:false 表示該事件會進行傳播;

事件可以進行傳播的情況下-觸發事件的順序是:{
1.自定義組件中實現的監聽器內容
2.給組件註冊的監聽器中的內容
3.該組件所在的activity中的OnTouchEvent()方法中
}
}




3.4 響應系統設置的事件:{
3.4.1 Configuration 類{
作用:專門用於描述手機設備上的配置信息{包括的是用戶特定的配置項和系統的動態配置項}
實例:獲取系統設備狀態{
實現步驟:{
第一步:獲取系統當前的Configuration對象
第二步:調用Configuration對象的屬性來獲取設備狀態
}
}
}
}









重寫onConfigurationChanged()方法響應系統設置更改:

重點:Handler消息傳遞機制{
作用:處於對性能的優化。安卓的UI操作並不是線程安全的,這意味着如果有
多個線程併發操作UI組件,有可能導致的線程安全問題。爲了解決的這個問題,使用了
handler處理機制。


在啓動主線程的時候,即是UI界面只可以被主線程修改。但是後期也會繼續
對UI界面進行修改,那麼就需要使用Handler事件處理機制

handler類的作用主要有兩個:{
1.在新啓動的線程中發送消息
2.在主線程中獲取、處理消息
}


實例:實現自動播放的動畫
}

一個線程對應的是一個Looper()對象
在線程中使用Handler的步驟如下:
{
1.調用Looper的perpare()方法爲當前線程創建Looper對象,創建Lopper對象的時候
它的構造器會創建與之配套的MessageQueue();
2.有了Looper之後,創建Handler子類的實例,重寫handlemMessage()方法,
該方法負責處理來自其他線程的消息
3.調用Looper()的loop()方法啓動Looper
}







//實例:使用線程計算質數
(使用另外一個線程計算的原因是:否則會導致ANR異常)

重點:不要在UI界面中引入一些過多的操作

3.6 使用異步任務{
AsyncTask實現調用的時候需要的是系統進行調用
實例:使用異步任務執行下載
}


截止到:234/767(電子版)

/-----------------------------2020-12-15號下午學習筆記-------------------------------/

第四章學習筆記:

使用activity繼承自LauncherActivity實現的是整個activity作爲一個列表實現渲染。

android應用要求所有的應用程序組件都必須顯式進行配置
使用bundle在Activity之間交換數據
bundle是一個簡單的數據攜帶包 該bundle對象包含了多個方法來存儲數據{
putxxx()
putSerializable()
}等




intent中的提供的putExtra()方法以及向intent中存儲數據其實還是用的bundle中的數據
如果調用以上的方法時,intent中沒有bundle對象,那麼就創建一個bundle對象
//截止到2020-12-15日下午 16:02學習筆記

2020-12-15日晚上學習筆記:
4.2Activity回調機制:
Activity中的回調和web中的回調是類似的
程序架構中的點:可以是接口形式存在也可以是抽象方法實現(後者就是Activity中的調用機制的實現方法)
回調實現的第一種實現方式就是典型的命令者模式
當前活動的Activity在棧頂
在onStart()方法之後一定會回調onResume()方法





Activity中的數據展示是由UI組件搭建而成的,但是Servlet中的數據的顯示是由瀏覽器直接生成的

Android採用Task對多個Activity進行管理
當啓動應用的時候Android會自動創建一個Task,然後是啓動應用的入口Activity(也就是在intent-filter和zoo那個配置爲
MAIN和LAUNCHER的Activity



開發者無法真正訪問Task(因爲Android並沒有爲Task組件提供一個接口)
但是可以通過所在的Activity中使用getTaskId()獲得其對應的Task的Id。

先啓動的Activity放到棧底然後後啓動的放到棧頂

Android中的幾種啓動方式:
{
standard:表示的是每一次啓動的時候只有一個Task也就是說後來啓動的都是直接覆蓋到原來的Task上(但是會產生很多的實例)
singleTop模式:表示的是基本上和standard差不多,有區別的地方在於:當將要創建的Activity在棧頂的時候,
系統就不再創建一個新的實例
singleTask模式:採用的singleTask這種加載模式的Activity能保證在同一個Task中只有一個實例,當系統採用這種模式的時候
分爲三種情況:
{
1.如果將要啓動的目標Activity不在,系統將會創建目標Activity的實例,並將它加入Task棧頂
2.如果已經位於棧頂,那麼此時與singleTop模式的行爲相同
3.如果是已經存在但是沒有在棧頂,那麼系統會將所有的Acticity移除棧頂從而使得目標的Activity在棧頂
}
}











singleInstance模式:
{
採用本模式的時候,無論系統從哪個Task啓動目標Activity,只會創建一個目標Activity實例,並會使用一個全新的
Task棧來加載該Activity實例


並且採用本模式的時候有兩種情況:
{
1.如果目標不存在,系統會創建一個全新的task並創建一個Activity並將它加入到新的task的棧頂
2.如果已經存在,那麼系統都會把它調出來放到前臺
}
}




需要說明的是採用singleInstance的模式創建Activity時,一個Task只包含一個Activity
設置xml文件中的加載模式的同時需要設置的是exported="true"對應的是:表示該Activity可以被其他應用啓動

4.5 Android 0 升級的Fragment:
Fragment擁有自己的生命週期,並且也可以接受它自己的輸入事件

Fragment必須被嵌入到Activity中使用(就說明:Fragment自身的生命週期也會受到Activity的控制)
也就是說只有當Activity活動的時候,程序員纔可以對其中的fragment進行操作

通常來說,創建Fragment類的時候需要實現的方法是:
{
1。onCreate()方法
2.onCreateView()方法(當Fragment繪製組件的時候回調該方法,該方法返回的一個View表示該Fragment顯示的View)
3.onPause()方法
}




創建一個對應的ListFragment類,無需重寫onCreateView()方法

對於需要添加一個Fragment組件的Activity組件也需要繼承自support-fragment下面的FragmentActivity
否則會出現錯誤。

實現大屏顯示圖書詳情fragment邏輯(自己總結):
首先先創建一個BookListFragment類(其中定義了一個interface接口,然後在Main2Activity中實現對應的callBacks接口,
在接口中實現的是對應於該特定Activity下的顯示邏輯,那就是將來在BookDetailFragment中顯示數據的傳遞邏輯(使用的是)
Bundle + setArguments() + getSupportFragmentManager().beginTransaction().replace(R.id.book_detail_container, bookFragment).commit();)
這裏重點說明一下:對於callBacks接口來說,不同的Main2Activity下,有不同的實現邏輯。
然後是,每一次在點擊了Main2Activity中的左邊的listFragment中的項之後,都會在右邊的detailfragment中的onCreate()方法
從而實現對於數據的更新。
對於listFragment來說,直接在Main2Activity中的xml文件中第一次渲染的時候就調用了對應的onCreate()方法。








/------------------------12-16號晚上學android學習筆記--------------------------/
page 268回顧筆記:
在Activity中使用fragment的時候可以使用id或者是tag屬性來標記fragment對象

4.5.4 fragment管理與fragment事務:
fragmentManager對象可以實現的功能是:{
1.使用findFragmentById()方法或者是findFragemntByTag()方法可以獲得
在該Activity中綁定的Fragment組件
2.使用popBackStack()方法獎Fragment從後臺彈出,模擬用戶按下back返回鍵的情形
3.使用addOnBackStackChangeListener()註冊一個監聽器,用於監聽後臺棧的變化
}





需要添加 刪除 替換 Fragment對象可以使用的是FragmenTransaction對象
(該對象代表的是Activity對Fragment執行的多個改變)

在使用事務對象commit之前,可以使用addToBackStack()方法將該事務對象添加到backStack
中,然後當用戶按下回退的時候,直接返回的是上一個fragment的狀態

實例:開發兼顧屏幕分辨率的應用
爲了實現這個目的可以在res/目錄下爲大屏幕,600dpi的屏幕建立相應的
資源文件夾:values-large,values-sw600dp,在該文件夾下建立一個名爲
refs.xml的引用資源文件。
該資源文件專門用於定義各種引用項。



實現上述目的的邏輯(自我總結):
首先在res/目錄下面創建一個values-large文件夾,裏面創建一個資源對象主要是用來存放對應資源文件

<?xml version="1.0" encoding="utf-8"?> @layout/activity_main2 然後在Main2Activity中的onCreate()方法中使用if語句判斷當前佈局界面是否包含container,如果是, 就表明是大屏幕顯示,此時出現的listFragment是存在於activity_main2.xml中的booklist文件(此時還需要設置 此時的book_list組件時單選模式,用來實現大屏顯示的效果(即:左邊點擊右邊顯示詳情)) 對於Main2Activity中的實現的onItemSelected()方法來說,需要判斷是否是大屏顯示,如果是和原來的邏輯一樣 如果不是大屏顯示,那麼需要在點擊了對應的list之後跳轉到對應的bookDetailActivity中,用來實現詳情的顯示。 在BookDetailActivity的onCreate()方法中,使用如下語句來創建新的顯示詳情的bookDetailFragment對象 if(savedInstanceState == null){ //創建BookFragment對象 BookDetailFragment bookDetailFragment = new BookDetailFragment(); //創建Bundle對象 Bundle bundle = new Bundle(); bundle.putInt(BookDetailFragment.ITEM_ID, getIntent().getIntExtra(BookDetailFragment.ITEM_ID,0));
        //向Fragment傳入參數
        bookDetailFragment.setArguments(bundle);
        //將指定fragment添加到book_detail_container容器中
        getSupportFragmentManager().beginTransaction()
                .add(R.id.book_detail_container,bookDetailFragment).commit();
    }

並在其中實現了對應的actionBar點擊之後的時間方法邏輯:
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {

    if(item.getItemId() == android.R.id.home) {
        //創建啓動的MainActivity的Intent
        Intent intent = new Intent(this,Main2Activity.class);
        //添加額外的Flag,獎Activity棧中處於Main2Activity之上的Activity彈出來
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        //啓動intent對應的Activity
        startActivity(intent);
        return true;
    }
    return super.onOptionsItemSelected(item);
}

至此,根據屏幕大小實現不同的顯示的邏輯得以實現。

//截止到2020-12-17日凌晨(0:45)
截止到(270)

/**------------------------------2020/12/20號下午學習筆記-----------------------------*/
Fragement生命週期:
其中的onAttach()、onCreate()等,方法在該fragment被加入到對應的activity中的時候只會別調用一次。
onCreateView()方法在每一次被回調的時候創建一次。


最常用的是就是onCreateView()方法。

4.7管理Fragment導航
Android的support-fragment中下提供了一個ViewPager組件,該組件非常方便實現分頁導航。
ViewPager只是一個容器組件,其中顯示的內容可由Adapter進行提供。
{其中使用的PageAdapter和FragmentPageAdapter子類(該子類是專門用於管理多個Fragment的)}


實例:結合ViewPager實現分頁導航。
實例:結合TabLayout實現Tab導航。

由於tablayout需要appcompat主題的支持,需要設置實例的主題是dark.actionbar

//第5章:使用intent和IntentFilter通信
使用intent提供了一致的編程模型,並且可以降低耦合。
這裏的Intent有點類似於spring、sprngMVC中的邏輯視圖名的設計。
Android中包含三種重要的組件:
{
Activity
Service
BroadcastReceiver
}







//5.2 Intent的屬性和intent-filter配置
1.Component屬性
創建一個ComponentName需要指定包名和類名(這樣就可以唯一指定一個組件類)
Android中的context代表了訪問該應用環境信息的接口,包名是作爲應用的唯一標識,故
context和包名是一一對應的關係。
制定了Component的intent已經明確了它將要啓動的那個組件,因此這種intent被稱爲顯示intent
沒有指定Component的intent被稱爲隱式intent
隱式intent沒有指定要啓動那個組件,所以會啓動符合條件的組件,但是具體是哪一個組件
是不確定的。







當intent使用顯式intent啓動另外一個組件的時候,被啓動組件基本上不需要使用

5.2.2 Action Category屬性與intent-filter配置
action表示該Intent所要完成的一個抽象“動作”,而Category則用於爲了Action增加額外的附加類
信息。通常Action屬性會與Category屬性結合使用。

其中的action表示的只是一種抽象動作。例如:Activity查看view,實際上,action這個字符串
並不管具體查看什麼,具體查看取決於Activity的配置。

一個intent對象只能包括一個action屬性,當程序創建的時候,該intent默認啓動Category
屬性值爲Intent.CATEGORY_DEFAULT常量的組件。

5.2.3 指定Action,Category調用系統的Activity
實例:查看並獲取聯繫人的電話
實例:返回系統 Home桌面

5.2.4 Data,Type屬性與intent-filter配置

Data屬性通常表示向action屬性提供需要操作的數據。
Data屬性接受一個Uri對象,該Uri對象通常通過如下形式的字符串來表示。

content://com.android.contacts/contacts/1
tel:123

Uri字符串總滿足如下格式:
scheme://host:port/path

Type屬性用於指定該Data屬性對應的MIME類型,這種MIME類型可以是任何自定義的MIME類型,
只要符合abx/xyz格式的字符串即可。

Type和Data會產生覆蓋,那麼如果不想覆蓋就可以使用intent.setDataAndType();

在Manifest中爲組件聲明Data Type 屬性都通過<data…/>元素,改元素的格式如下:

如果<data…/> 子元素只有android:port屬性,沒有指定android:host屬性,那麼android:port屬性,沒有指定android屬性將不會起作用

//5.2.5 Extra屬性

//5.2.6 Flag 屬性

//第六章Android應用資源
從物理存在形式上分有三大類:
{
界面佈局文件.xml文件
程序源文件(應用中的Activity,Service,BroadcastReceiver,ContentProvider)
資源文件(主要還是以xml文件爲主,還可有圖片形式等)
}





Android中除了res/目錄下存放資源外,assets目錄也用於存放資源。
一般來說,assets資源存放的是無法直接訪問的原生資源,應用程序需要通過AssetsManager以
二進制流的形式來讀取資源。

6.1 應用資源概述

6.1.1 資源的類型及存儲方式
animator/ 存放的是屬性動畫的XML文件
anim/ 定義補間動畫的XML文件
color/ 定義不同狀態下顏色列表的XML文件
drawable/ 存放適應不同屏幕分辨率的各種位圖文件
mipmap/ 存放適應不同屏幕分辨率的應用程序圖標
layout/ 存放各種用戶界面的佈局文件
menu/ 存放爲應用程序定義各種菜單的資源,包括選項菜單、子菜單、上下文菜單資源
raw/ 存放任意類型的原生資源(比如:音頻文件、視頻文件等)
values/ 存放各種簡單值的xml文件
xml/ 存放任意原生的xml文件









drawable-ldpi分辨率,drawable-mdpi中等分辨率,drawable-hdpi高分辨率,drawable-xhdpi超高分辨率
drawable-xxhdpi超超高分辨率 等子目錄。

如果開發時候所有的屏幕提供的是同一張圖片,那麼可以直接放在drawable目錄下。

6.1.2使用資源
1.在源程序中使用資源清單項
2.在源代碼中訪問實際的資源(使用Resources類,可以稱爲:“資源訪問總管家”)
3.在xml文件中使用資源


6.2 字符串 顏色 尺寸資源
6.2.1 顏色值的定義
6.2.2 定義字符串 顏色 尺寸資源文件

尺寸資源位於:/vlues資源文件夾下
<dimen…/>

6.2.3 使用字符串 顏色 尺寸資源文件
Android中允許定義boolean資源文件
在values/下面,使用:
true
並使用R.bool.name實現訪問



還可以定義整形變量:
<integer…/>定義整形變量

6.3 數組資源
Android中並不推薦在程序源代碼中定義數組

數組元素包含三種子元素:
<array…/>
<string-array…/>
<integer-array…/>


6.4 使用drawable資源
(只要一份xml文件可以被系統編譯成Drawable子類的對象,那麼這份xml文件即可作爲Drawable資源)
6.4.1 圖片資源
Android要求圖片資源的文件名必須符合java或Kotlin標識符的命名規則,否則不會生成索引。


6.4.2 StateListDrawable資源
該對象可以組織多個Drawable對象,當使用該對象作爲目標組件的背景的時候,該對象所顯示的Drawable
對象可以隨着目標組件狀態的改變而自動切換。

定義StateListDrawable對象所顯示的Drawable對象會隨着目標組件狀態的改變而自動切換。

定義的StateListDrawable對象的根元素爲:<selector…/>
該元素可以包含多個item元素。
實例:高亮顯示正在輸入的文本框

//LayerDrawable資源
該對象類似於StateListDrawable對象,也包含很多item元素,系統會按照這些Drawable對象的數組
順序來繪製他們,索引最大的Drawable對象將會被繪製在最上面。

定義LayerDrawable對象的XML文件的根元素爲:<layer-list …/>
可以包含有多個item元素
item元素中的屬性如下:
android:drawable
android:id 該Drawable對象指定一個標識
android:button|top|left|button:用於指定一個長度值,用於指定將該Drawable對象繪製
到目標組件的指定位置。





實例:定製拖動條外觀

//6.4.4 ShapeDrawable資源

該組件用於定義一個基本的幾何圖形,定義該對象的xml文件的根元素是<shape…/>元素
android:shape=“rectangle|oval|line|ring”

定義格式如下:
<corners…/> 定義幾何圖形四個角的弧度
<gradient…/> 定義使用漸變色填充
<padding…/> 定義幾何形狀的內邊距
<size…/> 定義幾何形狀的大小
<solid…/> 定義使用單色填充
<stroke…/> 定義爲幾何形狀繪製邊框





實例:橢圓形、漸變背景的文本框
//截至2020/12/22日晚上19:05(由於筆記太長,換下一個新的筆記本)

//-------------------------------------以上是截止到12-22日的筆記----------------------------------------------//

實例:實現橢圓形 漸變背景的文本框
//截至到上邊目錄顯示所謂的318頁

//12-23號晚上學習筆記
//6.4.5 ClipDrawable資源
ClipDrawable代表從其他位圖上截取一個“圖片片段”。

使用該對象的時候可以使用setLevel()方法來設置截取的區域的大小。
當設置的level值爲0時表示截取的片段爲空,當該值爲10000的時候表示截取的圖片是整張圖片
//實例:徐徐展開的風景(可以使用該對象實現圖片進度條)

//6.4.6 AnimationDrawable資源
以實現補間動畫爲例:需要定義的是AnimationDrawable對象的屬性是:{
alpha:設置透明度的改變
scale:設置圖片進行縮放變換
translate:設置圖片進行位移變換
rotate:設置圖片進行旋轉
}





該對象需要定義在anim文件夾中
上面屬性包括<set…/>在內還可以定義一個interpolator屬性,該屬性指定動畫的變化速度
如果程序想讓再一個set下面的所有元素使用相同的動畫速度,那麼可以指定屬性:
android:shareInterpolator=“true”


爲了在java代碼中調用動畫對象可以使用AnimationDrawableUtils對象

實際上想要保存對應的狀態需要設置set中的屬性fillAfter="true"即可。

6.5 屬性動畫資源
Animator是一個抽象類,實際開發中通常使用其子類
定義屬性動畫資源可以以{set objectAnimator animator}中的任意一個作爲根元素

//實例:不斷漸變的背景色

//6.6 使用原始的XML資源
6.6.1 原始資源的路徑
原始xml資源一般保存在/res/xml路徑下(但是開發者需要自己創建xml文件夾)
使用XmlResourceParser getXml()獲取xml文檔
使用InputStream openRawResource(int id);獲取xml文檔對應的輸入流



大部分時候都可以直接調用getXml()方法來獲取XML文檔
Android默認使用內置的pull解析器來解析xml文件(pull解析器是一個開源項目)

pull解析器方式有點類似於SAX解析,都採用時間驅動方式來進行解析。
當pull解析器開始解析之後,開發者可不斷調用pull解析器的next()方法獲取下一個解析事件
當處於某一個標籤時,可以調用XmlPullParser的nextText()方法來獲取文本節點的值。

6.6.2 使用原始的XML文件

//6.7 使用佈局資源

//6.8 使用菜單資源

//6.9 樣式 和 主題 資源
6.9.1 樣式資源
一個樣式相當於多個格式的集合,其他UI組件通過style屬性來指定樣式

樣式可以使用繼承,繼承之後子樣式會覆蓋對應的父樣式

6.9.2 主題資源
主題與樣式的區別是:
主題不可以用在單個view組件中
主題定義的格式應該是改變窗口外觀的格式,例如:窗口標題,窗口邊框等。


//6.10 屬性資源
使用的情景:如果用戶開發自定義的view組件需要指定屬性,那麼就需要屬性資源的幫助了
屬性資源文件的跟元素也是:<resources…/>元素,改元素包含如下兩個屬性。
{
attr
declare-styleable元素:定義一個styleable對象,每個styleable對象就是一組attr屬性的集合
}





在自定義組件的構造器中通過AttributeSet對象來獲取這些屬性。

//6.11 使用原始資源
只要是Android沒有爲之提供專門的支持,這種資源都是原始資源
位於:raw(會在R中生成一個索引項)下 或 assets(是更徹底的資源,需要通過AssetsManager資源)下

//6.12 國際化
6.12.1 爲Android應用提供國際化資源
我們需要在res/values/資源的文件夾下面保存程序中用到的字符串消息,爲了給這些消息提供不同
國家、語言的版本,開發者需要爲values目錄添加幾個不同的語言國家版本。
不同的values文件夾的命名方式爲:
values-語言代碼-r國家代碼




在不同的國際化資源中所有的消息的key是相同的,但是對應的value不同

//6.12.6 國際化Android應用
定義的國際化資源可以自動發揮作用

//6.13 自適應不同屏幕的資源
儘量使用dp爲分辨率單位

//6.14 本章小結

/--------------------第七章 圖形於圖像處理------------------/
//截止到2020/12/23號晚上22:02 (page 343)

/-----------2020/12/22號晚上23:58分開始學習------/
7.1 使用簡單圖片
//使用Drawable對象
7.1.2 Bitmap 和 BitmapFactory
BitmapDrawable裏封裝的圖片就是一個Bitmap對象。
可以調用BitmapDrawable的構造方法將bitmap對象包裝成一個BitmapDrawable對象




獲得bitmapDrawable對象所包裝的bitmap對象可以通過getBitmap();來獲得

7.1.3 Android 新增的ImageDecoder
使用該api對圖片解碼的時候,程序返回一個AnimatedImageDrawable對象,調用該返回
對象的start()方法,可以開始執行動畫。

截至到2020/12/24—凌晨0:44—7.2繪圖 (page 347/511)

//2020/12/24號下午學習筆記7.2 繪圖
7.2.1 繪圖基礎Canvas Paint等
Android中應該繼承view類並重寫其onDraw()方法
Canvas代表“依附於”一個指定View的畫布
Canvas提供了一個Paint對象,因此Paint類主要用於設置繪製風格,包括畫筆顏色等
Canvas中的另一個apiPath,代表任意多條直線連接而成的任意圖形,Canvas根據path繪製時
可以繪製出任意的圖形。





調用canvas.drawPath(path,paint)方法實現按照對應path路徑繪製圖片

前期只要美工把應用程序所需要的圖片製作出來後期看發的時候直接使用就可以

7.2.2 Path類
該類可以預先將N個點連成一條“路徑”,然後調用Canvas的drawPath()方法即可以沿着路徑繪製
圖形。

Android中還爲路徑繪製提供了PathEffect來定義繪製效果。

實現繪製文本的邏輯是:
//繪製路徑
paint.setStyle(Paint.Style.STROKE);
canvas.drawPath(paths[2],paint);
//沿着路徑繪製一段文本
paint.setStyle(Paint.Style.FILL);
canvas.drawTextOnPath(drawStr,paths[2],-20f,20f,paint);





7.2.3 繪製遊戲動畫
所謂的動畫就是不斷調用onDraw()方法,在調用的同時需要更改一部分的數據。
而通知View實現重新繪製需要調用的是invalidate(在ui線程中) 或 postInvalidate(在不是ui的線程中)

//實例採用雙緩衝實現圖畫板
所謂的雙緩衝技術其實很簡單:當程序需要在指定的View上進行繪製時,程序並不直接繪製到該
View組件上,而是先繪製到內存中的一個Bitmap對象上(這就是緩衝區),等到內存中的Bitmap繪製
好之後,再一次性地將Bitmap繪製到View組件上。


//實例:彈動的小球

7.3 圖形特效處理
7.3.1 使用Matrix控制變換
使用該對象的步驟如下:
1.獲取Matrix對象
2.調用Matrix的方法進行平移、旋轉、縮放、傾斜等
3.將程序對Matrix所作的變換應用到指定圖像或組件
Matrix 還可以用於對於View組件的平移、旋轉和縮放。





Canvas調用drawBitmap()方法可以實現繪製bitmap的時候應用Matrix變換

7.3.2 使用drawBitmapMesh扭曲圖像
該函數中的各種關鍵參數如下:
bitmap:指定需要扭曲的源位圖
meshWidth:該參數控制在橫向上把該源位圖劃分成多少格
meshHeight:該參數控制在縱向上把該源位圖劃分爲多少格
verts:該參數是一個長度爲(meshWidth + 1) * (meshHeight+1) * 2的數組
vertOffset:控制verts數組中從第幾個數組元素開始纔對bitmap進行扭曲





//7.3.3 使用Shader填充圖形
前面介紹Paint時提到的Shader包含了一個setShader(Shader s)方法
該方法控制畫筆的繪製效果

//7.4 逐幀動畫(Frame)
7.4.1 逐幀動畫AnimationDrawable與逐幀動畫
只需要在<animation-list…/>元素中使用<item…/> 子元素定義動畫的全部幀,
並指定各真的持續時間即可。


其中item中的屬性oneshot設置爲true表示不循環播放

在Java代碼中先創建AnimationDrawable對象,然後調用addFrame()向該動畫中添加幀
一旦程序獲取了AnimationDrawable對象之後,接下來就可以用ImageView把AnimationDrawable
對象顯示出來(習慣上把AnimationDrawable設置程ImageView的背景即可)

//實例:在指定點爆炸(實現邏輯:
先在MainActivity中創建FrameLayout對象,然後設置背景,然後加載myView組件,並設置對應的
動畫資源。
獲取動畫對象(目的是在後期的爲frame設置的監聽器中可以調用動畫對象開始和停止動作)
自己定義的MyView對象,主要是在onDraw()實現部分邏輯的目的是,爲了使得播放到最後一幀時
自動停止播放並將view組件設置爲不可見。






//7.5 補間動畫(Tween)
補間動畫是指:開發者只需要指定對應的開始和結束圖片,中間部分的圖片系統自動補齊。
//7.5.1Tween動畫與Interpolator

//Interpolator根據特定算法計算出整個動畫所需要動態插入幀的密度和位置。

爲了在動畫資源文件中指定補間動畫所使用的Interpolator,定義補間動畫的<set…/>集合元素
支持一個android:interpolator屬性。

7.5.2 位置 大小 旋轉度 透明度改變的補間動畫
//實例:蝴蝶飛舞

7.5.3 自定義補間動畫
自定義補間動畫需要繼承Animation類,關鍵是重寫該基類的applyTransformation();方法

Camera提供了一個三維空間變換的工具,功能比matrix更加強大。

//截止到378/511 at 2020/12/25 0:28

/----------------------2020/12/26號晚上 21:05 學習筆記------------------------/
接着7.5.3學習:
自定義補間動畫需要繼承Animation類,關鍵是重寫該基類的applyTransformation();方法
其中的參數:
{
interpolator:表示動畫的時間進行比。不管動畫實際的持續時間如何,該參數都是從
0-1進行變化的。





transformation:代表了補間動畫在不同時刻對圖形或組件的變形程度。(該對象可以)
實現對於圖片或者視圖的控制)
}

對於Camera類中的常用的方法有:
1.getMatrix()將Camera所作的變換應用到指定的matrix上
2.rotateX 表示使目標組件沿X軸旋轉
3.rotateY 表示使目標組件沿Y軸旋轉
4.rotateZ 表示使目標組件沿Z軸旋轉
5.translate 表示使得目標組件在三維空間裏進行位移變換
6.applyToCanvas() 表示將剛纔進行的變換應用到對應的canvas中





對於android手機的三維空間座標系來說
平行於屏幕從左到右是X軸
平行於屏幕從下到上是Y軸
垂直於屏幕從裏到外是Z軸


//自己總結的關於實現自定義的三維動畫邏輯:
首先是自定義一個類繼承animation類,然後定義對應的構造方法,設置其中的initialize()方法
中的邏輯,設置其中的applyTransformation()方法實現的是對於出來組件的時候動畫渲染邏輯
該方法中的重要邏輯是:{先調用camera.save()方法,然後根據interpolationTime控制三個座標軸上的偏移量
然後使用camera.rotateX 與 camera.rotateY()方法設置X和Y軸上的旋轉角度,然後獲取Transformation
參數的Matrix對象。並使用camera.setMatrix(matrix);設置對象,然後調用matrix.preTranslation() 及 matrix.preTranslation()
;方法;最後調用camera.restore()方法實現保存 }





//7.6 Android 8 增強的屬性動畫:
從大體上來說,屬性動畫是增強版的補間動畫,但是屬性動畫更加強大
補間動畫只可以對UI組件執行動畫,但是屬性動畫幾乎可以對任何對象執行動畫(不管他是不是顯示在屏幕上)

//屬性動畫的API
Animator 提供了創建屬性動畫的基類(基本上不使用該類)
ValueAnimator屬性動畫主要的時間引擎,負責計算各個幀的屬性值。

屬性動畫主要由兩方面組成{
計算各幀的相關屬性值
爲指定對象設置這些計算後的值
}






ValueAnimator主要負責的是第一個方面的值

ObjectAnimator 是ValueAnimator的子類,用於組合多個Animator,並指定多個ANimtor
是按次序播放還是同時播放。

除此之外,屬性動畫還需要一個Evaluator該工具類控制屬性動畫如何計算屬性值。

Android 8 還爲AnimatorSet新增了幾個方法:{
reverse(); //反向播放屬性動畫
long getCurrentPlayTime(); 獲取動畫的當前播放時間
setCurrentOlayTime(); 設置動畫的播放時間
}



通過設置setCurrentPlayTime()方法可以使得直接在對應的時間點進行播放

測試實現:
1.ValueAnimator創建動畫
四個步驟:
調用其中的ofInt() ofFloat() ofObject() 靜態方法創建ValueAnimator實例
調用ValueAnimator的setXxx()方法設置動畫持續時間,插值方式,重複次數。
調用ValueAnimator的start()方法啓動動畫
爲ValueAnimator註冊AnimatorUpdateListerner()監聽器,在該監聽器中可以監聽
ValueAnimator計算出來的值的改變,並將這些值應用到指定對象上。






2.使用ObjectAnimator創建動畫
該類可以直接將其父類中計算出來的值直接用到指定對象的屬性上

與ValueAninmator不同的是,使用ObjectAnimator的注意點:
要爲該對象對應的屬性提供對應的setter方法
如果是對於其中方法的ofInt()等中的參數時,其中的values數組如果只提供了
一個值,那麼該值會被認爲是結束值,該對象還應該爲該屬性提供一個getter()方法,該getter
方法返回的值就是開始值。
若該動畫對象不是view,爲了顯示動畫效果,還需要在onAnimatorUpdate()事件監聽方法中
調用.invalidate()方法,實現對應的組件的更新。(view組件會自動調用故不需要指定)





//7.6.2 使用屬性動畫
屬性動畫可以既可以用於UI組件,也可以用於對應的普通的對象

定義屬性動畫有兩種方式:
使用ValueAnimator 或 ObjectAnimator 的靜態工廠來創建動畫
使用資源文件來定義動畫

具體步驟如下:
創建ValueAnimator 或 ObjectAnimator 對象–既可從XML文件中加載該動畫資源;也可以使用兩個類的
靜態構造方法來創建動畫。
根據需要可以爲animator設置對應的屬性。
如果需要設置監聽animator的動畫開始事件等,應該爲animator對象設置事件監聽器。
如果有多個動畫需要按次序或同時播放,則應該使用AnimatorSet組合這些動畫。
調用Animator對象的start()方法啓動動畫。





//---------------2020/12/27晚上學習筆記(從p 383 開始學習)---------------------
-0x1000000 + red << 16 | (green << 8) | blue
對於上式的解釋:
oxff000000代表透明度爲ff,也就是完全不透明
red代表一個0-255的隨機整數,但是這個整數要添加到oxff000000加粗
的兩個位上,也就是說要將red的值左移(16位,對應爲十六進制的4位)
,這就是red << 16的原因





green 代表的是0-255的隨機整數,但是這個整數要添加到0xff000000張加粗的兩個位置

blue…

//實例:大珠小珠落玉盤

//使用SurfaceView實現動畫
View存在的缺陷:
{
View缺乏雙緩衝機制
當程序需要更新view上的圖片時,程序必須重繪View上顯示的整張圖片
新線程無法直接更新view組件
}





7.7.1 SurfaceView繪圖機制
surfaceView會和surfaceHolder結合使用
使用getHolder()可以得到對應的holder對象

surfaceHolder對象提供下面的方法來獲得canvas對象:
lockCanvas()鎖定整個SrufaceView對象,獲取該SurfaceView上的canvas
lockCanvas(Rect dirty) 鎖定SurfaceView上的Rect劃分區域,獲取該區域上的canvas(該方法只更新對應的
圈出來的區域))


需要說的是當需要調用surfaceHolder的unlockCanvasAndPost()方法之後,該方法之前所繪製的圖形所處於緩衝區中
下一次lockCanvas()方法鎖定的區域可能會“遮擋”它。

//測試實現使用surfaceView動畫效果實現
(實現邏輯(自己總結:{
首先創建一個FishView類,然後在構造方法中得到綁定的holder對象,並將本view
放進去,然後創建一個bitmap對象得到對應的資源文件;初始化對應的數組,然後
得到;實現對應的resume() pause()方法 surfaceCreated()方法 surfaceChanged()方法
創建一個心得thread類,然後再其中的run方法中得到fishView類的getHolder()方法,可以開始執行動畫。
鎖定SurfaceView並返回到繪圖的Canvas,然後繪製背景圖片,然後是判斷魚是否
已經出了屏幕,並使用matrix來控制魚的旋轉角度和位置,然後調用canvas.drawBitmao()
表示在畫布上繪製對應的圖片(並設置了旋轉的角度和對應的速度,然後是解鎖canvaas)並渲染)
當前圖像,設置線程沉睡0.06秒,然後是設置如下代碼即可:








void requestExitAndWait(){
//把這個線程標記爲完成,併合併到主程序線程中
done = true;
try{
join();
}catch (Exception e){
e.printStackTrace();
}
}







    void onWindowResize(int w,int h){
        //處理SurfaceView的大小改變事件
        System.out.println("w:" + w + "===h:" + h);
    }


}))

//截止到392 頁面學習筆記 (2020/12/27晚上11:30)

/-----------------------2020/12/28 晚上學習筆記 (從392開始)----------------------------/
surfaceView來說和view的顯著區別是,線程可以使用surfaceView對象的surfaceHolder對象來繪製圖像。

//基於surfaceView開發示波器
重點:考慮surfaceView組件的情況是:程序或遊戲界面的動畫元素很多,並且很多動畫元素的移動都需要
通過定時器來控制,就可以考慮該組件。

//2020/12/28號 22:30開始 晚上學習筆記
/----------------------------第八章 Android 數據存儲與IO-----------------------/
Android中Sqlite數據庫對應於一個文件(沒有後臺進程)
8.1 使用SharedPreference對象存儲數據
使用情景:少量的數據保存 數據格式簡單 都是普通的字符串 標量類型的值等
SharedPreference對象主要是保存類似於配置信息格式的數據,主要是key-value形式。
通過SharedPreference.Editor對象纔可以寫進去數據
使用Editor對象的.apply()方法可以更新數據。(使用commit會立即修改但是使用apply()不會阻塞前臺進程)






爲了得到SharedPreference對象可以是喲個context對象的getSharedPreference();方法得到
想要將本應用中的數據暴漏出來的話,Android 4.2 開始推薦使用ContentProvider對象來訪問。

8.1.2 SharedPreference對象的存儲位置和格式
使用該對象保存的數據放在:
/data/data//shared_prefs 目錄下,並總是以xml格式來保存

//8.2 Filr存儲
8.2.1 openFileOutPut 和 openFileInput
除此之外,context提供了幾個方法來訪問應用程序的數據文件夾
getDir()方法獲得子目錄
file getFileDir()獲得絕對路徑
String[] fileList返回應用程序數據文件夾下面的全部文件
deleteFile()刪除指定文件





使用context存儲的都是再手機的內置存儲中

讀寫SD卡上的文件步驟如下:
1.請求動態獲取讀寫SD卡的權限
2.調用Environment的getExternalStorageDirectory()方法來獲取外部存儲器(SD)的目錄
3.使用FileInputStream FileOutputStream FileReader或FileWriter命令來創建虛擬存儲卡,
4.爲了讀寫SD卡上的數據,必須在應用程序的清單文件中設置權限:





//截止到2020/12/29號晚上23:32min

/---------------------------2020/12/30號下午13:46開始學習筆記--------------------/
from 404 begin

//實例:SD卡文件瀏覽器

8.3 SQLite數據庫
該數據庫是一個輕量級的數據庫,是一個嵌入式的數據庫引擎
該數據庫只是一個文件

8.3.1 SQLiteDatabase(底層就是一個數據庫文件)簡介
該對象的作用有點類似於JDBC的connection接口

該對象支持的查詢方法返回的都是一個Cursor對象

當移動到指定行之後,接下來就可以調用Cursor的getXxx()方法獲取該行的指定列的數據了。

8.3.2 創建數據庫和數據表

8.3.3 SQLiteOpenHelper類
實際項目中很少使用直接的openOrCreateDatebase()靜態方法來打開數據庫,通常都會繼承該類並通過
該類的getReadableDatabase() 和 getWritableDatabase()方法打開數據庫

該類可以用來進行版本更新和數據庫的創建。

重寫其中的onCreate()方法,該方法是隻有在第一次生成數據庫表結構的時候調用,在裏面可以
設定數據庫表的結構(也可以添加一些數據進去)

當用戶創建一個helper對象時,程序員指定數據庫版本號(當某一次創建的時候版本號高於原來的版本時,
系統會自動進行必需的表結構的更新)

當數據庫升級失敗的時候,需要先進行轉儲,然後對數據表進行更新,之後再保存回來原來的數據。

getWritableDatabase()以寫的方式打開數據庫,然後使用getReadableDatabase()方法,先以讀寫的方式打開
數據庫,如果數據庫的磁盤已經滿了就會打開失敗,當打開失敗的時候會繼續嘗試以只讀的方式打開數據庫。

//8.3.4 使用SQL語句操作數據庫
使用execSQL()方法可以執行任意的SQL語句,包括帶有佔位符號的Sql語句。
當需要執行查詢語句的時候,可調用rawQuery()方法

//8.3.5 使用sqlite3工具
在android SDK 的 platform-tools 目錄下提供了一個sqlite3.exe 文件,他是一個簡單的sqlite數據庫管理工具
類似於MySQL提供的命令行窗口。

sqlite3常用命令如下:
.database查看當前的數據庫
.tables 查看當前數據庫裏的數據表
.help 查看sqlite3支持的命令


再將sql語句真正地插入到數據庫中的之前先在sqlite3這個工具類中測試是否是有語法錯誤

需要說明的是sqlite內部只支持NULL,INTEGER,REAL(浮點數),text(文本),和BLOB(大二進制對象)

但實際上其他的類型該數據庫也會接受只不過是在保存到底層數據庫中的時候會轉換成上述的5種數據。

同時,sqlite3還會把各種類型的數據保存到任意類型的字段中,開發者可以不用關心聲明該字段所使用的數據類型。
但是有一種例外情況:
定義爲:INTEGER PRIMARY KEY 的字段 只能存儲64位整數,當向這種字段中保存除了整數之外的其他類型的數據時
SQLite會產生錯誤。


//8.3.6 使用特定的方法操作SQLite數據庫

insert方法插入一行記錄使用ContentValues存放(該類型類似於Map)
其中的參數:(String table,String nullColumnHack,COntentValues values)
第二個參數只有當vlues是null時,會添加除了主鍵之外其他字段都是null的記錄。(第二個參數指定的是插入的列名)

8.3.7 事務
當結束事務的時候,會根據前邊SQLiteDatabase對象是否調用了setTransactionSuccessful()方法來設置事務標誌
如果事務執行中調用該方法設置了事務成功,則提交事務,否則程序將會回滾事務。

//8.3.8 SQLite數據庫最佳實踐建議

1.關於打開數據庫的方式
通過前面介紹我們知道,打開SQLite數據庫有兩種方式
直接通過SQLiteDatabase的靜態方法打開數據庫;
通過SQLiteOpenHelper類的子類來打開數據庫(強烈建議使用第二種方式)


2.關於SQLite的用途:
不要把大量的數據都放到SQLite中;如果需要保存大量數據需要設置服務器端。
SQLite可以緩存部分的服務器端的數據。

4.關於操作數據庫的方式
使用execSQL()原生操作,rawQuery()方法執行原生操作SQL語句

使用insert update delete query 方法執行SQL語句

強烈建議使用OEM工具:Ormlite GreenDao LitePal等(有Hibenate經驗優先)

//8.4 手勢
Android提供了手勢檢測併爲手勢檢測提供了相應的監聽器
Android允許開發者自己添加手勢,並提供了相應的API識別用戶手勢

8.4.1 手勢檢測
Android爲手勢檢測提供了一個GestureDetector類,該類的一個實例代表了一個手勢檢測器
創建該類時需要傳入一個GestureDetector.OnGestureListener實例(該實例就是一個監聽器,負責給用戶的手勢提供相應)

使用Android手勢的步驟:
使用GestureDetector對象(該對象必須實現的是監聽器接口)
爲應用程序的Activity的TouchEvent事件綁定監聽器(將Activity上的touchEvent事件交給GestureDetector處理)

//實例:通過手勢縮放圖片
實現邏輯自己總結:
首先需要定義手勢檢測器變量、Bitmap變量、定義圖片的寬和高、記錄當前的縮放、控制圖片縮放的matrix對象
然後定義一個手勢檢測器初始化,先得到對應的vx滑動速度,根據vx進行圖片的縮放,然後重置matrix對象
縮放matrix對象,然後是得到BitmapDrawable對象,判斷是否已經回收,如果沒有回收就回收
然後根據新的matrix創建新的bitmap位圖對象,然後設置imageView顯示位圖對象,最後是
在acitivity中的onTouchEvent()方法中返回一個手勢檢測器的onTouchEvent(event);結果。





處理多點觸碰也通過重寫onTouch()方法進行實現,通過該方法中的MotionEvent參數的getPointerCount()方法可判斷
觸碰點的數量

通過MotionEvent的getActionMasked()方法來判斷觸碰事件的類型。

//8.4.2 增加手勢

Android中使用GestureLibrary來代表手勢庫,並提供了GestureLibraries工具類來創建手勢庫

Android還提供了一個手勢編輯組件:GestureOverlayView組件,用戶可以在組件上繪製的不是圖形而是手勢

該組件還提供了三個監聽器
onGestureListener onGesturePerformedListener onGesturingListener (分別表示手勢開始 結束 完成 取消等事件)
第二個是最常用的監聽器,它用於在手勢事件完成時提供相應。

注意:一個組件不是標準的視圖組件的時候因此在界面佈局中使用該組件時需要使用全限定類名

<android.gesture.GestureOverlayView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/gesture"
    android:gestureStrokeType="multiple"
    />

該組件中使用的android:gestureStrokeType="multiple"屬性表示的是設置爲single(手勢只有一筆完成)
使用multiple表示多筆完成

實例:實現存儲用戶手勢邏輯
自己總結邏輯:

1.創建GestureOverlayView 以及 Gesture對象
初始化手勢編輯視圖對象,爲繪製手勢對象綁定監聽器並設置動態獲得SD卡權限

2.然後在activity中的內部方法中實現保存手勢的邏輯:
判斷用戶是否同意了獲得讀寫權限,如果是,那麼獲得對應的佈局文件,然後在佈局文件中添加一個imageView組件
接着將剛纔在GestureOverlayView組件中繪製的圖像以bitmap(位圖)顯示在imageView組件中,然後創建一個對話框
將剛纔準備好的佈局組件顯示到對話框中,然後設置確定的實現邏輯是:保存手勢到手勢庫中。


//截止到2020.12.30 晚上 22:11  (p432)

//---------------截止到2020.12.31 晚 20:38開始學習筆記-------------//

//2020.12.31 晚 20:40 學習筆記:
8.4.3 識別用戶自定義手勢

GestureLibrary提供了recognize(Gesture ges) 方法來識別手勢,該方法返回該手勢庫中所有與ges手勢匹配的手勢,
返回的結果是一個ArrayList 集合,其中的Prediction對象封裝了匹配的屬性信息,其中的name表示匹配的手勢
名字,其中的score表示匹配的相似度。

//截止到2020.12.31 晚上 21:42 止 //截止到433頁

//2021.1.1 上午 1:40 學習筆記:---------------------------------------------
//8.4.3 識別用戶手勢
識別用戶手勢邏輯自己總結:

定義手勢編輯組件變量和手勢變量;在onCreate()方法中請求用戶允許讀寫SD卡權限;在activity中自帶的方法中處理顯示
組件邏輯(包括:判斷用戶是否同意授權,如果同意那麼先得到之前創建的手勢庫,然後手勢庫裝載,是否成功;如果成功,
獲取手勢編輯組件,給手勢編輯組件增加監聽器;在監聽器中實現:{
創建一個List 數組用來保存返回的識別結果,然後創建以惡個List result 數組對象,實現的是
用來生成需要顯示的語句;然後遍歷得到的返回數組(當識別度大於2.0的時候生成對應的結果,然後判斷自己定義的結果數組長度
是不是大於0的,如果是,則生成一個適配器用於準備結果;然後創建一個帶有List的對話框來顯示所有的手勢;至此邏輯總結完畢)
})





8.5 讓應用說話(TTS)(TextToSpeech)
Android提供的自動朗讀功能。
android中還支持將文本生成的音頻錄製成音頻文件。
使用的時候需要提供一個OnInitListener監聽器,該監聽器負責監聽TextToSpeech的初始化結果。
在程序中獲得了TextToSpeech對象之後可以使用setLanguage()方法來設置該TTS語音引擎應使用的語音,國家選項。
目前內置的TTS引擎對中文支持的效果不好,但是科大訊飛的TTS引擎對中文支持比較好。




TextToSpeech的兩個常用的方法是:
speak() 該方法只是朗讀文本
synthesizeToFile() 該方法可以將轉換得到的音頻保存到聲音文件中。

speak()方法中的queueMode參數指定TTS發音隊列模式,該參數支持下面的兩個常量:
TextToSpeech.QUEUE_FLUSH 表示當TTS調用speak()方法時,會中斷當前實例正在運行的任務。
TextToSpeech.QUEUE_ADD 表示將當前的語音加入到對應的語音隊列中,並等待當前發音隊列中的任務執行完之後才執行當前的語音。

//測試TTS

//8.6 本章小結

/-------------------------------第9章 使用ContentProvider實現數據共享--------------------------------/
ContentProvider是Android提供的用於實現不同應用之間數據交互的標準API
而其他的應用程序則可以使用ContentResolver對象來操作對應的數據。

//截止到 2021.1.1 下午 13:08 (p439)

//2021.1.1 下午 16:56 開始學習筆記:
ContentProvider也是android四大組件之一,也需要在Manifest.xml文件中進行配置

只要是一個應用提供了Contentprovider接口,那麼不管該應用是否啓動,外部的應用都可以訪問數據等。

9.1 數據共享標準:ContentProvider組件
該對象提供Uri形式對外提供數據

9.1.1 ContentProvider簡介

開發一個ContentProvider的步驟:
1.定義一個ContenProvider類,需要繼承Android提供的ContentProvider基類。
2.向Android系統中註冊一個ContentProvider,註冊的時候需要指定一個Uri(也就是authorities)即可
只要在<application…/>元素下添加子元素即可。


對於自己定義的provider類除了需要繼承ContentProvider類之外還需要提供如下幾個方法:
1.onCreate() 在ContentProvider創建後調用
2.insert()根據uri插入vlaues對應的數據
3.delete()根據uri刪除selection條件所匹配的全部記錄
4.update()根據uri修改selection條件所匹配的全部記錄
5.query() 根據uri查詢得到selection條件匹配的全部記錄 其中的projection就是一個列名列表,表明只選擇出來指定的數據列
6.getType()方法用於返回當前uri代表的MIME類型。





//9.1.2 Uri簡介:
一個Uri分爲三個部分:
content//:這個部分是Android的ContentProvider規定的,就像上網的協議默認是http一樣,用來暴露對於contentprovider的訪問
org.wyy.providers.testprovider 這個部分就是ContentProvider的authorities
words資源部分(或者說數據部分)。當訪問着需要訪問不同資源時,這個部分是動態改變的。
在words/2 表示的是words數據中的ID爲2的數據
上述的Uri借本上遵循的是RESTFul





使用uri對象的Uri.parse(""); 可以實現將String類型的字符串轉換爲:Uri

9.1.3 使用ContentResolver操作數據(用來操作contentProvider對象中保存的數據)
該對象可以使用context對象的.getContentResolver()方法得到對應的contentResolver對象

一般來說contentProvider是單例的

//9.2 開發contentProvider

9.2.1 contentProvider 和 contentResolver的關係

9.2.2 開發contentProvider子類
需要注意的是:在ContentProvider子類中實現的各種方法不是自身調用的。
而是提供給其他應用程序調用的。

9.2.3 配置ContentProvider
Android要求的是所有的應用組件都需要進行顯示配置
其中設置的屬性android:exported屬性表示指定該provider是否可以被調用(設置爲true可以被調用)

其中設置的readPermission writePermission 屬性表示設置需要的權限
或者使用permission來設置
如果不設置權限那麼表示可以被所有的APP訪問

//截止到2021.1.1 22:54爲止(p444)

/--------------------------------2021.1.2 12:08 開始學習筆記--------------------------------------/
9.2.4 使用ContentResolver調用方法
其中update() delete()方法返回的是更新或刪除的數據數目

//9.2.5 創建ContentProvider的說明
實際上,爲了確定該ContentProvider實際可以處理的Uri,以及確定每一個方法中Uri參數所操作的數據,Android系統提供了
UriMatcher工具類

其中的addUri(String authority,String path,int code)方法用於向該對象註冊Uri其中的authoirity和path組合成了一個Uri,而code代表該Uri對應的標識碼。

int match(Uri uri) 可以根據前面註冊的uri來判定指定uri對應的標識碼。找不到返回-1。

可以使用ContentUris.parseId(uri)來獲得對應的ID值

//實例:開發contentProvider實現單詞本

建議:使用工具類定義常量可以實現對訪問路徑的定義。

在ContentProvider中使用sqlite3保存對應的數據。

注意的是:在使用contentProvider更新完數據之後需要使用getContext().getContentResolver().notifyChange(uri,null);
通知數據已經改變

//9.3 操作系統的ContentProvider
實際上,android中本身提供了很多的ContentProvider, 例如聯繫人信息,系統的多媒體信息等。

開發者可以使用ContentResolver對象來獲得系統中的數據

通過查閱對應的API文檔可以獲得想要訪問的系統contentProvider對象中的數據對應的Uri

//9.3.1 使用ContentProvider對象管理聯繫人

Android中提供了Contacts應用程序來管理聯繫人,而且還提供了provider

android要求訪問本身的contentProvider的時候需要用戶動態獲取權限

//重點:
android中的聯繫人信息是一張表(主表),開發者需要先向該主表中插入記錄。電話信息是一張從表(參照聯繫人表),
E-mail信息單獨是一張從表(參照聯繫人表),因此開發者可以分別爲一個聯繫人添加多個電話信息、多個E-mail信息。

//自己總結實現聯繫人信息獲得的邏輯:
先給一個按鈕註冊一個請求獲得動態訪問權限的按鈕,然後點擊之後到activity中的onRequestPermmissionResult()方法,
在該方法中定義兩個數組一個是存儲聯繫人姓名的數組一個是用來存放聯繫人對應的數據的數組List<List>
details,使用contentResolver對象的.query()方法可以根據系統提供的聯繫人Uri得到對應的數據,
,然後是使用while循環遍歷所有的聯繫人{
先得到聯繫人的ID,得到聯繫人的名字,然後向names集合中添加名字,使用contentResolver對象的查詢聯繫人的電話號碼,
其中可以設置條件是使用的聯繫人的CONTACT_ID,然後創建一個detail數組,向該數組中通過遍歷將本聯繫人的電話號數據
加入其中,然後得到聯繫人的E-mail,遍歷該數組得到e-mail中對應的多個E-mail地址數據,並向該detial數組中添加
對應的e-mail地址。最後,將每一次循環得到的detail數組添加到對應的details數組中。
接着是獲得佈局視圖,然後從該佈局中得到對應的ExpandableListView對象,然後創建一個ExpandalbeListViewAdapter對象
其中的設置getGroupCount()返回的是names數組的長度;其中的getChildrenCount()返回的是details中對應的position數組的長度;
其中的getGroup()獲得對應的position處的組數據;其中的getChild()方法得到的是對應位置的子列表項的數據(也就是電話號碼和對應e-mail數據)
其中的getGroupId()方法得到的是第幾組;其中的childId()方法得到的是對應的第幾個子數據;其中的getGroupView()
方法決定的是每一個組選項的外觀;其中的getChildView()方法得到的是每一個子選項的外觀。最後爲獲得佈局中的ExpandableListView組件
設置對應的監聽器,從而實現了結果的顯示。
}














//9.3.2 使用ContentProvider管理多媒體內容
獲得對應的多媒體的Uri即可實現管理。

注意在使用RecyclerView的時候,需要給該對象設置一個recyclerView.
show.setLayoutManager(new LinearLayoutManager(this));
這樣的話纔可以顯示出來組件。

//9.4 監聽 ContentProvider的數據改變
9.4.1 ContentObserver簡介:
需要向指定的uri註冊一個ContentObserver監聽器
提供了registerContentObserver(Uri uri,boolean notifyForDescendets,ContentObserver observer);


中間的參數設置爲:false時候表示必須時Uri(content://abc)變化的時候纔會監聽到改變;
但是設置爲true的時候表示儘管有:content://abc//xyz 或 content://abc//foo 也會監聽到變化。

9.5 小節

/----------------------------------2020.1.2 17:46 晚上看筆記------------------------------------/
/第十章 Service 和 BroadcastReceiver
Service是四大組件中與Activity最相似的組件
Service一直在後臺運行,絕對不會到前臺來,有自己的生命週期。
BroadcastReceiver組件就像一個全局的事件監聽器,只不過它用於系統發出的Broadcast。
通過使用該對象可以在不同的應用程序之間通信。




10.1 service簡介

10.1.1 創建、配置Service

service組件生命週期方法:
IBinder onBind() 該方法時Service子類必須實現的方法。該方法返回的是一個IBinder對象,應用程序可通過該對象與
service組件通信
onCreate() 方法該service第一次被創建後將立即回調該方法。
onDestory() 該Service被關閉之前將會調用該方法
onStartCommand() 該方法的早期版本是void onStart(Intent intent,Int startId) 每次客戶端調用startService(Intent)
方法啓動該Service時都會回調該方法。





onUnbind() 當該service上綁定的所有客戶端斷開連接時將會回調該方法。

在onCreate() 或 onStartCommand() 方法中定義相關業務代碼

設置Service組件中的process表示該組件處於某一個進程中(默認是處於該App所在的進程中)
android中的四大組件都可以通過該屬性指定運行的進程

啓動Service由兩種方式:
1.通過context的startService()方法 該方法啓動的service與訪問者之間沒有關聯,即使訪問者退出了,該service也仍然運行
2.通過context的bindService()方法,使用該方法啓動service訪問者與service綁定在一起,訪問者一旦退出,service就終止。

10.1.2 啓動和停止service

多次啓動一個service不會多次調用onCreate()方法,但是會多次調用onStartCommand()方法

10,1.3 綁定本地service並與之通信
如果Service和訪問者之間需要進行方法調用或交換數據,則應該使用bindService()方法 和 unBindService()方法。
bindService()方法中的參數:
其中的ServiceConnection conn,表示該對象用於監聽訪問者與service之間的連接情況。當訪問者與service之間
連接成功時將回調該ServiceConnectionn對象的onServiceConnected(ComponentName name,IBinder service) 方法,當
service所在的宿主進行由於異常中止或其他原因終止,導致該service與訪問者之間斷開連接時回調該serviceConnection
對象的onServiceDisconnected(ComponentName)方法。(但是當調用者主動斷開連接的時候onServiceDisconnected()方法不會被調用)





其中的參數flags表示綁定時是否自動創建service,該參數爲0時,表示不自動創建;該參數爲BIND_AUTO_CREATE(自動創建)

注意到在ServiceConnection中的onService()方法中有一個IBinder對象可以用來進行通信。

在綁定了本地service的情況下,onBind(Intent intent) 方法返回的IBinder對象將會傳給ServiceConnection對象裏
onServiceConnected()方法的service參數,這樣訪問者就可以通過該IBinder對象與Service進行通信。

實際上開發的時候將通常會繼承Binder類的方式實現自己的IBinder對象。

IBinder 將會傳給service的訪問者

多次調用bindService()不會多次綁定

重點理解:
Service的生命週期:

onCreate()創建該Service之後立即調用的

如果需要該Service是由Activity的startService()方法啓動之外,還需要Service子類重寫onUnbind()方法時返回true;

只有是通過bindService調用的在使用了unBindService()之後纔會調用onDestory()方法。

當一個activity使用bindService調用一個已經啓動的service的時候只是可以得到對應的iBinder對象,
而在調用了對應的unBindService之後也不會使得該service徹底destroy

10.1.5 使用IntentService
Service存在的兩個問題:
1.Service不會專門啓動一個單獨的進程,與其所在的應用位於同一個進程中
2.Service不是一條新的線程,因此不應該在Service中處理耗時的任務


//重點//
爲什麼不可以直接在activity中直接創建一個新的線程,因爲如果是直接創建一個新的線程,那麼
由於activity本身會被用戶退出,並且是BroadCastReceiver的生命週期本身很短,那麼會出現在子線程還沒有結束的
情況下,activity已經被用戶退出了,或是BroadcastRececiver已經結束了,這種情況下,此時它們所在的進程就
變成了空的進程,那麼此時很可能被android的回收機制回收那麼對應的子線程還沒有執行完畢就結束了。



IntentService會使用隊列來管理請求的intent對象,每當客戶端代碼請求i的時候都會創建一個新的worker線程來處理
該Intent。
對於異步的startService(),IntentService會按照次序處理隊列中的intent請求,該線程保證同一時刻只處理一個intent。

並且IntentService會自動停止不需要開發者自己停止。

10.2 跨進程調用Service(AIDL Service)
IPC(跨進程通信)

10.2.1 AIDL Service(與java中的遠程RMI具有一定的相似之處)
與RMI不同的是,service只是將service對象的代理iBinder返回給用戶。

因此AIDL遠程接口的實現類就是那個IBinder實現類。

遠程Service的onBind()方法只是將IBinder對象的代理傳給客戶端的ServiceConnection的onServiceConnected()方法
的第二個參數。

10.2.2 創建AIDL文件(android接口定義語言)

AIDL接口的源代碼必須以.aidl結尾
在AIDL中用到的數據類型,除了基本類型之外,其他的類型都需要導包,即使在同一個包中也需要導包。

開發人員定義的AIDL接口只是定義了進程之間的通信接口,service端。客戶端都需要使用Android SDK安裝目錄下的build-tools子目錄下面
的aidl.exe工具爲該接口提供實現。(使用AS會自動爲該接口提供實現)

在定義好了AIDL接口之後,android studio工具會自動在build/generated/source/aidl/debug目錄下生成了一個XXX.java
接口,再改接口中包含了一個stub內部類。該內部類,該內部類實現了IBinder.ICat兩個接口。
這個Stub類將會作爲遠程Service的回調類–它實現了IBinder接口,因此可以作爲Service的onBind()方法的返回值。

如果沒有自動生成接口那麼可以使用ctrl+F9 強制生成接口。

10.2.3 將接口暴露給客戶端
上一步定義好AIDL接口之後,接下來就可以定義一個Service實現類了,該Service的onBind()方法所返回的IBinder對象
應該是ADT所生成的ICat.Stub的子類的實例。

10.2.4 客戶端訪問AIDL Service
AIDL接口在客戶端和服務器端都需要定義。
客戶端綁定遠程service步驟:
1創建ServiceConnection對象
2.以ServiceConnection對象作爲參數,調用Context的bindService()方法綁定遠程Service即可。



使用AIDL接口的作用是:
服務器端 ---- AIDL接口 ----- 客戶端

Android將指定Component屬性,以及指定Package屬性的intent都當成顯式Intent。

//實例:傳遞複雜數據的AIDL Service
Android要求調用遠程Service的參數和返回值都必須實現Parcelable接口。
實現該接口不僅需要的是實現該接口中的方法,而且要求在實現類中定義一個名爲CREATOR、類型爲Parcelable.Creator的靜態
常量。除此之外還要求使用AIDL代碼來定義這些自定義類型。
其中定義的Creator靜態常量是用來恢復自定義對象的。



Android中實現Parcelable接口是提供了一種輕量型的序列化機制。

在AIDL接口中定義方法時,需要指定形參的傳遞模式。

實現自定義複雜數據類型的AIDL訪問步驟:
1.先定義一個Person.aidl形的接口;緊接着定義一個對應Person.java類型的接口()其中定義一個CREATOR常量,目的是
實現對應的數據類型的轉換爲序列化對象。(定義Pet類型的接口同上)
2.然後定義一個IPet.aidl通信接口。(其中指定的是定義一個Pet對象類型的list集合參數類型是
person類型的 並且使用了in表示傳入參數的形式)
3.然後實現一個繼承自Service的類,其中定義一個static常量,裏面實現的是一些數據的初始化。
4.繼承對應的xxx.Stub(也就是實現了IPet接口,並實現了IBinder接口),並在onBind()方法中返回對應的binder對象
5.然後實現客戶端的Activity的創建,通過在ServiceConnection實現類中的onServiceConnected()方法實現:
petService = IPet.Stub.adInterface(service);得到返回來的對象代理然後進行處理得到Service對象







6.然後在onCreate()方法中得到對應的數據,並使用ArrayAdapter<> 進行包裝並顯示。

//同樣地,調用getSystemService(String name):根據Service名稱來獲得系統的Serivice

10.3 電話管理器(TelephoneManager)

10.4 短信管理器

10.5 音頻管理器AudioManager
10.5.1 簡介:
adjustStreamVolumn(int streamType,int direaction,int flag)
第一個參數:調整手機指定類型的聲音。
第二個參數:是調大還是調小
第三個參數:是設置調整聲音時的標誌




setMicrophoneMute()表示設置是否讓麥克風靜音
setMode() 設置聲音模式,
setRingMode()設置手機的電話鈴聲模式。
setSpeakphone()設置是否打開擴音器
setStreamVolume直接設置手機的指定類型的音量值。



10.6 振動器(Vibrator)
10.6.1 Vibrator簡介

vibrator提供瞭如下的三個方法來創建振動效果:
creaeteOneShot() 創建只震動一次的振動效果
createWaveform創建波形振動的振動效果
createWaveform創建波形振動效果第二種


10.6.2 使用Vibrator控制手機振動

10.7 手機鬧鐘服務(AlarmManager)

10.7.1 AlermManager簡介

10.7.2 設置鬧鐘
AlermManager是一個全局定時器,即使在程序推出之後也會啓動指定組件。

10.8 廣播接收器(BroadcastReceiver 四大組件之一)
本質上是一個全局監聽器,可以方便實現不同系統之間的通信。
10.8.1 簡介:

用來接受程序發出的BroadcastIntent對象。
啓動BroadcastReceiver步驟:
1.創建需要啓動的BroadcastReceiver的Intent
2.調用Context的sendBroadcast()或sendOrderBroadcast()方法來啓動指定的BroadcastReceiver


指定該對象可以匹配的intent對象的兩種方式:
1.使用代碼指定,調用BroadcastReceiver的Context的registerReceiver(BroadcastReceiver xxx,
Intent intent); 方法指定
2.在AndroidManifest.xml文件中配置。


注意:系統指定的BroadcastReceiver找不到時,系統也不會異常終止。

不要在receive中實現一個耗時的操作因爲可能會導致ANR異常。
建議使用intent在一個service中進行耗時操作(建議使用IntentService)

10.8.2 發送廣播

10.8.3 有序廣播

Broadcast被分爲兩種:
1.普通廣播 是完全異步的,可以在同一時刻被所有接收者收到,消息的傳遞效率比較高。

2.有序廣播 接收者將按照預先聲明的優先級依次接受Broadcast。接收者的優先級可以在intent-filter/>
的periority中設置。

優先接收到Broadcast的接收者可以調用abortBroadcast()終止進程。
優先收到的接收者可以調用setResultExtras(Bundle)方法將處理結果存入Broadcast對象中
然後傳給下一個接收者。

下一個接收者可以通過Bundle bundle = getResultExtras(true);獲取上一個接收者存入的數據。

//實例:基於Service的音樂播放器

//10.9 接受系統廣播消息

//實例:開機自動運行的Activity

//實例:手機電量顯示

sendStickyBroadcast():發送持續廣播

//------------------------截止到 p511(2020.1.3 凌晨1:14截至)------------------------//

用以記錄自己的學習過程,爲了方便日後複習。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章