1+x安卓應(yīng)用開(kāi)發(fā)(中級(jí))課程-項(xiàng)目6 組件化開(kāi)放_(tái)第1頁(yè)
1+x安卓應(yīng)用開(kāi)發(fā)(中級(jí))課程-項(xiàng)目6 組件化開(kāi)放_(tái)第2頁(yè)
1+x安卓應(yīng)用開(kāi)發(fā)(中級(jí))課程-項(xiàng)目6 組件化開(kāi)放_(tái)第3頁(yè)
1+x安卓應(yīng)用開(kāi)發(fā)(中級(jí))課程-項(xiàng)目6 組件化開(kāi)放_(tái)第4頁(yè)
1+x安卓應(yīng)用開(kāi)發(fā)(中級(jí))課程-項(xiàng)目6 組件化開(kāi)放_(tái)第5頁(yè)
已閱讀5頁(yè),還剩19頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

《騰訊1+x安卓應(yīng)用開(kāi)發(fā)(中級(jí))》教案

一、教案設(shè)計(jì)課題項(xiàng)目6任務(wù)1通用UI組件的開(kāi)發(fā)課型理論課理論課時(shí)2課時(shí)實(shí)踐課時(shí)2課時(shí)教學(xué)目標(biāo)知識(shí)目標(biāo)能力(技能)目標(biāo)掌握開(kāi)發(fā)通用UI組件的常用方法。能夠開(kāi)發(fā)通用UI組件,實(shí)現(xiàn)復(fù)雜UI效果。教學(xué)重點(diǎn)開(kāi)發(fā)通用UI組件的方法和步驟。教學(xué)難點(diǎn)自定義標(biāo)簽屬性和自定義組件類教學(xué)內(nèi)容自定義UI組件一般分為3個(gè)步驟。一是自定義標(biāo)簽屬性,二是自定義組件類,三是在XML布局文件中使用自定義標(biāo)簽。自定義的組件類可以繼承View及其子類,例如TextView、Button、ViewGroup、LinearLayout等。1.自定義標(biāo)簽屬性Android系統(tǒng)原生控件的屬性以android開(kāi)頭,例如android:layout_width表示寬度,我們自定義的組件也可以定義自己的屬性。在values目錄下創(chuàng)建attrs.xml文件,編寫(xiě)如下代碼:<?xmlversion="1.0"encoding="utf-8"?><resources>//LoadingView標(biāo)簽屬性定義<declare-styleablename="LoadingView"><attrname="loadingViewWidth"format="integer"></attr><attrname="loadingViewHeight"format="integer"></attr><attrname="loadingViewRadius"format="integer"></attr><attrname="loadingViewFillColor"format="color"></attr><attrname="loadingViewTextSize"format="dimension"></attr><attrname="loadingViewTextColor"format="color"></attr><attrname="loadingViewText"format="string"></attr></declare-styleable>name為自定義的名稱,format參數(shù)見(jiàn)表9-1。表9-1format參數(shù)表boolean布爾值color顏色值dimension尺寸值enum枚舉值float浮點(diǎn)值flag位或運(yùn)算fraction百分?jǐn)?shù)Integer整型值reference參考某一資源IDstring字符串系統(tǒng)提供了TypeArray類,獲取到該類的實(shí)例后就可通過(guò)getColor()等方法獲得布局文件中設(shè)置的屬性值。TypedArraytypeArray=context.obtainStyledAttributes(attrs,R.styleable.LoadingView);width=typeArray.getInt(R.styleable.LoadingView_loadingViewWidth,50);height=typeArray.getInt(R.styleable.LoadingView_loadingViewHeight,20);radius=typeArray.getInt(R.styleable.LoadingView_loadingViewRadius,10);fillColor=typeArray.getInt(R.styleable.LoadingView_loadingViewFillColor,Color.GRAY);textSize=typeArray.getDimension(R.styleable.LoadingView_loadingViewTextSize,10);textColor=typeArray.getInt(R.styleable.LoadingView_loadingViewTextColor,Color.WHITE);text=typeArray.getString(R.styleable.LoadingView_loadingViewText);2.定義組件類自定義組件類一般分為兩種情況。一是自定義的類繼承自View及其子類,例如View、TextView、Button等。這種情況下,通常是通過(guò)復(fù)寫(xiě)onMeasure()方法測(cè)量View的大小,并通過(guò)復(fù)寫(xiě)onDraw()方法繪制自定義控件的效果,繪制方法參見(jiàn)項(xiàng)目五任務(wù)一的圖形的繪制。二是自定義的類繼承自ViewGroup或者各種Layout,例如LinearLayout、RelativeLayout等。這種情況下,通常是把系統(tǒng)原生控件組合在一起形成復(fù)合的自定義控件。不管哪種情況,都需要?jiǎng)?chuàng)建構(gòu)造方法,如果有需求,還可以在此綁定業(yè)務(wù)邏輯,實(shí)現(xiàn)與用戶的交互。復(fù)寫(xiě)onDraw()方法繪制自定義控件的效果:publicclassLoadingViewextendsView{…@OverrideprotectedvoidonDraw(Canvascanvas){//在此方法中繪制控件super.onDraw(canvas);//繪制一個(gè)圓角矩形RectFrectf=newRectF(0,0,width,height);canvas.drawRoundRect(rectf,radius,radius,mPaint);mPaint.setColor(textColor);//在矩形上繪制文字canvas.drawText(text,width/2-mPaint.measureText(text)/2,height/2+textSize/2,mPaint);}…}把系統(tǒng)原生控件組合在一起形成復(fù)合的自定義控件:publicclassGeneralTopBarextendsRelativeLayout{…//創(chuàng)建按鈕leftBtn=newButton(context);tvTitle=newTextView(context);//設(shè)置按鈕的背景圖leftBtn.setBackground(leftBackground);//把按鈕添加到布局LayoutParamsleftParams=newLayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT);leftParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT);leftParams.addRule(RelativeLayout.CENTER_VERTICAL);addView(leftBtn,leftParams);LayoutParamstitleParams=newLayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.MATCH_PARENT);titleParams.addRule(RelativeLayout.CENTER_IN_PARENT);addView(tvTitle,titleParams);//把標(biāo)題文字添加到布局…}3.在XML布局文件中使用自定義標(biāo)簽<包名.類名android:layout_width="match_parent"android:layout_height="60dp"/>教學(xué)準(zhǔn)備教材,PPT、教綱、教案參考資料/huanghaibin-dev/CalendarView教學(xué)過(guò)程方法與手段教學(xué)備注【課堂導(dǎo)入】在實(shí)際項(xiàng)目開(kāi)發(fā)中,由于界面樣式和交互方式的個(gè)性化需求,僅使用Android原生的基本控件會(huì)影響開(kāi)發(fā)效率。此時(shí),需要開(kāi)發(fā)者對(duì)原生控件的樣式和交互行為進(jìn)行定制開(kāi)發(fā),構(gòu)建符合實(shí)際需求的自定義組件,以便提高開(kāi)發(fā)效率?!窘虒W(xué)實(shí)施】9.1.1任務(wù)描述把左右兩個(gè)Button和中間的TextView組合在一起形成復(fù)合UI組件標(biāo)題欄。左右兩個(gè)按鈕的背景圖和中間的標(biāo)題文字可以在布局文件中通過(guò)屬性自行設(shè)置,并為左右兩個(gè)按鈕綁定點(diǎn)擊事件。如圖所示。9.1.2問(wèn)題引導(dǎo)在實(shí)際項(xiàng)目開(kāi)發(fā)中,由于界面樣式和交互方式的個(gè)性化需求,僅使用Android原生的基本控件會(huì)影響開(kāi)發(fā)效率。此時(shí),需要開(kāi)發(fā)者對(duì)原生控件的樣式和交互行為進(jìn)行定制開(kāi)發(fā),構(gòu)建符合實(shí)際需求的自定義組件,以便提高開(kāi)發(fā)效率。9.1.3知識(shí)準(zhǔn)備自定義標(biāo)簽屬性自定義組件類在XML布局文件中使用自定義標(biāo)簽9.1.4完成一個(gè)復(fù)合UI組件標(biāo)題欄的制作9.1.5知識(shí)拓展通過(guò)復(fù)寫(xiě)onDraw()方法繪制控件來(lái)自定義組件【知識(shí)(技能)鞏固練習(xí)】自定義下圖所示的組合控件:【教學(xué)小結(jié)】講授、演示課后作業(yè)與訓(xùn)練完成項(xiàng)目6課后練習(xí)對(duì)應(yīng)的習(xí)題。教學(xué)反思

課題項(xiàng)目6任務(wù)2網(wǎng)絡(luò)請(qǐng)求組件的封裝課型理論課理論課時(shí)2課時(shí)實(shí)踐課時(shí)2課時(shí)教學(xué)目標(biāo)知識(shí)目標(biāo)能力(技能)目標(biāo)掌握封裝網(wǎng)絡(luò)請(qǐng)求組件的方法。能夠封裝網(wǎng)絡(luò)請(qǐng)求組件,發(fā)送請(qǐng)求,實(shí)現(xiàn)響應(yīng),完成業(yè)務(wù)功能需求。教學(xué)重點(diǎn)封裝網(wǎng)絡(luò)請(qǐng)求組件的方法。教學(xué)難點(diǎn)理解解耦設(shè)計(jì)思想。教學(xué)內(nèi)容1.創(chuàng)建OkHttpClient對(duì)象并初始化在整個(gè)項(xiàng)目中我們只需要一個(gè)OkHttpClient對(duì)象,不同的網(wǎng)絡(luò)請(qǐng)求只需要?jiǎng)?chuàng)建不同的Requset對(duì)象和Call對(duì)象。所以我們將OkHttpClient對(duì)象的創(chuàng)建寫(xiě)成單例模式。我們的做法是,寫(xiě)一個(gè)網(wǎng)絡(luò)請(qǐng)求的類NetClient。當(dāng)?shù)谝淮问褂肗etClient類時(shí),創(chuàng)建NetClient的對(duì)象,并且保證始終只有一個(gè)實(shí)例,okHttpClient作為NetClient對(duì)象的成員變量,也只有一個(gè)實(shí)例。具體代碼見(jiàn)任務(wù)實(shí)施部分。2.CallBack的封裝自己定義一個(gè)接口來(lái)代理OkHttp的CallBack接口,確保代碼中不出現(xiàn)與OkHttp相關(guān)的內(nèi)容,實(shí)現(xiàn)與OkHttp的解耦,方便后期的維護(hù)和修改。這部分封裝了對(duì)成功和失敗的回調(diào)處理,如下所示:publicinterfaceIMyJsonCallBack{/*連接失敗執(zhí)行的方法方法參數(shù)用int數(shù)據(jù)類型,相當(dāng)于是一個(gè)標(biāo)識(shí)*/voidonFailure(intcode);/*連接成功執(zhí)行的方法方法參數(shù)根據(jù)需求寫(xiě),可以是字符串,也可以是輸入流等*/voidonSuccess(TresponceBean);}在這個(gè)部分,可以根據(jù)業(yè)務(wù)需求設(shè)置不同類型的參數(shù)。在我們這個(gè)例子中,需要返回結(jié)果bean實(shí)體。對(duì)于不同的請(qǐng)求,Bean類的屬性有可能不同,因此在這里使用泛型T。3.發(fā)送網(wǎng)絡(luò)請(qǐng)求的封裝網(wǎng)絡(luò)請(qǐng)求主要包括GET請(qǐng)求和POST請(qǐng)求。我們的做法是在網(wǎng)絡(luò)請(qǐng)求的類NetClient中分別寫(xiě)兩個(gè)方法來(lái)實(shí)現(xiàn)這兩種請(qǐng)求。另外需要注意的是,OkHttp框架在回調(diào)完成后是處于子線程中的,而UI操作必須在主線程進(jìn)行,所以我們需要把請(qǐng)求結(jié)果傳遞給主線程。最后為了方便應(yīng)用層的使用,我們?cè)诳蚣軐訉⒎?wù)器返回的json格式的字符串解析成對(duì)應(yīng)的實(shí)體對(duì)象,這樣在應(yīng)用層中就可以直接操作Bean類的屬性了。教學(xué)準(zhǔn)備教材,PPT、教綱、教案參考資料教學(xué)過(guò)程方法與手段教學(xué)備注【課堂導(dǎo)入】我們?cè)陧?xiàng)目中常常需要請(qǐng)求網(wǎng)絡(luò),為了提高開(kāi)發(fā)效率,不可避免地使用一些第三方框架。第三方框架代碼看起來(lái)不多,但是如果我們每個(gè)請(qǐng)求都這么寫(xiě),還是會(huì)造成代碼冗余,另外,如果該框架的API發(fā)生了更新,那么每個(gè)網(wǎng)絡(luò)請(qǐng)求的地方都要修改,也不利于后期的維護(hù)。因此,有必要對(duì)第三方框架進(jìn)行二次封裝?!窘虒W(xué)實(shí)施】9.2.1任務(wù)描述對(duì)OkHttp網(wǎng)絡(luò)請(qǐng)求框架進(jìn)行二次封裝,封裝后提供GET請(qǐng)求和POST請(qǐng)求。對(duì)于GET請(qǐng)求,用戶只需要輸入請(qǐng)求url,就可以通過(guò)我們提供的CallBack接口獲取到返回的字符串。對(duì)于POST請(qǐng)求,用戶只需要輸入請(qǐng)求url、請(qǐng)求的bean實(shí)體和結(jié)果bean的字節(jié)碼,就可以通過(guò)我們提供的CallBack接口獲取到服務(wù)器返回的json字符串對(duì)應(yīng)的bean實(shí)體。9.2.2問(wèn)題引導(dǎo)我們?cè)陧?xiàng)目中常常需要請(qǐng)求網(wǎng)絡(luò),為了提高開(kāi)發(fā)效率,不可避免地使用一些第三方框架。第三方框架代碼看起來(lái)不多,但是如果我們每個(gè)請(qǐng)求都這么寫(xiě),還是會(huì)造成代碼冗余,另外,如果該框架的API發(fā)生了更新,那么每個(gè)網(wǎng)絡(luò)請(qǐng)求的地方都要修改,也不利于后期的維護(hù)。因此,有必要對(duì)第三方框架進(jìn)行二次封裝。9.2.3知識(shí)準(zhǔn)備創(chuàng)建OkHttpClient對(duì)象并初始化CallBack的封裝發(fā)送網(wǎng)絡(luò)請(qǐng)求的封裝9.2.4實(shí)現(xiàn)一個(gè)二次封裝的網(wǎng)絡(luò)框架,并利用框架分別發(fā)送GET請(qǐng)求和POST請(qǐng)求。9.2.5知識(shí)拓展什么是耦合什么是解耦怎么實(shí)現(xiàn)低耦合【知識(shí)(技能)鞏固練習(xí)】實(shí)現(xiàn)對(duì)OkHttpClient的二次封裝?!窘虒W(xué)小結(jié)】講授、演示課后作業(yè)與訓(xùn)練完成項(xiàng)目6課后練習(xí)對(duì)應(yīng)的習(xí)題。教學(xué)反思

課題項(xiàng)目6任務(wù)3通用業(yè)務(wù)組件的封裝課型理論課理論課時(shí)2課時(shí)實(shí)踐課時(shí)3課時(shí)教學(xué)目標(biāo)知識(shí)目標(biāo)能力(技能)目標(biāo)掌握封裝通用業(yè)務(wù)組件的方法。能夠?qū)νㄓ脴I(yè)務(wù)組件封裝,實(shí)現(xiàn)通用組件庫(kù),提升開(kāi)發(fā)效率。教學(xué)重點(diǎn)對(duì)通用業(yè)務(wù)組件的封裝。教學(xué)難點(diǎn)理解典型的組件化架構(gòu)教學(xué)內(nèi)容1.典型的組件化架構(gòu)組件化之前,所有業(yè)集中在一個(gè)Module中。業(yè)務(wù)之間能直接相互調(diào)用,代碼高度耦合,并且不能靈活對(duì)工程進(jìn)行配置和組裝。組件化之后,將不同的業(yè)務(wù)組件對(duì)應(yīng)不同的Module,通過(guò)APP殼管理各個(gè)業(yè)務(wù)組件和打包APK,通過(guò)通用組件庫(kù)提供基礎(chǔ)功能服務(wù)。如圖9-4所示。圖9-4典型的組件化架構(gòu)App殼:負(fù)責(zé)管理各個(gè)業(yè)務(wù)組件和打包APK,沒(méi)有具體的業(yè)務(wù)功能。業(yè)務(wù)組件層:根據(jù)不同的業(yè)務(wù)劃分成獨(dú)立的業(yè)務(wù)組件,每個(gè)組件都能獨(dú)立編譯運(yùn)行,組件之間不能直接調(diào)用。通用組件庫(kù):包含了各種開(kāi)源庫(kù)以及與業(yè)務(wù)無(wú)關(guān)的各種自主研發(fā)的工具,供業(yè)務(wù)組件調(diào)用。組件化給我們帶來(lái)的好處顯而易見(jiàn)。符合單一責(zé)任原則:各個(gè)組件專注自身功能的實(shí)現(xiàn),模塊中代碼高度聚合,只負(fù)責(zé)一項(xiàng)業(yè)務(wù)。加快編譯速度:每個(gè)業(yè)務(wù)功能都能獨(dú)立編譯運(yùn)行。提高協(xié)作效率:各業(yè)務(wù)研發(fā)可以互不干擾,團(tuán)隊(duì)成員只需專注自身負(fù)責(zé)的業(yè)務(wù),降低團(tuán)隊(duì)成員熟悉項(xiàng)目的成本。提高代碼的復(fù)用性:通用功能都封裝在通用組件庫(kù)中,業(yè)務(wù)組件添加了對(duì)通用組件庫(kù)的依賴便可以直接調(diào)用。降低維護(hù)成本:由于業(yè)務(wù)功能的獨(dú)立性,對(duì)一個(gè)業(yè)務(wù)的修改和增刪不會(huì)影響其他業(yè)務(wù)。2.統(tǒng)一管理所有版本號(hào)組件化后,每個(gè)業(yè)務(wù)組件對(duì)應(yīng)一個(gè)Module(模塊),需要對(duì)各個(gè)模塊的SDK等版本號(hào)進(jìn)行統(tǒng)一管理,做法是,首先在主工程的“perties”文件中,以鍵值對(duì)的方式設(shè)置好版本號(hào),然后在各個(gè)模塊的gradle文件中引用。默認(rèn)情況下,SDK等版本號(hào)直接用數(shù)字表示,如下方代碼所示:android{compileSdkVersion30buildToolsVersion"30.0.2"defaultConfig{applicationId"com.example.module_movie"minSdkVersion16targetSdkVersion30versionCode1versionName"1.0"…}}我們把那些需要統(tǒng)一的版本號(hào)在主工程的“perties”文件中以鍵值對(duì)的方式規(guī)定好,在這個(gè)文件定義的常量可以被任何一個(gè)build.gradle讀取。代碼如下所示:compile_sdk_version=30min_sdk_version=16target_sdk_version=30build_tools_version=30.0.2constraint_version=1.1.3規(guī)定好后,就可以在各個(gè)模塊的gradle文件中引用了,直接使用鍵名就可以獲得對(duì)應(yīng)的值,但需要注意的是,所有取出來(lái)的值都是String字符串形式的,所以如果我們想獲得整形數(shù)據(jù),必須用toInteger()進(jìn)行轉(zhuǎn)換。代碼如下所示:android{compileSdkVersioncompile_sdk_version.toInteger()buildToolsVersionbuild_tools_versiondefaultConfig{…minSdkVersionmin_sdk_version.toInteger()targetSdkVersiontarget_sdk_version.toInteger()versionCode1versionName"1.0"…}}對(duì)于第三方庫(kù)也可以統(tǒng)一管理其版本號(hào),代碼如下:dependencies{…api"com.android.support.constraint:constraint-layout:$constraint_version"…}由于constraint_version寫(xiě)在雙引號(hào)中,所以需要在其前面加上$,這樣才能取出constraint_version這個(gè)鍵對(duì)應(yīng)的值。又因?yàn)槲覀兪峭ㄟ^(guò)通用庫(kù)來(lái)管理第三方庫(kù)的,所以,業(yè)務(wù)組件的Gradle文件不需要添加以上對(duì)第三方庫(kù)依賴的代碼。3.靈活切換業(yè)務(wù)組件的模式我們希望業(yè)務(wù)組件在開(kāi)發(fā)過(guò)程中能獨(dú)立運(yùn)行調(diào)試,獨(dú)立開(kāi)發(fā)調(diào)試完成后,能以插件的形式進(jìn)行集成調(diào)試。通過(guò)Gradle能實(shí)現(xiàn)這兩種模式之間的靈活切換。AndroidGradle提供了兩種插件,在開(kāi)發(fā)中可以通過(guò)配置不同的插件來(lái)切換不同的模式。Application插件:其id是com.android.applicationLibrary插件:其id是com.android.library配置為Application插件意味著該模塊能獨(dú)立運(yùn)行調(diào)試,項(xiàng)目構(gòu)建后會(huì)輸出一個(gè)APK安裝包。配置為L(zhǎng)ibrary插件則意味著該模塊以插件的形式進(jìn)行集成調(diào)試,構(gòu)建后輸出ARR包。4.在業(yè)務(wù)組件中使用通用組件庫(kù)定義好的功能想要在業(yè)務(wù)組件中使用通用組件庫(kù)定義好的功能,就需要在業(yè)務(wù)組件的Gradle文件中添加對(duì)通用組件庫(kù)的依賴。代碼如下所示:dependencies{…/*添加對(duì)通用組件庫(kù)的依賴*/implementationproject(path:':lib_common')…}“l(fā)ib_common”是通用組件庫(kù)的模塊名。此外,通用組件庫(kù)需要以api的方式添加對(duì)第三方庫(kù)的依賴。這樣,在通用組件庫(kù)中添加第三方庫(kù)即可,依賴于通用組件庫(kù)的業(yè)務(wù)模塊不需要再添加。代碼如下:dependencies{…api'com.squareup.okhttp3:okhttp:4.9.0'…}5.各業(yè)務(wù)組件之間的跳轉(zhuǎn)各業(yè)務(wù)組件解耦后,無(wú)法再通過(guò)startActivity()的方法打開(kāi)其他組件的Activity。這時(shí),我們可以通過(guò)阿里提供的一個(gè)路由框架ARouter來(lái)實(shí)現(xiàn)業(yè)務(wù)組件之間的跳轉(zhuǎn)。(1)使用ARouter前需要添加兩個(gè)依賴。一個(gè)是路由器,一個(gè)是注解處理器。在通用組件庫(kù)的build.gradle中添加的依賴,代碼如下://路由api"com.alibaba:arouter-api:$arouter_api"在業(yè)務(wù)組件的build.gradle中添加的依賴,代碼如下://注解處理器,在每個(gè)需要跳轉(zhuǎn)的module中都加上,不能只在通用組件庫(kù)中添加annotationProcessor"com.alibaba:arouter-compiler:$arouter_processor_version"為業(yè)務(wù)組件配置路徑映射的前綴,代碼如下:android{defaultConfig{//配置路徑映射的前綴,用于ARouter跳轉(zhuǎn)找到路徑j(luò)avaCompileOptions{annotationProcessorOptions{arguments=[AROUTER_MODULE_NAME:project.getName()]}}}}(2)為需要跳轉(zhuǎn)的Activity添加注解需要注意的是,路徑至少兩級(jí),即/xx/xx,代碼如下:@Route(path="/ModuleFood/FoodActivity")publicclassFoodActivityextendsAppCompatActivity{}(3)在Application中初始化ARouter.init(this);(4)在需要跳轉(zhuǎn)的地方使用ARouter.getInstance().build("/ModuleFood/FoodActivity").navigation();教學(xué)準(zhǔn)備教材,PPT、教綱、教案參考資料教學(xué)過(guò)程方法與手段教學(xué)備注【課堂導(dǎo)入】在實(shí)際開(kāi)發(fā)中,隨著項(xiàng)目需求的增加和變化,項(xiàng)目會(huì)越來(lái)越大,代碼越來(lái)越臃腫,耦合越來(lái)越多,如果修改某個(gè)業(yè)務(wù),則導(dǎo)致其他業(yè)務(wù)受影響,并且,對(duì)工程所做的任何修改都要編譯整個(gè)工程,覆蓋所有業(yè)務(wù)測(cè)試,導(dǎo)致開(kāi)發(fā)效率降低。為了解決這些問(wèn)題,我們需要對(duì)項(xiàng)目進(jìn)行重構(gòu)以及模塊的拆分,每個(gè)業(yè)務(wù)對(duì)應(yīng)一個(gè)模塊,使工程下的各個(gè)業(yè)務(wù)組件(業(yè)務(wù)模塊)相互獨(dú)立,沒(méi)有關(guān)聯(lián),這些業(yè)務(wù)組件可以調(diào)用通用組件庫(kù)的工具。各個(gè)業(yè)務(wù)組件既可以單獨(dú)編譯運(yùn)行,也可以集成到app工程中運(yùn)行,從而提高開(kāi)發(fā)效率?!窘虒W(xué)實(shí)施】9.3.1任務(wù)描述工程下包含“美食”和“電影”兩個(gè)業(yè)務(wù)組件,以及一個(gè)通用組件庫(kù)。兩個(gè)業(yè)務(wù)模塊各司其職,相互獨(dú)立,通用組件庫(kù)包含了各種開(kāi)源庫(kù)以及與業(yè)務(wù)無(wú)關(guān)的各種自主研發(fā)的工具,供業(yè)務(wù)組件調(diào)用。兩個(gè)業(yè)務(wù)組件之間通過(guò)阿里路由框架ARouter實(shí)現(xiàn)組件之間的跳轉(zhuǎn)。9.3.2問(wèn)題引導(dǎo)在實(shí)際開(kāi)發(fā)中,隨著項(xiàng)目需求的增加和變化,項(xiàng)目會(huì)越來(lái)越大,代碼越來(lái)越臃腫,耦合越來(lái)越多,如果修改某個(gè)業(yè)務(wù),則導(dǎo)致其他業(yè)務(wù)受影響,并且,對(duì)工程所做的任何修改都要編譯整個(gè)工程,覆蓋所有業(yè)務(wù)測(cè)試,導(dǎo)致開(kāi)發(fā)效率降低。為了解決這些問(wèn)題,我們需要對(duì)項(xiàng)目進(jìn)行重構(gòu)以及模塊的拆分,每個(gè)業(yè)務(wù)對(duì)應(yīng)一個(gè)模塊,使工程下的各個(gè)業(yè)務(wù)組件(業(yè)務(wù)模塊)相互獨(dú)立,沒(méi)有關(guān)聯(lián),這些業(yè)務(wù)組件可以調(diào)用通用組件庫(kù)的工具。各個(gè)業(yè)務(wù)組件既可以單獨(dú)編譯運(yùn)行,也可以集成到app工程中運(yùn)行,從而提高開(kāi)發(fā)效率。9.3.3知識(shí)準(zhǔn)備典型的組件化架構(gòu)統(tǒng)一管理所有版本號(hào)靈活切換業(yè)務(wù)組件的模式在業(yè)務(wù)組件中使用通用組件庫(kù)定義好的功能各業(yè)務(wù)組件之間的跳轉(zhuǎn)9.3.4實(shí)現(xiàn)以下功能:包含“美食”和“電影”兩個(gè)業(yè)務(wù)組件,以及一個(gè)通用組件庫(kù)。兩個(gè)業(yè)務(wù)模塊各司其職,相互獨(dú)立,通用組件庫(kù)包含了各種開(kāi)源庫(kù)以及與業(yè)務(wù)無(wú)關(guān)的各種自主研發(fā)的工具,供業(yè)務(wù)組件調(diào)用。兩個(gè)業(yè)務(wù)組件之間通過(guò)阿里路由框架ARouter實(shí)現(xiàn)組件之間的跳轉(zhuǎn)?!局R(shí)(技能)鞏固練習(xí)】創(chuàng)建兩個(gè)業(yè)務(wù)組件,并實(shí)現(xiàn)它們之間的跳轉(zhuǎn)?!窘虒W(xué)小結(jié)】講授、演示課后作業(yè)與訓(xùn)練完成項(xiàng)目6課后練習(xí)對(duì)應(yīng)的習(xí)題。教學(xué)反思

課題項(xiàng)目6任務(wù)4Jetpack架構(gòu)組件的使用課型理論課理論課時(shí)3課時(shí)實(shí)踐課時(shí)3課時(shí)教學(xué)目標(biāo)知識(shí)目標(biāo)能力(技能)目標(biāo)熟悉Jetpack架構(gòu)組件及其作用。能夠掌握J(rèn)etpack架構(gòu)組件封裝,解決安卓開(kāi)發(fā)碎片化問(wèn)題。教學(xué)重點(diǎn)ViewModel、LiveData和DataBingding的配合使用。教學(xué)難點(diǎn)理解安卓開(kāi)發(fā)碎片化產(chǎn)生的原因和Jetpack在解決碎片化問(wèn)題中的作用。教學(xué)內(nèi)容1.Jetpack是什么Jetpack包含與平臺(tái)API解除捆綁的androidx.*軟件包庫(kù)。從產(chǎn)品的維度叫做Jetpack,從技術(shù)的維度叫做AndroidX。目前Jetpack中所有的組件庫(kù)的包名都以AndroidX開(kāi)頭,AndroidX命名空間中的庫(kù)與Android平臺(tái)分開(kāi)提供,并向后兼容各個(gè)Android版本。Jetpack可以提供向后兼容性,且比Android平臺(tái)的更新頻率更高,以此確保您始終可以獲取最新且最好的Jetpack組件版本。2.Jetpack的優(yōu)勢(shì)(1)遵循最佳做法AndroidJetpack組件采用最新的設(shè)計(jì)方法構(gòu)建,具有向后兼容性,可以減少崩潰和內(nèi)存泄露。(2)消除樣板代碼AndroidJetpack可以管理各種繁瑣的Activity(如后臺(tái)任務(wù)、導(dǎo)航和生命周期管理),消除大量重復(fù)樣板式的代碼,以便開(kāi)發(fā)者可以更高效更專注地打造出色的應(yīng)用。(3)減少不一致Jetpack組件庫(kù)可在各種Android版本和設(shè)備中以一致的方式運(yùn)作,幫助您降低復(fù)雜性。3.Jetpack組件庫(kù)Jetpack組件是庫(kù)的集合,可以搭配工作,也可以單獨(dú)使用,API以JetpackLibrary的形式提供給我們,使得我們不需要對(duì)不同的系統(tǒng)版本寫(xiě)適配邏輯,而是統(tǒng)一使用Jetpack提供的接口即可,從而解決長(zhǎng)期以來(lái)的碎片化問(wèn)題。Jetpack主要包括4個(gè)部分,分別是基礎(chǔ)(Foundation)、架構(gòu)(Architecture)、行為(Behavior)和界面(UI)。(1)基礎(chǔ)組件基礎(chǔ)組件可以提供橫向功能,例如向后兼容性、測(cè)試和Kotlin語(yǔ)言支持。AppCompat:幫助較低版本的Android系統(tǒng)進(jìn)行兼容。AndroidKTX:幫助開(kāi)發(fā)者編寫(xiě)更簡(jiǎn)潔、更慣用的Kotlin代碼。多dex處理:為具有多個(gè)DEX文件的應(yīng)用提供支持。測(cè)試:用于單元和運(yùn)行時(shí)界面測(cè)試的Android測(cè)試框架。(2)架構(gòu)組件架構(gòu)組件可以幫助開(kāi)發(fā)者設(shè)計(jì)穩(wěn)健、可測(cè)試且易維護(hù)的應(yīng)用。DataBingding:以聲明的方式將應(yīng)用中的數(shù)據(jù)源綁定到界面組件。Lifecycles:構(gòu)建生命周期感知型組件,這些組件可以根據(jù)Activity或Fragment的當(dāng)前生命周期狀態(tài)調(diào)整行為。LiveData:在底層數(shù)據(jù)庫(kù)更改時(shí)通知視圖。Navigation:構(gòu)建和組織應(yīng)用內(nèi)界面,處理深層鏈接以及在屏幕之間導(dǎo)航。Paging:在頁(yè)面中加載數(shù)據(jù),并在RecyclerView中呈現(xiàn),可以輕松完成分頁(yè)預(yù)加載以達(dá)到無(wú)限滑動(dòng)的效果特性。Room:創(chuàng)建、存儲(chǔ)和管理由SQLite數(shù)據(jù)庫(kù)支持的持久性數(shù)據(jù)。通過(guò)注解的方式實(shí)現(xiàn)相關(guān)功能,編譯時(shí)自動(dòng)生成相關(guān)實(shí)現(xiàn)類。ViewModel:以注重生命周期的方式管理界面相關(guān)的數(shù)據(jù)。讓數(shù)據(jù)可在發(fā)生屏幕旋轉(zhuǎn)等配置更改后繼續(xù)留存。可以實(shí)現(xiàn)在Fragment之間共享數(shù)據(jù)。WorkManager:管理Android后臺(tái)作業(yè)??梢暂p松地調(diào)度那些必須可靠運(yùn)行的可延期異步任務(wù)。通過(guò)這些API,可以創(chuàng)建任務(wù)并提交給WorkManager,以便在滿足工作約束條件時(shí)運(yùn)行。(3)行為組件行為組件可以幫助開(kāi)發(fā)者的應(yīng)用與標(biāo)準(zhǔn)Android服務(wù)(如通知、權(quán)限、分享)相集成。下載管理器:安排和管理大量下載任務(wù)。媒體和播放:用于媒體播放和路由的向后兼容API(包括GoogleCast)。通知:提供向后兼容的通知API,支持Wear和Auto。權(quán)限:用于檢查和請(qǐng)求應(yīng)用權(quán)限的兼容性API偏好設(shè)置:創(chuàng)建交互式設(shè)置屏幕,建議使用AndroidXPreferenceLibrary庫(kù)將用戶可配置設(shè)置集成到應(yīng)用中。共享:提供適合應(yīng)用操作欄的共享操作??梢愿p松地實(shí)現(xiàn)友好的用戶分享。切片:在應(yīng)用外顯示模板化界面元素。(4)界面組件動(dòng)畫(huà)和過(guò)渡:使用開(kāi)始和結(jié)束狀態(tài)在UI中設(shè)置運(yùn)動(dòng)動(dòng)畫(huà)。表情符號(hào):在舊版平臺(tái)上也能啟用最新的表情符號(hào)字體。Fragment:組件化界面的基本單位。布局:用XML中聲明UI元素或者在代碼中實(shí)例化UI元素;調(diào)色板:從調(diào)色板中提取出有用的信息。Jetpack的內(nèi)容非常豐富,這里主要介紹架構(gòu)組件中的ViewModel、 LiveData和 DataBinding的使用。更多內(nèi)容可以通過(guò)官方文檔進(jìn)行學(xué)習(xí):/jetpack。4.ViewModelViewModel把View中的數(shù)據(jù)獨(dú)立處理,單獨(dú)對(duì)其進(jìn)行存儲(chǔ)和管理,使得Activity/Fragment的功能得到簡(jiǎn)化,不需要再管理界面中的數(shù)據(jù)。此外,ViewModel讓數(shù)據(jù)可在發(fā)生屏幕旋轉(zhuǎn)等配置更改后繼續(xù)留存。圖9-17展示了Activity發(fā)生屏幕旋轉(zhuǎn)而后結(jié)束的過(guò)程中經(jīng)歷的各種生命周期狀態(tài),并在右側(cè)顯示了在此過(guò)程中,ViewModel的生命周期。系統(tǒng)可能會(huì)在Activity的整個(gè)生命周期內(nèi)多次調(diào)用onCreate(),例如在旋轉(zhuǎn)設(shè)備屏幕或者切換系統(tǒng)語(yǔ)言時(shí),就會(huì)再次調(diào)用onCreate()。ViewModel存在的時(shí)間范圍是從首次請(qǐng)求ViewModel直到Activity完成并銷毀。因此,我們通常在系統(tǒng)首次調(diào)用Activity對(duì)象的onCreate()方法時(shí)請(qǐng)求ViewModel。(1)創(chuàng)建一個(gè)自己的ViewModel類publicclassMyViewModelextendsViewModel{publicintnumber=0;}(2)在Activity的onCreate()方法中請(qǐng)求ViewModelprotectedvoidonCreate(BundlesavedInstanceState){…ViewModelProvider.AndroidViewModelFactoryfactory=ViewModelProvider.AndroidViewModelFactory.getInstance(getApplication());MyViewModelmyViewModel=newViewModelProvider(this,factory).get(MyViewModel.class);…}圖9-17Activity發(fā)生屏幕旋轉(zhuǎn)而后結(jié)束的過(guò)程中ViewModel的生命周期5.LiveData(1)簡(jiǎn)介L(zhǎng)iveData是一種可觀察的數(shù)據(jù)存儲(chǔ)器類。與常規(guī)的可觀察類不同,LiveData具有生命周期感知能力,意指它遵循其他應(yīng)用組件(如Activity、Fragment或Service)的生命周期。這種感知能力可確保LiveData僅更新處于活躍生命周期狀態(tài)的應(yīng)用組件觀察者。如果觀察者(由Observer類表示)的生命周期處于STARTED或RESUMED狀態(tài),則LiveData會(huì)認(rèn)為該觀察者處于活躍狀態(tài)。LiveData只會(huì)將更新通知給活躍的觀察者。為觀察LiveData對(duì)象而注冊(cè)的非活躍觀察者不會(huì)收到更改通知。我們可以注冊(cè)一個(gè)跟實(shí)現(xiàn)了LifecycleOwner接口的對(duì)象配對(duì)的觀察者。有了這種關(guān)系,當(dāng)相應(yīng)的Lifecycle對(duì)象的狀態(tài)變?yōu)镈ESTROYED時(shí),此關(guān)系允許移除觀察者。這對(duì)于Activity和Fragment特別有用,因?yàn)樗鼈兛梢苑判牡赜^察LiveData對(duì)象,而不必?fù)?dān)心泄露(當(dāng)Activity和Fragment的生命周期被銷毀時(shí),系統(tǒng)會(huì)立即退訂它們)。(2)使用LiveData的優(yōu)勢(shì)使用LiveData有以下幾個(gè)優(yōu)勢(shì):確保界面符合數(shù)據(jù)狀態(tài)LiveData遵循觀察者模式。當(dāng)?shù)讓訑?shù)據(jù)發(fā)生變化時(shí),LiveData會(huì)通知Observer對(duì)象。您可以整合代碼以在這些Observer對(duì)象中更新界面。這樣一來(lái),您無(wú)需在每次應(yīng)用數(shù)據(jù)發(fā)生變化時(shí)更新界面,因?yàn)橛^察者會(huì)替您完成更新。不會(huì)發(fā)生內(nèi)存泄漏觀察者會(huì)綁定到Lifecycle對(duì)象,并在其關(guān)聯(lián)的生命周期遭到銷毀后進(jìn)行自我清理。不會(huì)因Activity停止而導(dǎo)致崩潰如果觀察者的生命周期處于非活躍狀態(tài)(如返回棧中的Activity),則它不會(huì)接收任何LiveData事件。不再需要手動(dòng)處理生命周期界面組件只是觀察相關(guān)數(shù)據(jù),不會(huì)停止或恢復(fù)觀察。LiveData將自動(dòng)管理所有這些操作,因?yàn)樗谟^察時(shí)可以感知相關(guān)的生命周期狀態(tài)變化。數(shù)據(jù)始終保持最新?tīng)顟B(tài)如果生命周期變?yōu)榉腔钴S狀態(tài),它會(huì)在再次變?yōu)榛钴S狀態(tài)時(shí)接收最新的數(shù)據(jù)。例如,曾經(jīng)在后臺(tái)的Activity會(huì)在返回前臺(tái)后立即接收最新的數(shù)據(jù)。適當(dāng)?shù)呐渲酶娜绻捎谂渲酶模ㄈ缭O(shè)備旋轉(zhuǎn))而重新創(chuàng)建了Activity或Fragment,它會(huì)立即接收最新的可用數(shù)據(jù)。共享資源您可以使用單例模式擴(kuò)展LiveData對(duì)象以封裝系統(tǒng)服務(wù),以便在應(yīng)用中共享它們。LiveData對(duì)象連接到系統(tǒng)服務(wù)一次,然后需要相應(yīng)資源的任何觀察者只需觀察LiveData對(duì)象。(3)使用LiveData的步驟①創(chuàng)建LiveData對(duì)象創(chuàng)建LiveData的實(shí)例以存儲(chǔ)某種類型的數(shù)據(jù)。這通常在ViewModel類中完成。publicclassNameViewModelextendsViewModel{//創(chuàng)建LiveData以存儲(chǔ)String類型的數(shù)據(jù)privateMutableLiveData<String>currentName;//定義getCurrentName()方法,用來(lái)獲取變量currentName的值publicMutableLiveData<String>getCurrentName(){if(currentName==null){currentName=newMutableLiveData<String>();}returncurrentName;}...}注意:請(qǐng)確保用于更新界面的LiveData對(duì)象存儲(chǔ)在ViewModel對(duì)象中,而不是將其存儲(chǔ)在Activity或Fragment中,這樣可以避免Activity和Fragment過(guò)于龐大(只負(fù)責(zé)顯示數(shù)據(jù),不負(fù)責(zé)存儲(chǔ)數(shù)據(jù)狀態(tài))。還可以將LiveData實(shí)例與特定的Activity或Fragment實(shí)例解耦,并使LiveData對(duì)象在配置更改后繼續(xù)存在。②觀察LiveData對(duì)象創(chuàng)建一個(gè)Observer對(duì)象,該對(duì)象可以定義onChanged()方法,該方法用來(lái)控制LiveData對(duì)象存儲(chǔ)的數(shù)據(jù)更改時(shí)發(fā)生的操作。通常情況下,我們可以在界面控制器(如Activity或Fragment)中創(chuàng)建Observer對(duì)象。在大多數(shù)情況下,應(yīng)用組件的onCreate()方法是開(kāi)始觀察LiveData對(duì)象的正確位置。原因一是確保系統(tǒng)不會(huì)從Activity或Fragment的onResume()方法進(jìn)行冗余調(diào)用。原因二是確保Activity或Fragment變?yōu)榛钴S狀態(tài)后具有可以立即顯示的數(shù)據(jù)。一旦應(yīng)用組件處于STARTED狀態(tài),就會(huì)從它正在觀察的LiveData對(duì)象接收最新值。通常,LiveData僅在數(shù)據(jù)發(fā)生更改時(shí)才發(fā)送更新,并且僅發(fā)送給活躍觀察者。有一種例外情況是,觀察者從非活躍狀態(tài)更改為活躍狀態(tài)時(shí)也會(huì)收到更新。此外,如果觀察者第二次從非活躍狀態(tài)更改為活躍狀態(tài),則只有在自上次變?yōu)榛钴S狀態(tài)以來(lái)值發(fā)生了更改時(shí),它才會(huì)收到更新。publicclassNameActivityextendsAppCompatActivity{privateNameViewModelmodel;@OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);...//獲取ViewModelViewModelProvider.AndroidViewModelFactoryfactory=ViewModelProvider.AndroidViewModelFactory.getInstance(getApplication());model=newViewModelProvider(this,factory).get(ViewModelWithLiveData.class);//創(chuàng)建更新用戶界面的觀察者finalObserver<String>nameObserver=newObserver<String>(){@OverridepublicvoidonChanged(@NullablefinalStringnewName){//更新UI,在本例中是TextViewnameTextView.setText(newName);}};//觀察LiveData,把LifecycleOwner和observer作為參數(shù)傳入這個(gè)Activitymodel.getCurrentName().observe(this,nameObserver);}}在以nameObserver作為參數(shù)的情況下調(diào)用observe()后,系統(tǒng)會(huì)立即調(diào)用onChanged(),從而提供mCurrentName中存儲(chǔ)的最新值。如果LiveData對(duì)象尚未在mCurrentName中設(shè)置值,則不會(huì)調(diào)用onChanged()。③更新LiveData對(duì)象LiveData沒(méi)有公開(kāi)可用的方法來(lái)更新存儲(chǔ)的數(shù)據(jù),但其子類MutableLiveData類有兩個(gè)public方法setValue(T)和postValue(T),如果我們需要修改存儲(chǔ)在LiveData對(duì)象中的值,必須使用這些方法。通常情況下會(huì)在ViewModel中使用MutableLiveData,然后ViewModel只會(huì)向觀察者公開(kāi)不可變的LiveData對(duì)象。設(shè)置觀察者關(guān)系后,您可以更新LiveData對(duì)象的值,這樣當(dāng)用戶點(diǎn)按某個(gè)按鈕時(shí)會(huì)觸發(fā)所有觀察者,代碼如下:button.setOnClickListener(newOnClickListener(){@OverridepublicvoidonClick(Viewv){StringanotherName="JohnDoe";model.getCurrentName().setValue(anotherName);}});在本示例中調(diào)用setValue(T)能致使觀察者使用值“JohnDoe”調(diào)用其onChanged()方法。本示例中演示的是按下按鈕時(shí)的方法,但也可以出于各種各樣的原因調(diào)用setValue()或postValue()來(lái)更新mName,這些原因包括響應(yīng)網(wǎng)絡(luò)請(qǐng)求或數(shù)據(jù)庫(kù)加載完成等。在所有情況下,調(diào)用setValue()或postValue()都會(huì)觸發(fā)觀察者并更新界面。注意:我們必須調(diào)用setValue(T)方法以從主線程更新LiveData對(duì)象。如果在工作線程中執(zhí)行代碼,可以改用postValue(T)方法來(lái)更新LiveData對(duì)象。6.DataBinding(1)簡(jiǎn)介DataBinding以聲明的方式將應(yīng)用中的數(shù)據(jù)源綁定到界面組件。通過(guò)DataBinding能使Activity/Fragment的功能得到進(jìn)一步簡(jiǎn)化,Activity/Fragment與View直接不再需要通過(guò)引用建立聯(lián)系,而是通過(guò)DataBinding建立它們之間的關(guān)聯(lián)。從而使MVVC(Model數(shù)據(jù)層-View視圖層-ViewModel數(shù)據(jù)視圖層)各個(gè)模塊更加獨(dú)立,程序變得更加模塊化,更容易維護(hù)。(2)使用DataBinding的步驟①開(kāi)啟DataBinding打開(kāi)當(dāng)前模塊的build.gradle文件,在android模塊中添加如下配置:android{…defaultConfig{…buildFeatures{dataBinding=true}}}②修改布局文件把布局文件的根節(jié)點(diǎn)改為“l(fā)ayout”,里面包括了data節(jié)點(diǎn)和傳統(tǒng)的布局。data節(jié)點(diǎn)起到連接View和Modle的作用。在data節(jié)點(diǎn)中聲明variable變量,這些變量的值可以輕松地傳到布局文件的對(duì)應(yīng)控件中。<?xmlversion="1.0"encoding="utf-8"?><layoutxmlns:android="/apk/res/android"xmlns:app="/apk/res-auto"xmlns:tools="/tools"><data><variablename="mydata"type="com.example.chapter09.jetpack_component.ViewModelWithLiveData"/></data><androidx.constraintlayout.widget.ConstraintLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"tools:context=".ThirdActivity"><TextView…android:text="@{String.valueOf(mydata.number)}"…/>…<Button…android:onClick="@{()->mydata.addNumber(1)}"/>…</androidx.constraintlayout.widget.ConstraintLayout></layout>variable節(jié)點(diǎn)中的name是自定義的變量名,type是這個(gè)變量的類型。此時(shí),TextView控件的text屬性就可以設(shè)置為"@{String.valueOf(mydata.number)}",表示將mydata.number的值轉(zhuǎn)為字符串后作為其屬性值。number是位于com.example.chapter09.jetpack_component包中的ViewModelWithLiveData類的一個(gè)屬性。Button控件的onClick屬性設(shè)置為"@{()->mydata.addNumber()}",表示當(dāng)該按鈕被單擊時(shí),調(diào)用mydata的addNumber()方法。addNumber()是com.example.chapter09.jetpa

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論