999精品在线视频,手机成人午夜在线视频,久久不卡国产精品无码,中日无码在线观看,成人av手机在线观看,日韩精品亚洲一区中文字幕,亚洲av无码人妻,四虎国产在线观看 ?

面向觸控類(lèi)安卓支持庫(kù)的應(yīng)用代碼替換技術(shù)

2020-11-12 10:38:34沈立煒趙文耘
關(guān)鍵詞:特征功能方法

王 超 沈立煒 趙文耘

1(復(fù)旦大學(xué)軟件學(xué)院 上海 201203) 2(復(fù)旦大學(xué)計(jì)算機(jī)科學(xué)技術(shù)學(xué)院 上海 201203) 3(上海市數(shù)據(jù)科學(xué)重點(diǎn)實(shí)驗(yàn)室 上海 201203)

0 引 言

屏幕觸摸是移動(dòng)設(shè)備上最主要的人機(jī)交互渠道,它能提供例如下拉刷新、左右滑動(dòng)等應(yīng)用特性,這些特性豐富了界面的展示效果。為了實(shí)現(xiàn)這些特性,安卓應(yīng)用開(kāi)發(fā)者需要基于最基本的onTouchEvent等事件機(jī)制集成應(yīng)用響應(yīng)邏輯,但依舊需要編寫(xiě)相應(yīng)代碼以識(shí)別觸控的事件類(lèi)型,如手指的下拉、釋放等。

谷歌從2011年開(kāi)始提供安卓支持庫(kù)來(lái)輔助開(kāi)發(fā)者,這些支持庫(kù)對(duì)開(kāi)發(fā)者經(jīng)常需要的功能進(jìn)行了封裝,其中包括了對(duì)特定類(lèi)型界面觸控事件的封裝,例如SwipRefreshLayout控件集成了下拉刷新的功能、DrawerLayout控件集成了左右滑動(dòng)的功能。使用這些支持庫(kù)不僅提高了開(kāi)發(fā)者的開(kāi)發(fā)效率,而且能夠在低版本的安卓平臺(tái)上使用高版本的功能。但許多開(kāi)發(fā)者對(duì)安卓支持庫(kù)提供的功能缺乏了解,因此將已有代碼替換成支持庫(kù)需要花費(fèi)很多的精力去學(xué)習(xí),比如開(kāi)發(fā)者需要對(duì)安卓支持庫(kù)中下拉刷新、左右側(cè)滑等控件的代碼結(jié)構(gòu)和實(shí)現(xiàn)機(jī)制有深入的了解。此外,對(duì)于維護(hù)采用基本事件處理機(jī)制編寫(xiě)的安卓應(yīng)用程序,沒(méi)有相應(yīng)的技術(shù)來(lái)提醒安卓應(yīng)用維護(hù)者進(jìn)行支持庫(kù)的替換,因此維護(hù)人員需要花費(fèi)額外的精力在應(yīng)用程序的源碼中尋找可替換的功能代碼。

目前已經(jīng)有的代碼替換工作主要集中在API和Library庫(kù)的遷移。例如將項(xiàng)目中涉及的棄用API(Deprecated API) 用新的API進(jìn)行遷移[1]。再比如隨著軟件系統(tǒng)生命周期的變化,對(duì)于系統(tǒng)中已有的依賴(lài)庫(kù)需要用更相關(guān)的庫(kù)來(lái)進(jìn)行遷移[2]。而對(duì)于將已有功能代碼替換成安卓支持庫(kù)中相應(yīng)控件實(shí)現(xiàn)的代碼,目前還沒(méi)有很好的方法來(lái)支持。

針對(duì)上述目標(biāo),本文提出了一種面向安卓觸控類(lèi)支持庫(kù)的應(yīng)用代碼替換技術(shù),其利用android.support.v4.widget支持庫(kù)下的觸摸控件并以自動(dòng)化的方式尋找目標(biāo)應(yīng)用中的可替換點(diǎn),最終為應(yīng)用開(kāi)發(fā)者和維護(hù)者生成替換建議。具體而言,本文首先提出用以描述安卓事件回調(diào)方法代碼特征的元模型,以此為基礎(chǔ)將目標(biāo)代碼特征模型與安卓支持庫(kù)各控件的特征模型進(jìn)行匹配。當(dāng)匹配的結(jié)果能夠進(jìn)行替換時(shí),分別從功能的實(shí)現(xiàn)代碼、監(jiān)聽(tīng)器的綁定、layout資源文件這三個(gè)方面生成替換建議。實(shí)驗(yàn)結(jié)果表明本文所提技術(shù)能夠?yàn)橹С謳?kù)控件相應(yīng)的,且用基本觸控邏輯來(lái)實(shí)現(xiàn)的事件回調(diào)方法及其資源布局給出正確的替換建議。安卓開(kāi)發(fā)者利用本文方法,可以分析出應(yīng)用程序中的哪些代碼可以進(jìn)行替換,以及用安卓支持庫(kù)中的哪一個(gè)觸摸控件進(jìn)行替換。

1 相關(guān)工作

與本文相關(guān)的研究工作主要包括安卓應(yīng)用分析、代碼相似度檢測(cè)、代碼遷移技術(shù)這三個(gè)方面。

安卓應(yīng)用分析方法主要分為動(dòng)態(tài)分析和靜態(tài)分析兩大類(lèi)。動(dòng)態(tài)分析是指當(dāng)應(yīng)用程序在運(yùn)行時(shí)對(duì)應(yīng)用程序的各種行為進(jìn)行分析,以獲取程序的動(dòng)態(tài)行為特征。靜態(tài)分析則是分析應(yīng)用程序的源碼或者字節(jié)碼,構(gòu)造應(yīng)用程序的整體結(jié)構(gòu)。對(duì)于安卓靜態(tài)分析,目前一些研究工具利用不同類(lèi)型的圖來(lái)描繪程序的特征,如控制流圖、數(shù)據(jù)流圖等[3-4]。為了獲取安卓應(yīng)用程序的源碼或字節(jié)碼,需要對(duì)APK安裝包反編譯,常用的反編譯工具有Dexpler[5]、Smail[6]和AndroGuard[7]。本文方法也依賴(lài)于安卓靜態(tài)分析技術(shù),在安卓應(yīng)用程序的源碼層面上利用抽象語(yǔ)法樹(shù)分析結(jié)果來(lái)進(jìn)一步描繪程序的特征。

針對(duì)代碼的相似問(wèn)題目前已有很多分析方法,如基于文本識(shí)別、基于度量值、基于代碼結(jié)構(gòu)和基于圖結(jié)構(gòu)的代碼相似分析。基于文本識(shí)別的代碼相似分析方法是將代碼表示成文本或token序列的方式,進(jìn)而采用模式匹配技術(shù)來(lái)檢測(cè)代碼間是否相似。代碼克隆[8]就是基于文本識(shí)別的方法來(lái)檢測(cè)待分析代碼中的重復(fù)部分。基于度量值的代碼相似分析方法,不直接比較程序代碼,而是提取選定的度量值信息,形成一組包含這些信息的特征向量,通過(guò)比較這些特征向量來(lái)比較代碼的相似程度[9]。衡量代碼的度量值有很多,如圈復(fù)雜度、類(lèi)耦合度和繼承深度等。基于代碼結(jié)構(gòu)的代碼相似分析方法是將待分析的代碼轉(zhuǎn)化成抽象語(yǔ)法樹(shù),進(jìn)而在語(yǔ)法樹(shù)上使用匹配或搜索技術(shù)尋找相似的子樹(shù)[10-11]。基于圖結(jié)構(gòu)的代碼相似分析是將程序代碼表示成程序依賴(lài)圖來(lái)進(jìn)行分析[12-13]。從兩個(gè)特定的起始點(diǎn)開(kāi)始,尋找兩幅圖中的最大相似子圖。本文方法也利用了基于代碼結(jié)構(gòu)相似的分析方法,將安卓應(yīng)用程序代碼構(gòu)造成抽象語(yǔ)法樹(shù),進(jìn)而在抽象語(yǔ)法樹(shù)的基礎(chǔ)上利用樹(shù)匹配算法進(jìn)行相似分析。

代碼遷移目前主要分為API遷移和Library庫(kù)的遷移。對(duì)于API的遷移,可以通過(guò)比較兩個(gè)版本API在庫(kù)中的聲明變化以及兩個(gè)版本API在代碼中的使用方式來(lái)進(jìn)行遷移[14]。對(duì)于Library庫(kù)的遷移,通過(guò)對(duì)大量開(kāi)源軟件項(xiàng)目的分析來(lái)識(shí)別相似庫(kù)之間的遷移變化,進(jìn)而根據(jù)大量的分析數(shù)據(jù)來(lái)為L(zhǎng)ibrary庫(kù)的遷移提供建議[2]。與上述工作不同,本文方法關(guān)注控件支持庫(kù)層面的遷移,涉及一組代碼語(yǔ)句與控制結(jié)構(gòu),其中的核心要素是識(shí)別目標(biāo)代碼與安卓支持庫(kù)中特定控件在功能和結(jié)構(gòu)上的相似性。

2 動(dòng)機(jī)案例

圖1為開(kāi)發(fā)者使用基礎(chǔ)回調(diào)方法onTouch實(shí)現(xiàn)的下拉刷新功能:當(dāng)手指下拉并松開(kāi)后,在屏幕上發(fā)送一條通知。該代碼在基礎(chǔ)回調(diào)方法的UP分支下實(shí)現(xiàn)發(fā)送通知的業(yè)務(wù)邏輯。

圖1 下拉刷新案例功能代碼

圖2為該應(yīng)用程序相應(yīng)的資源文件,其中子視圖由兩個(gè)文本框TextView構(gòu)成,這兩個(gè)文本框在LinearLayout布局的內(nèi)部。

圖2 下拉刷新案例資源文件

圖1的功能代碼和圖2的資源文件都可以用安卓支持庫(kù)中已經(jīng)封裝好的控件進(jìn)行替換。當(dāng)安卓應(yīng)用軟件開(kāi)發(fā)者需要用安卓支持庫(kù)中已有的控件進(jìn)行替換時(shí),先要判斷是否能夠替換以及用什么控件進(jìn)行替換,然后還要分別從功能代碼和資源文件兩塊進(jìn)行替換。

對(duì)于開(kāi)發(fā)者來(lái)說(shuō)這將會(huì)面臨很多困難。首先許多安卓開(kāi)發(fā)者對(duì)安卓支持庫(kù)下提供的功能并不了解,因此將已有代碼替換成支持庫(kù)需要一定的學(xué)習(xí)代價(jià)。雖然擁有了一定的安卓支持庫(kù)的儲(chǔ)備知識(shí),但沒(méi)有相應(yīng)的技術(shù)提醒開(kāi)發(fā)者該應(yīng)用程序中的某些功能能夠用安卓支持庫(kù)中的控件進(jìn)行替換。此外,一些開(kāi)發(fā)者知道該項(xiàng)目的有些功能可以使用支持庫(kù)的控件進(jìn)行替換,但是他們不知道如何在項(xiàng)目中進(jìn)行替換。

當(dāng)開(kāi)發(fā)者使用基于本文方法所開(kāi)發(fā)的工具時(shí),就可以根據(jù)工具生成的建議快速地在項(xiàng)目中進(jìn)行支持庫(kù)的替換。該工具將會(huì)從功能實(shí)現(xiàn)代碼、監(jiān)聽(tīng)器的綁定和布局文件這三個(gè)方面給出替換建議。

圖3為根據(jù)替換建議用SwipeRefreshLayout這個(gè)支持庫(kù)控件進(jìn)行替換后的功能代碼。該代碼中,遷移的代碼被放置在SwipeRefreshLayout的onRefresh回調(diào)方法中,同時(shí)為SwipeRefreshLayout綁定OnRefresh-Listener監(jiān)聽(tīng)器,用來(lái)監(jiān)聽(tīng)事件。

圖3 用支持庫(kù)控件替換后的功能代碼

資源文件的替換如圖4所示。根據(jù)替換建議,使用SwipeRefreshLayout控件節(jié)點(diǎn)來(lái)替換原先的LinearLayout節(jié)點(diǎn)。

圖4 用支持庫(kù)替換后的資源文件

3 支持庫(kù)代碼特征模型及其構(gòu)造

3.1 安卓事件回調(diào)方法的代碼特征元模型

圖5所示的元模型用來(lái)描繪安卓事件回調(diào)方法的代碼特征信息。該元模型既可以表示支持庫(kù)中的回調(diào)方法,又可以用來(lái)描述目標(biāo)替換代碼的方法代碼結(jié)構(gòu)。

圖5 安卓事件回調(diào)方法的代碼特征元模型

Widget表示安卓支持庫(kù)中的一個(gè)觸摸控件,在該元模型中,控件包含了一組監(jiān)聽(tīng)器。每一個(gè)監(jiān)聽(tīng)器負(fù)責(zé)監(jiān)聽(tīng)一個(gè)或多個(gè)事件并觸發(fā)相應(yīng)的回調(diào)方法(Callback)。我們使用一棵特征樹(shù)(FeatureTree)來(lái)表示Callback的具體代碼及其應(yīng)用邏輯,并以FeatureTreeRoot來(lái)表示該特征樹(shù)的根節(jié)點(diǎn)。根節(jié)點(diǎn)一般命名為基礎(chǔ)回調(diào)的方法名,例如onTouch、onTouchEvent等。

特征樹(shù)是由一系列表示代碼元素的節(jié)點(diǎn)構(gòu)成,即CodeElement。節(jié)點(diǎn)之間存在Order信息與Include關(guān)系。Order關(guān)系表示同層次代碼元素與同層次代碼元素之間的次序關(guān)系,Include關(guān)系表示外部代碼元素與內(nèi)部代碼元素之間的包含關(guān)系。另外,每一個(gè)節(jié)點(diǎn)包含KeyWordSet屬性,用以代表代碼元素中的關(guān)鍵字集合。該集合可包括方法名以及部分靜態(tài)常量名。這些關(guān)鍵字從SDK中提取得來(lái),用以反映代碼的實(shí)現(xiàn)功能。

元模型中列舉了三種特定類(lèi)型的代碼元素,即代碼控制結(jié)構(gòu)(ControlStructure)、代碼語(yǔ)句(Statement)和插樁點(diǎn)(Instrumentation)。

ControlStructure用來(lái)描述代碼的骨架結(jié)構(gòu),表示程序執(zhí)行的動(dòng)作順序。本文將控制結(jié)構(gòu)分成兩類(lèi),循環(huán)結(jié)構(gòu)(Loop)和分支結(jié)構(gòu)(Branch)。循環(huán)結(jié)構(gòu)包括For、While、Do等,分支結(jié)構(gòu)包括If、Switch等。

Statement用來(lái)記錄代碼結(jié)構(gòu)中的基本語(yǔ)句信息,例如方法調(diào)用信息,Statement就記錄了該方法調(diào)用是在代碼控制結(jié)構(gòu)中的哪個(gè)分支下進(jìn)行調(diào)用的。

Instrumentation記錄控件回調(diào)方法在代碼中的哪個(gè)位置被間接觸發(fā)。例如SwipeRefreshLayout控件中的onRefresh回調(diào)方法是在onTouchEvent這個(gè)基礎(chǔ)回調(diào)方法中的UP分支下被間接觸發(fā)的。在進(jìn)行代碼替換時(shí),用戶實(shí)現(xiàn)業(yè)務(wù)功能的代碼就放在該插樁點(diǎn)所記錄的回調(diào)方法的內(nèi)部。

3.2 目標(biāo)代碼特征模型的構(gòu)造方法

算法1是目標(biāo)代碼特征模型的構(gòu)造方法。該算法的輸入是一個(gè)Callback方法,對(duì)Callback方法中的每一個(gè)結(jié)構(gòu)塊進(jìn)行迭代分析。算法的輸出是FeatureTree,即一個(gè)以樹(shù)狀結(jié)構(gòu)表示回調(diào)方法的特征模型。

算法1目標(biāo)代碼特征模型的構(gòu)造方法

Function: BuildFeatureTree

輸入: Callback。

輸出: FeatureTree。

begin

For each ControlBlock in Callback

begin

CNode=CreateNode(Loop/Branch)

CreateOrder(PreCNode, CNode)

SNode=CreateNode(Condition)

AddIncludeNode(CNode, SNode)

BNode=CreateNode(Statement)

AddIncludeNode(SNode, BNode)

PreCNode=CNode

end

return FeatureTree

end

在迭代過(guò)程中,對(duì)于每一個(gè)結(jié)構(gòu)塊,創(chuàng)建一個(gè)ControlStructure類(lèi)型的節(jié)點(diǎn),節(jié)點(diǎn)記錄該控制結(jié)構(gòu)的類(lèi)型是Loop還是Branch,并將此控制結(jié)構(gòu)節(jié)點(diǎn)與父控制結(jié)構(gòu)節(jié)點(diǎn)關(guān)聯(lián)起來(lái)。為了記錄控制結(jié)構(gòu)之間的Order關(guān)系,在關(guān)聯(lián)兩個(gè)控制結(jié)構(gòu)節(jié)點(diǎn)時(shí)以O(shè)rder屬性的邊來(lái)連接這兩個(gè)節(jié)點(diǎn)。控制結(jié)構(gòu)中的條件信息,用Statement類(lèi)型的節(jié)點(diǎn)來(lái)保存,并將該節(jié)點(diǎn)以Include關(guān)系關(guān)聯(lián)到所屬的控制結(jié)構(gòu)節(jié)點(diǎn)上。對(duì)于某一個(gè)條件下的代碼語(yǔ)句,仍然用Statement類(lèi)型節(jié)點(diǎn)來(lái)保存,并將該節(jié)點(diǎn)以Include關(guān)系關(guān)聯(lián)到所對(duì)應(yīng)的分支條件節(jié)點(diǎn)上。如果該控制結(jié)構(gòu)是分支結(jié)構(gòu),則需要對(duì)分支結(jié)構(gòu)下的每一個(gè)分支條件進(jìn)行分析。

3.3 支持庫(kù)控件的特征模型構(gòu)建

首先需要為支持庫(kù)每一個(gè)觸摸控件中每一個(gè)監(jiān)聽(tīng)器下的每一個(gè)回調(diào)方法構(gòu)造特征模型。為了獲取支持庫(kù)控件中的回調(diào)方法,可以通過(guò)參閱文檔或檢索支持庫(kù)中具有Listener的類(lèi)來(lái)找到相應(yīng)的回調(diào)方法。為了找到觸發(fā)回調(diào)方法的調(diào)用語(yǔ)句,需要對(duì)回調(diào)方法進(jìn)行回溯,由于回調(diào)方法有時(shí)候并不能在某一個(gè)方法中找到對(duì)其的調(diào)用,因此回溯過(guò)程將分為以下兩種情形:

(1) 如果在某一個(gè)方法中找到觸發(fā)該回調(diào)方法的調(diào)用語(yǔ)句,則以該方法繼續(xù)向上回溯。

(2) 如果沒(méi)有找到觸發(fā)該回調(diào)方法的調(diào)用語(yǔ)句,則利用事先對(duì)安卓?jī)?nèi)部回調(diào)方法的總結(jié),找到觸發(fā)該回調(diào)方法的方法,然后以該方法繼續(xù)向上回溯。

算法2描述了回調(diào)函數(shù)調(diào)用鏈的回溯過(guò)程,該算法的輸入是一個(gè)支持庫(kù)控件中的回調(diào)方法,輸出是控件中的基礎(chǔ)回調(diào)方法。通過(guò)算法2,可以將控件中以回調(diào)方法為終點(diǎn),以基礎(chǔ)回調(diào)方法為起點(diǎn)的方法調(diào)用鏈構(gòu)建完成。接著采用算法1,對(duì)基礎(chǔ)回調(diào)方法進(jìn)行特征模型樹(shù)的構(gòu)造。此時(shí)的特征模型樹(shù)需要加上插樁類(lèi)型節(jié)點(diǎn),該節(jié)點(diǎn)存儲(chǔ)了控件中的某個(gè)回調(diào)方法,并且將該節(jié)點(diǎn)連接到基礎(chǔ)回調(diào)方法對(duì)應(yīng)的代碼塊下。

算法2回調(diào)函數(shù)調(diào)用鏈的回溯算法

Function: SearchBaseMethod

輸入: Callback。

輸出: BaseMethod。

begin

if Callback是基礎(chǔ)回調(diào)方法 then

begin

BaseMethod=Caller

return BaseMethod

end

if 找到該回調(diào)方法的Caller then

begin

SearchBaseMethod(Caller)

end

else then

begin

通過(guò)整理的回調(diào)方法總結(jié)中找到Caller

SearchBaseMethod(Caller)

end

end

圖6給出了一個(gè)控件特征模型的例子。onTouchEvent是SwipeRefreshLayout控件內(nèi)部的一個(gè)基礎(chǔ)回調(diào)函數(shù)。

圖6 特征模型樹(shù)示例

可以看出,其內(nèi)部是一個(gè)分支類(lèi)型的控制結(jié)構(gòu),用ControlStructure類(lèi)型的節(jié)點(diǎn)來(lái)表示,節(jié)點(diǎn)存儲(chǔ)了該控制結(jié)構(gòu)類(lèi)型為Branch類(lèi)型。該結(jié)構(gòu)有三個(gè)分支,分別用三個(gè)Statement類(lèi)型的節(jié)點(diǎn)保存分支條件的信息。每一個(gè)分支條件下用Statement類(lèi)型節(jié)點(diǎn)保存該分支下的代碼語(yǔ)句片段信息。由于UP分支下間接調(diào)用了onRefresh這個(gè)回調(diào)方法,因此用一個(gè)插樁類(lèi)型的節(jié)點(diǎn)來(lái)存儲(chǔ)該回調(diào)方法信息。

4 目標(biāo)應(yīng)用的支持庫(kù)控件替換

4.1 代碼替換技術(shù)的方法流程

代碼替換技術(shù)的方法流程如圖7所示,該方法流程主要分成兩個(gè)階段,第一階段是安卓支持庫(kù)特征模型的準(zhǔn)備,第二階段是基于第一階段支持庫(kù)特征模型的代碼替換技術(shù)。

圖7 代碼替換技術(shù)的方法流程

安卓支持庫(kù)特征模型的準(zhǔn)備分成兩個(gè)部分:一是回調(diào)方法調(diào)用鏈的構(gòu)建,二是回調(diào)方法特征模型的構(gòu)建。回調(diào)方法調(diào)用鏈的構(gòu)建是對(duì)于安卓支持庫(kù)控件中的每一個(gè)回調(diào)方法,找到該方法是在哪個(gè)基礎(chǔ)回調(diào)方法中被觸發(fā)的。回調(diào)方法特征模型的構(gòu)建是對(duì)控件中的每一個(gè)回調(diào)方法構(gòu)建特征模型樹(shù)。

支持庫(kù)特征模型的代碼替換分成三個(gè)部分,分別是基于支持庫(kù)特征模型的待替換代碼的定位、匹配和替換。首先需要對(duì)待分析的安卓應(yīng)用進(jìn)行掃描,對(duì)應(yīng)用中每一個(gè)Activity中的每一個(gè)回調(diào)方法進(jìn)行定位。如果該回調(diào)方法名與支持庫(kù)特征模型中的某個(gè)基礎(chǔ)回調(diào)方法名一致,則該回調(diào)方法是一個(gè)潛在待替換代碼。如果方法名不一致,則繼續(xù)定位應(yīng)用中的下一個(gè)回調(diào)方法。對(duì)于定位到的一個(gè)潛在待替換代碼,采用樹(shù)匹配的算法將潛在待替換代碼特征模型樹(shù)與控件中相對(duì)應(yīng)的特征模型樹(shù)進(jìn)行匹配,根據(jù)匹配結(jié)果判斷能否進(jìn)行替換。當(dāng)可以替換時(shí),生成相應(yīng)的替換建議。

4.2 基于支持庫(kù)特征模型的代碼匹配

為了對(duì)目標(biāo)代碼特征模型樹(shù)和安卓支持庫(kù)控件的特征模型樹(shù)進(jìn)行匹配比較,本文采用一種樹(shù)匹配算法(TM)來(lái)尋找兩棵特征模型樹(shù)間的最大匹配。S(SA,S1,S2,…,Si)和T(TB、T1,T2,…,Tj)分別是目標(biāo)代碼特征模型樹(shù)和安卓支持庫(kù)控件特征模型樹(shù)。其中:Si為樹(shù)S的第一層子樹(shù)的第i個(gè)節(jié)點(diǎn);Tj為樹(shù)T的第一層子樹(shù)的第j個(gè)節(jié)點(diǎn);SA和SB分別為樹(shù)的根節(jié)點(diǎn)。M為兩個(gè)特征模型樹(shù)的匹配,最大匹配M就是擁有最多節(jié)點(diǎn)對(duì)間的匹配,其最大匹配節(jié)點(diǎn)個(gè)數(shù)為M+1,加1是因?yàn)楦?jié)點(diǎn)也是匹配的節(jié)點(diǎn)對(duì)。為了求出M()的最大匹配,采用動(dòng)態(tài)規(guī)劃的思想,有以下幾種情形:

1) 當(dāng)兩個(gè)子樹(shù)中有一個(gè)為空是,匹配數(shù)M為0。

2) 當(dāng)兩個(gè)子樹(shù)都不為空時(shí),可分為以下幾個(gè)情形:

(1) 匹配Si和Tj,這時(shí)M()變?yōu)镸()+W(Si、Tj);

(2) 匹配Si,這時(shí)M()變?yōu)镸();

(3) 匹配Tj,這時(shí)M()變?yōu)镸()。

最后根據(jù)樹(shù)匹配算法的結(jié)果,計(jì)算出兩個(gè)特征模型之間的相似度:

式中:Node(S)和Node(T)分別表示樹(shù)S和樹(shù)T節(jié)點(diǎn)的個(gè)數(shù);TM(S,T)表示通過(guò)樹(shù)匹配算法計(jì)算后返回的兩棵樹(shù)間的最大匹配的節(jié)點(diǎn)個(gè)數(shù)。

圖8所示為兩個(gè)特征模型樹(shù)S和T,節(jié)點(diǎn)中的標(biāo)號(hào)表示該節(jié)點(diǎn)的類(lèi)型,具有相同標(biāo)號(hào)的節(jié)點(diǎn)看成是相同節(jié)點(diǎn)。利用TM算法可以求出S和T之間的最大匹配為9,因此它們之間的相似度為0.9。

圖8 兩棵特征模型樹(shù)

因此兩棵特征模型樹(shù)的最大匹配節(jié)點(diǎn)個(gè)數(shù)越多,則兩棵樹(shù)的相似度就越大,也就越相似。對(duì)于本文的場(chǎng)景,需要在目標(biāo)代碼的特征模型樹(shù)中匹配到一棵子樹(shù),該子樹(shù)即控件基礎(chǔ)回調(diào)方法的特征模型樹(shù)。所以最大匹配樹(shù)TM(S,T)滿足以下關(guān)系時(shí),目標(biāo)代碼可以用安卓支持庫(kù)里的控件進(jìn)行替換:

TM(S,T)=Node(T)

式中:T表示的是安卓支持庫(kù)控件代碼的特征模型樹(shù);S表示的是目標(biāo)代碼的特征模型樹(shù);Node(T)表示樹(shù)T節(jié)點(diǎn)的個(gè)數(shù);TM(S,T)表示通過(guò)樹(shù)匹配算法計(jì)算后返回的兩棵樹(shù)間的最大匹配的節(jié)點(diǎn)個(gè)數(shù)。

4.3 基于支持庫(kù)特征模型的替換

1) 功能實(shí)現(xiàn)代碼和監(jiān)聽(tīng)器的替換。算法3描述了功能實(shí)現(xiàn)代碼和監(jiān)聽(tīng)器的替換方法。該算法的輸入是兩個(gè)特征模型樹(shù),分別是目標(biāo)代碼的特征模型樹(shù)CallbackFeatureTree和能夠用來(lái)替換該目標(biāo)代碼的支持庫(kù)控件中的基礎(chǔ)回調(diào)方法的特征模型樹(shù)BaseMethodFeatureTree。該算法用CodeSegmentMap來(lái)保存能夠被遷移的代碼片段,用NotReplaceSet來(lái)保存未被遷移的代碼片段。

算法3功能實(shí)現(xiàn)代碼和監(jiān)聽(tīng)器的替換算法

Function: CallbackReplace

輸入: CallbackFeatureTree, BaseMethodFeatureTree。

輸出: CodeSegmentMap, NotReplaceCodeSet。

begin

for each Statement in CallbackFeatureTree

begin

if Statement 對(duì)應(yīng)到BaseMethodFeatureTree中的一個(gè)插樁點(diǎn) then

begin

for each widget in WidgetSet

begin

for each FeatureTreeRoot in widget

begin

if FeatureTreeRoot==BaseMethodFeatureTree.root then

begin

find Listener where Listener.contain(FeatureTreeRoot)

CodeSegmentMap.put(控件+監(jiān)聽(tīng)器+插樁點(diǎn), Statement)

end

end

end

end

if Statement 對(duì)應(yīng)不到BaseMethodFeatureTree中的一個(gè)節(jié)點(diǎn) then

begin

NotRepalceCodeSet.put(Statement)

end

end

return CodeSegmentMap, NotReplaceCodeSet

end

在算法3中,以CallbackFeatureTree為基準(zhǔn),遍歷該特征模型樹(shù)上的Statement類(lèi)型節(jié)點(diǎn),如果該節(jié)點(diǎn)直接對(duì)應(yīng)到BaseMethodFeatureTree中的一個(gè)非插樁節(jié)點(diǎn),那么說(shuō)明新控件已經(jīng)包含這些語(yǔ)句。如果對(duì)應(yīng)的是一個(gè)插樁類(lèi)型的節(jié)點(diǎn),說(shuō)明該代碼語(yǔ)句是可以進(jìn)行遷移的。如果沒(méi)有對(duì)應(yīng)到任何一個(gè)節(jié)點(diǎn),則將該代碼語(yǔ)句記錄到NotReplaceCodeSet中,該代碼語(yǔ)句無(wú)法被遷移。對(duì)于監(jiān)聽(tīng)器的搜索,首先找到BaseMethodFeatureTree是在哪個(gè)widget下的,然后在該Widget下找到哪一個(gè)listener的孩子節(jié)點(diǎn)中有一個(gè)孩子節(jié)點(diǎn)是該BaseMethod的,則該listener就是需要用來(lái)替換的監(jiān)聽(tīng)器。最后以插樁點(diǎn)、監(jiān)聽(tīng)器和該控件作為key鍵,Statement作為值,記錄到CodeSegmentMap中。

2) layout資源文件的替換。layout資源文件的替換分成兩步:第一步需要找到待替換的控件是什么;第二步需要找到資源文件是哪一個(gè)。在Callback所處的Activity中,可以找到該回調(diào)的監(jiān)聽(tīng)器,然后向上回溯找到是哪一個(gè)對(duì)象set了這個(gè)監(jiān)聽(tīng)器,則該對(duì)象就是需要找的待替換控件。一個(gè)Activity的資源文件是在該Activity中的onCreate方法內(nèi)部的setContentView方法中被加載的,該方法中的參數(shù)就是layout資源文件的名字。例如方法參數(shù)是R.layout.activity_main,則需要的資源文件名稱(chēng)就是activity_main.xml。

接著需要在該資源文件中搜索到用戶控件的節(jié)點(diǎn),當(dāng)找到該節(jié)點(diǎn)后,將該節(jié)點(diǎn)用支持庫(kù)控件進(jìn)行替換。算法4描述了節(jié)點(diǎn)搜索的方法。

算法4搜索節(jié)點(diǎn)的算法

Function: depthSearch

輸入: root//xml文件的根節(jié)點(diǎn)。

輸出: child//待替換的控件節(jié)點(diǎn)。

begin

nodeStack.add(root)

while(!node.isEmpty)

begin

node=nodeStack.pop()

list=node.getChildren()

for child ∈ list

begin

nodeStack.add(child)

if child.name==layout.name then

begin

return child

end

end

end

end

算法4的實(shí)質(zhì)是樹(shù)的深度優(yōu)先搜索算法,由于Activity是由一組ViewGroup組成,所以從根節(jié)點(diǎn)出發(fā),依次遍歷每一組ViewGroup。對(duì)于每一組ViewGroup,依次搜索其每一個(gè)孩子節(jié)點(diǎn)分支,然后再以該孩子節(jié)點(diǎn)為起點(diǎn),照此方法直到搜索到某一分支的葉子節(jié)點(diǎn)時(shí)返回上一層繼續(xù)搜索。當(dāng)搜索到節(jié)點(diǎn)的名字屬性與待替換控件的名字屬性一致時(shí)就停止搜索,那么該位置的節(jié)點(diǎn)就是需要用新的控件去替換的位置。

4.4 替換建議的生成

本文給用戶提供的生成建議包含以下幾個(gè)部分:

1) 對(duì)于安卓應(yīng)用中可以進(jìn)行遷移的代碼,需要將支持庫(kù)控件、監(jiān)聽(tīng)器、回調(diào)方法、可遷移代碼組合成完整的代碼片段。為了方便用戶的理解,該建議還增加了一些文字描述,將這些描述與組合后的代碼片段作為完整的可遷移代碼的替換建議。圖9給出了可遷移代碼建議的模板。

圖9 可遷移代碼的建議模板

在替換建議中,圖9模板先給出了替換前的代碼,并用文字指明了該代碼片段位于哪個(gè)Activity的哪個(gè)基礎(chǔ)回調(diào)方法,然后給出了遷移后的代碼示例,也用文字介紹了使用安卓支持庫(kù)中的哪個(gè)控件進(jìn)行替換,以及綁定的監(jiān)聽(tīng)器和回調(diào)方法的信息。

2) 對(duì)于安卓應(yīng)用中未被遷移的代碼,本文同樣將未被遷移代碼和一些文字描述作為替換建議展示給用戶。圖10給出了未被遷移代碼建議的模板,其既給出了未被遷移的代碼片段,又給出了該代碼片段是位于該應(yīng)用中的哪個(gè)Activity里的哪個(gè)基礎(chǔ)回調(diào)方法下的。

圖10 未被遷移代碼的建議模板

3) 對(duì)于資源文件的替換,本文依舊給出原資源文件和替換后的資源文件,同時(shí)也通過(guò)文字描述進(jìn)行解釋?zhuān)奖阌脩舻亩ㄎ缓吞鎿Q。圖11給出了資源文件替換建議的模板,文字描述告訴用戶資源文件的名稱(chēng),以及是用支持庫(kù)中的哪個(gè)控件進(jìn)行替換。

圖11 資源文件替換的建議模板

5 實(shí)驗(yàn)分析

圖12為基于本文方法所設(shè)計(jì)的工具界面,該工具的界面分成上下兩個(gè)部分。上半部分是用戶的輸入部分,用戶需要提供待分析的安卓項(xiàng)目的地址。下半部分是替換建議生成部分,分別從可遷移代碼、資源文件替換和未被遷移代碼三個(gè)方面給出替換建議。界面中的三個(gè)文本框分別用來(lái)展示這三個(gè)方面的替換信息。

圖12 工具界面

本文主要通過(guò)兩組實(shí)驗(yàn)來(lái)對(duì)本文方法在實(shí)際開(kāi)發(fā)中的實(shí)用性進(jìn)行分析,這兩組實(shí)驗(yàn)分別是針對(duì)用戶開(kāi)發(fā)應(yīng)用的支持庫(kù)替換實(shí)驗(yàn)和針對(duì)開(kāi)源應(yīng)用的支持庫(kù)替換實(shí)驗(yàn)。

1) 針對(duì)用戶開(kāi)發(fā)應(yīng)用的支持庫(kù)替換實(shí)驗(yàn)。本實(shí)驗(yàn)邀請(qǐng)了三位具有初級(jí)安卓開(kāi)發(fā)經(jīng)驗(yàn)的同學(xué),讓這三位同學(xué)基于基礎(chǔ)回調(diào)方法實(shí)現(xiàn)例如下拉操作、側(cè)滑操作等功能的安卓應(yīng)用程序。表1列舉了給這三位同學(xué)安排的開(kāi)發(fā)任務(wù)和提供的開(kāi)發(fā)建議。

表1 實(shí)驗(yàn)的開(kāi)發(fā)任務(wù)與開(kāi)發(fā)建議

當(dāng)三位同學(xué)完成應(yīng)用開(kāi)發(fā)后,利用本文方法對(duì)這三個(gè)應(yīng)用進(jìn)行替換分析。最終的分析結(jié)果如表2所示。

表2 實(shí)驗(yàn)結(jié)果

其中有兩個(gè)應(yīng)用有替換建議,有一個(gè)應(yīng)用沒(méi)有替換建議。本節(jié)將選取實(shí)驗(yàn)1和實(shí)驗(yàn)3,即一個(gè)有替換建議的例子和一個(gè)沒(méi)有替換建議的例子來(lái)對(duì)該實(shí)驗(yàn)進(jìn)行分析。

(1) 有替換建議的例子分析。該例子用onTouchEvent這個(gè)基礎(chǔ)回調(diào)方法實(shí)現(xiàn)下拉刷新的功能。圖13是該功能實(shí)現(xiàn)代碼的片段。該例子在onTouchEvent的Up分支下寫(xiě)了一段更新子視圖的邏輯,該邏輯是當(dāng)手指下拉松開(kāi)后,在子視圖的ListView中添加一行List。

圖13 功能實(shí)現(xiàn)代碼片段

通過(guò)本文方法分析后,安卓支持庫(kù)里的下拉刷新控件SwipeRefreshLayout可以對(duì)例子中用基礎(chǔ)回調(diào)方法onTouchEvent實(shí)現(xiàn)的下拉刷新代碼進(jìn)行替換。圖14是可遷移代碼的替換建議,可待遷移代碼放置在SwipeRefreshLayout的onRefresh回調(diào)方法中,該回調(diào)方法是在手指下拉手松后被間接觸發(fā)的。同時(shí)為Swipe-RefreshLayout綁定一個(gè)setOnRefreshListener監(jiān)聽(tīng)器,用來(lái)監(jiān)聽(tīng)事件。

圖14 可遷移代碼的替換建議

該例子的資源文件如圖15中替換前的代碼所示,該資源文件有兩個(gè)視圖,分別是子視圖ListView和父視圖LinearLayout,子視圖ListView在父視圖LinearLayout的內(nèi)部。對(duì)于替換后的資源文件如圖15中替換后的代碼所示, ListView這個(gè)子視圖在SwipeRefreshLayout控件節(jié)點(diǎn)的內(nèi)部。

圖15 資源文件的替換建議

(2) 無(wú)替換建議的例子分析。該例子沒(méi)有替換建議是因?yàn)樵摾訉⑾吕⑿碌倪壿嬘靡粋€(gè)類(lèi)封裝好,所以在Activity中只保留了更新子視圖的邏輯,對(duì)于下拉刷新的邏輯則在那個(gè)類(lèi)中進(jìn)行實(shí)現(xiàn)。圖16展示了Activity中處理業(yè)務(wù)邏輯的代碼片段。PullRefreshLayout是封裝好的類(lèi),在Activity中直接創(chuàng)建該類(lèi)的一個(gè)對(duì)象,然后綁定相應(yīng)的監(jiān)聽(tīng)器來(lái)監(jiān)聽(tīng)動(dòng)作,在該例子中使用的是setRefreshListener。

圖16 無(wú)替換建議的實(shí)現(xiàn)代碼

2) 針對(duì)開(kāi)源應(yīng)用的支持庫(kù)替換實(shí)驗(yàn)。本部分實(shí)驗(yàn)從開(kāi)源社區(qū)上找了五個(gè)與安卓支持庫(kù)觸摸控件功能相似的開(kāi)源安卓應(yīng)用項(xiàng)目,然后利用本文的方法對(duì)這五個(gè)安卓應(yīng)用項(xiàng)目進(jìn)行替換分析。本實(shí)驗(yàn)所選取的開(kāi)源應(yīng)用的來(lái)源信息如表3所示,最終分析結(jié)果如表4所示。

表3 開(kāi)源項(xiàng)目來(lái)源

表4 開(kāi)源項(xiàng)目實(shí)驗(yàn)結(jié)果

可以看出,這五個(gè)案例中有2個(gè)案例有替換建議輸出,有3個(gè)案例沒(méi)有替換建議輸出。其中能夠進(jìn)行替換的項(xiàng)目均包含與支持庫(kù)控件相應(yīng)的,且用基本觸控邏輯來(lái)實(shí)現(xiàn)的事件回調(diào)方法。相對(duì)地,在三個(gè)沒(méi)有替換建議輸出的應(yīng)用中,有一個(gè)是使用了封裝好的功能類(lèi)來(lái)實(shí)現(xiàn)對(duì)應(yīng)的功能,有兩個(gè)是直接使用了安卓支持庫(kù)中的控件。對(duì)于將功能封裝成一個(gè)類(lèi)的情形,本文給出的方法同樣也可以進(jìn)行分析替換,但這樣做的意義不大。由于用戶已經(jīng)將一個(gè)功能封裝好了,那就沒(méi)有必要再去用安卓支持庫(kù)里的控件進(jìn)行替換,因此本文設(shè)計(jì)的方法對(duì)封裝好的功能類(lèi)是不進(jìn)行分析的。

6 結(jié) 語(yǔ)

本文提出了一種面向安卓觸控類(lèi)支持庫(kù)的應(yīng)用代碼替換技術(shù)。首先設(shè)計(jì)了一種用于描述安卓事件回調(diào)方法中代碼特征的元模型,其不僅能夠表示支持庫(kù)中的回調(diào)函數(shù),也可以用來(lái)描述目標(biāo)替換代碼中的方法代碼結(jié)構(gòu);接著基于安卓支持庫(kù)的特征模型和目標(biāo)替換代碼的特征模型進(jìn)行匹配;最后對(duì)于可以進(jìn)行替換的目標(biāo)代碼,設(shè)計(jì)了一種涵蓋功能實(shí)現(xiàn)、頁(yè)面布局的代碼替換建議生成方法。

本文方法仍然有一些不足的地方,需要在后續(xù)工作中不斷完善。第一,目前只是針對(duì)安卓觸摸類(lèi)控件進(jìn)行替換分析,對(duì)于支持庫(kù)中的其他功能目前還無(wú)法做到替換分析;第二,本文方法的實(shí)現(xiàn)與用戶交互的功能還不夠完善,后續(xù)將對(duì)該方法實(shí)現(xiàn)進(jìn)行擴(kuò)展,增加與用戶交互的功能。

猜你喜歡
特征功能方法
也談詩(shī)的“功能”
如何表達(dá)“特征”
不忠誠(chéng)的四個(gè)特征
抓住特征巧觀察
關(guān)于非首都功能疏解的幾點(diǎn)思考
用對(duì)方法才能瘦
Coco薇(2016年2期)2016-03-22 02:42:52
四大方法 教你不再“坐以待病”!
Coco薇(2015年1期)2015-08-13 02:47:34
捕魚(yú)
中西醫(yī)結(jié)合治療甲狀腺功能亢進(jìn)癥31例
辨證施護(hù)在輕度認(rèn)知功能損害中的應(yīng)用
主站蜘蛛池模板: 99青青青精品视频在线| 欧美亚洲欧美区| 国内精品91| 午夜福利无码一区二区| 亚洲乱码视频| 1024你懂的国产精品| 色婷婷综合激情视频免费看| 国产99精品视频| 中文无码精品A∨在线观看不卡| 天天色天天操综合网| 国产国产人成免费视频77777 | 亚洲成人77777| AV在线麻免费观看网站| 国产精品蜜臀| 国产爽爽视频| 久久一色本道亚洲| 少妇高潮惨叫久久久久久| 污污网站在线观看| 国产一在线观看| 九月婷婷亚洲综合在线| 久久亚洲中文字幕精品一区| 51国产偷自视频区视频手机观看| 亚洲永久色| 欧洲极品无码一区二区三区| 国产精品久久久久久久久| 无码国内精品人妻少妇蜜桃视频| 久久综合九九亚洲一区| 97精品伊人久久大香线蕉| 亚洲欧美综合在线观看| 无码日韩人妻精品久久蜜桃| 91午夜福利在线观看精品| 国产好痛疼轻点好爽的视频| 国产欧美日韩视频怡春院| a级毛片在线免费| 色丁丁毛片在线观看| 久久天天躁狠狠躁夜夜躁| 日韩欧美亚洲国产成人综合| 欧美精品不卡| 国产亚洲精品在天天在线麻豆| 久久午夜夜伦鲁鲁片不卡| 国产小视频免费| 久视频免费精品6| 网友自拍视频精品区| 亚洲精品卡2卡3卡4卡5卡区| 美女免费精品高清毛片在线视| 狠狠亚洲婷婷综合色香| 欧美在线视频不卡第一页| 欧美成在线视频| 亚洲天堂视频在线观看免费| 少妇人妻无码首页| 人妻精品久久久无码区色视| 亚洲人成在线精品| 成人综合网址| 国产鲁鲁视频在线观看| av在线人妻熟妇| 97av视频在线观看| 久久精品这里只有国产中文精品| www.国产福利| 精品国产Ⅴ无码大片在线观看81| 成人免费午间影院在线观看| 国产欧美性爱网| 欧洲一区二区三区无码| a毛片在线播放| 国产成年无码AⅤ片在线| 色色中文字幕| 国产一国产一有一级毛片视频| 色综合天天操| 黄色污网站在线观看| 在线观看91精品国产剧情免费| 成人伊人色一区二区三区| 亚洲欧美激情小说另类| 高清无码手机在线观看| 亚洲首页在线观看| 久久网欧美| 特级欧美视频aaaaaa| 91九色最新地址| 国产高颜值露脸在线观看| 欧美日韩一区二区在线免费观看| 呦女亚洲一区精品| 精品国产电影久久九九| 日本精品一在线观看视频| 欧美第九页|