久久福利_99r_国产日韩在线视频_直接看av的网站_中文欧美日韩_久久一

您的位置:首頁(yè)技術(shù)文章
文章詳情頁(yè)

我的 Android 開(kāi)發(fā)實(shí)戰(zhàn)經(jīng)驗(yàn)總結(jié)

瀏覽:80日期:2022-09-27 10:58:09

以前一直想寫(xiě)一篇總結(jié) Android 開(kāi)發(fā)經(jīng)驗(yàn)的文章,估計(jì)當(dāng)時(shí)的我還達(dá)不到某種水平,所以思路跟不上,下筆又捉襟見(jiàn)肘。近日,思路較為明朗,于是重新操起鍵盤(pán)開(kāi)始碼字一番。先聲明一下哈,本人不是大廠的程序猿。去年畢業(yè)前,就一直在當(dāng)前創(chuàng)業(yè)小團(tuán)隊(duì)從事自己熱愛(ài)的打碼事業(yè)至今。下面總結(jié)是建立在我當(dāng)前的技術(shù)水平和認(rèn)知上寫(xiě)的,如有不同看法歡迎留下評(píng)論互相交流。

1.理解抽象,封裝變化

目前 Android 平臺(tái)上絕大部分開(kāi)發(fā)都是用著 Java ,而跟 Java 這樣一門(mén)面向?qū)ο蟮恼Z(yǔ)言打交道,不免要觸碰到 抽象 和 封裝 的概念。我身邊接觸過(guò)的一些開(kāi)發(fā)者,有一部分還對(duì)這些概念停留在寫(xiě)一個(gè)抽象類、接口、或者一個(gè)方法(或抽象方法)。至于為什么,我不大清楚是他們表達(dá)不出來(lái),還是不理解。下面我也不高談闊論,直接舉例子來(lái)解釋我所理解的抽象。

//Activity 間使用 Intent 傳遞數(shù)據(jù)的兩種寫(xiě)法 下面均是偽代碼形式,請(qǐng)忽略一些細(xì)節(jié)//寫(xiě)法一//SrcActivity 傳遞數(shù)據(jù)給 DestActivityIntent intent = new Intent(this,DestActivity.class);intent.putExtra("param", "clock");SrcActivity.startActivity(intent);//DestActivity 獲取 SrcActivity 傳遞過(guò)來(lái)的數(shù)據(jù)String param = getIntent.getStringExtra("param");//寫(xiě)法二//SrcActivity 傳遞數(shù)據(jù)給 DestActivityIntent intent = new Intent(this,DestActivity.class);intent.putExtra(DestActivity.EXTRA_PARAM, "clock");SrcActivity.startActivity(intent);//DestActivity 獲取 SrcActivity 傳遞過(guò)來(lái)的數(shù)據(jù)public final static String EXTRA_PARAM = "param";String param = getIntent.getStringExtra(EXTRA_PARAM);

寫(xiě)法一,存在的問(wèn)題是,如果 SrcActivity 和 DestActivity 哪個(gè)把 "param" 打錯(cuò)成 "para" 或者 "paran" ,傳遞的數(shù)據(jù)都無(wú)法成功接收到。而寫(xiě)法二則不會(huì)出現(xiàn)此類問(wèn)題,因?yàn)閮蓚€(gè) Activity 之間傳遞數(shù)據(jù)只需要知道 EXTRA_PARAM 變量即可,至于 EXTRA_PARAM 變量到底是 "param" 、 "para" 、"paran" 這一點(diǎn)并不需要關(guān)心,這就是一種對(duì)可能發(fā)生變化的地方進(jìn)行抽象封裝的體現(xiàn),它所帶來(lái)的好處就是降低手抖出錯(cuò)的概率,同時(shí)方便我們進(jìn)行修改。

基于抽象和封裝,Java 本身很多 API 在設(shè)計(jì)上就有這樣的體現(xiàn),如 Collections 中的很多排序方法:

我的 Android 開(kāi)發(fā)實(shí)戰(zhàn)經(jīng)驗(yàn)總結(jié)

Collections中的排序API

這些方法都是基于 List 這個(gè)抽象的列表接口進(jìn)行排序,至于這是一個(gè)用什么樣的數(shù)據(jù)結(jié)構(gòu)實(shí)現(xiàn) List(ArrayList 還是 LinkedList),排序方法本身并不關(guān)心。看,是不是體現(xiàn)了 JDK 的設(shè)計(jì)人員的一種抽象編程的思維,因?yàn)?List 的具體實(shí)現(xiàn)可能有千萬(wàn)種,如果每一類 List 都要寫(xiě)一套排序方法,估計(jì)要哭瞎了。

小結(jié):把容易出現(xiàn)變化的部分進(jìn)行抽象,就是對(duì)變化的一種封裝。

2.選好"車(chē)輪"

一個(gè)項(xiàng)目的開(kāi)發(fā),我們不可能一切從0做起,如果真是這樣,那同樣要哭瞎。因此,善于借用已經(jīng)做好的 "車(chē)輪" 非常重要,如:

網(wǎng)絡(luò)訪問(wèn)框架:okhttp、retrofit、android-async-http、volley圖片加載框架:Android-Universal-Image-Loader、Glide、Fresco、Picasso緩存框架:DiskLruCache、 RobospiceJson解析框架:Gson、Fastjson、Jackson事件總線:EventBus、OttoORM框架:GreenDAO、Litepal還有其他各種各樣開(kāi)源的自定義控件、動(dòng)畫(huà)等。除了以上提到的開(kāi)源框架,也包括一些不開(kāi)源的SDK數(shù)據(jù)統(tǒng)計(jì):友盟統(tǒng)計(jì),百度統(tǒng)計(jì)...奔潰搜集:騰訊bugly、bugtags...云存儲(chǔ):七牛...即使通訊:環(huán)信、融云、阿里百川...推送:小米推送、騰訊推送、百度推送...安全加固:360加固寶、愛(ài)加密...

一般情況下,我在選擇是否引入一些開(kāi)源框架主要基于以下幾個(gè)因素:

借助搜索引擎,如果網(wǎng)上有一大波資料,說(shuō)明使用的人多,出了問(wèn)題好找解決方案;當(dāng)然,如果普遍出現(xiàn)差評(píng),就可以直接Pass掉了看框架的作者或團(tuán)隊(duì),如 JakeWharton大神、Facebook團(tuán)隊(duì)等。大神和大公司出品的框架質(zhì)量相對(duì)較高,可保證后續(xù)的維護(hù)和bug修復(fù),不容易爛尾;關(guān)注開(kāi)源項(xiàng)目的 commit密度,issue的提交、回復(fù)、關(guān)閉數(shù)量,watch數(shù),start數(shù),fork數(shù)等。像那種個(gè)基本不怎么提交代碼、提issue又不怎么回復(fù)和修復(fù)的項(xiàng)目,最好就pass掉;

針對(duì)不開(kāi)源SDK的選擇,也主要基于以下幾點(diǎn)去考慮:

借助搜索引擎,查明口碑;很多第三方SDK的官網(wǎng)首頁(yè)都會(huì)告訴你,多少應(yīng)用已經(jīng)接入了此SDK,如果你看到有不少知名應(yīng)用在上面,那這個(gè)SDK可以考慮嘗試一下了。諸如,友盟官網(wǎng):

我的 Android 開(kāi)發(fā)實(shí)戰(zhàn)經(jīng)驗(yàn)總結(jié)

接入友盟的App

查看SDK使用文檔、它們的開(kāi)發(fā)者社區(qū)、聯(lián)系客服。好的SDK,使用文檔肯定會(huì)詳細(xì)指引你。出了問(wèn)題,上開(kāi)發(fā)者社區(qū)提問(wèn),他們的開(kāi)發(fā)工程師也會(huì)社區(qū)上回答。實(shí)在不行只能聯(lián)系客服,如果客服的態(tài)度都讓你不爽,那就可以考慮換別家的SDK了。

小結(jié):選好 "車(chē)輪" ,事半功倍

3.抽象依賴第三方框架

為什么要抽象依賴于第三方框架呢?這里和第1點(diǎn)是互相照應(yīng)的,就是降低我們對(duì)具體某個(gè)框架的依賴性,從而方便我們快速切換到不同的框架去。說(shuō)到這里,你可能覺(jué)得很抽象,那我直接舉一個(gè)加載圖片的例子好了。

假設(shè)你當(dāng)前為項(xiàng)目引入一個(gè)加載圖片的框架 —— Android-Universal-Image-Loader,最簡(jiǎn)單的做法就是加入相應(yīng)的依賴包后,在任何需要加載圖片的地方寫(xiě)上下面這樣的代碼段。

ImageLoader imageLoader = ImageLoader.getInstance(); // Get singleton instance// Load image, decode it to Bitmap and display Bitmap in ImageView (or any other view // which implements ImageAware interface)imageLoader.displayImage(imageUri, imageView);// Load image, decode it to Bitmap and return Bitmap to callbackimageLoader.loadImage(imageUri, new SimpleImageLoadingListener() { @Override public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {// Do whatever you want with Bitmap }});

這種做法最簡(jiǎn)單粗暴,但是帶來(lái)的問(wèn)題也最嚴(yán)重的。如果我有幾十上百個(gè)地方都這么寫(xiě),而在某一天,我聽(tīng)說(shuō)Facebook出了個(gè)神器 Fresco,想要換掉 Android-Universal-Image-Loader ,你就會(huì)發(fā)現(xiàn)你需要喪心病狂的去改動(dòng)幾十上百個(gè)地方的代碼,不僅工作量大,而且還容易出錯(cuò)。造成這樣的原因,就在于項(xiàng)目和加載圖片的框架之間形成了強(qiáng)耦合,而實(shí)際上,項(xiàng)目本身不應(yīng)該知道我具體用了哪個(gè)加載圖片的框架。

正確的方式,應(yīng)該是對(duì)框架做一個(gè)抽象的封裝,以應(yīng)對(duì)未來(lái)發(fā)生的變化,我直接舉自己的開(kāi)源項(xiàng)目 AndroidAlbum 中的一種封裝做法好了。

我的 Android 開(kāi)發(fā)實(shí)戰(zhàn)經(jīng)驗(yàn)總結(jié)

AndroidAlbum

大致代碼如下:

//1、聲明 ImageLoaderWrapper 接口,定義一些抽象的加載接口方法public interface ImageLoaderWrapper { /** * 顯示 圖片 * * @param imageView 顯示圖片的ImageView * @param imageFile 圖片文件 * @param option 顯示參數(shù)設(shè)置 */ public void displayImage(ImageView imageView, File imageFile, DisplayOption option); /** * 顯示圖片 * * @param imageView 顯示圖片的ImageView * @param imageUrl 圖片資源的URL * @param option 顯示參數(shù)設(shè)置 */ public void displayImage(ImageView imageView, String imageUrl, DisplayOption option); /** * 圖片加載參數(shù) */ public static class DisplayOption {/** * 加載中的資源id */public int loadingResId;/** * 加載失敗的資源id */public int loadErrorResId; }}// 2、將 UniversalAndroidImageLoader 封裝成繼承 ImageLoaderWrapper 接口的 UniversalAndroidImageLoader ,//這里代碼有點(diǎn)長(zhǎng),感興趣可以查看項(xiàng)目源碼中的實(shí)現(xiàn) https://github.com/D-clock/AndroidAlbum// 3、做一個(gè)ImageLoaderFactorypublic class ImageLoaderFactory { private static ImageLoaderWrapper sInstance; private ImageLoaderFactory() { } /** * 獲取圖片加載器 * * @return */ public static ImageLoaderWrapper getLoader() {if (sInstance == null) { synchronized (ImageLoaderFactory.class) {if (sInstance == null) { sInstance = new UniversalAndroidImageLoader();//<link>https://github.com/nostra13/Android-Universal-Image-Loader</link>} }}return sInstance; }}//4、在所有需要加載圖片的地方作如下的調(diào)用ImageLoaderWrapper loaderWrapper = ImageLoaderFactory.getLoader();ImageLoaderWrapper.DisplayOption displayOption = new ImageLoaderWrapper.DisplayOption();displayOption.loadingResId = R.mipmap.img_default;displayOption.loadErrorResId = R.mipmap.img_error;loaderWrapper.displayImage(imagview, url, displayOption);

這樣一來(lái),切換框架所帶來(lái)的代價(jià)就會(huì)變得很小,這就是不直接依賴于框架所帶來(lái)的好處。當(dāng)然,以上只是我比較簡(jiǎn)單的封裝,你也可以進(jìn)行更加細(xì)致的處理。

小結(jié):預(yù)留變更,不強(qiáng)耦合于第三方框架

4.從 MVC 到 MVP

說(shuō)實(shí)話,在沒(méi)接觸 MVP 的架構(gòu)之前,一直都是使用 MVC 的模式進(jìn)行開(kāi)發(fā)。而隨著項(xiàng)目越來(lái)越大,Activity或者 Fragment里面代碼越來(lái)越臃腫,看的時(shí)候想吐,改的時(shí)候想屎...這里撇開(kāi)其他各種各樣的架構(gòu)不談,只對(duì)比MVC 和 MVP 。

我的 Android 開(kāi)發(fā)實(shí)戰(zhàn)經(jīng)驗(yàn)總結(jié)

MVC

View:布局的xml文件Controller:Activity、Fragment、Dialog等Model:相關(guān)的業(yè)務(wù)操作處理數(shù)據(jù)(如對(duì)數(shù)據(jù)庫(kù)的操作、對(duì)網(wǎng)絡(luò)等的操作都應(yīng)該在Model層里)

你會(huì)發(fā)現(xiàn),如果 View 層只包含了xml文件,那我們 Android 項(xiàng)目中對(duì) View 層可做操作的程度并不大,頂多就是用include復(fù)用一下布局。而 Activity 等簡(jiǎn)直就是一個(gè)奇葩,它雖然歸屬于 Controller 層,但實(shí)際上也干著 View 層的活(View 的初始化和相關(guān)操作都是在Activity中)。就是這種既是 View 又是 Controller 的結(jié)構(gòu),違背了單一責(zé)任原則,也使得 Activity 等出現(xiàn)了上述的臃腫問(wèn)題。

我的 Android 開(kāi)發(fā)實(shí)戰(zhàn)經(jīng)驗(yàn)總結(jié)

MVP
標(biāo)簽: Android
相關(guān)文章:
主站蜘蛛池模板: 一级欧美一级日韩 | 欧产日产国产一区 | 欧美精品片 | 国产日韩欧美视频 | 最新中文字幕在线 | 欧美日韩综合视频 | a中文在线| 精品国产一区二区三区久久 | 在线涩涩 | 99精品欧美一区二区三区 | 在线免费观看毛片 | 91精品亚洲| www.久久 | 婷婷五月色综合香五月 | 亚洲成人一区二区三区 | 成年人黄色一级毛片 | 精品视频成人 | 久久精品在线 | 日本免费黄色 | 中文字幕在线观看精品视频 | 青青草在线免费视频 | 日韩视频一区二区 | 欧美国产精品一区二区 | 韩国三级午夜理伦三级三 | 久久se精品一区精品二区 | 欧美aaa大片 | 午夜天堂精品久久久久 | 九九免费观看全部免费视频 | 精品国产乱码久久久久久1区2区 | 欧美日韩在线电影 | 高清国产午夜精品久久久久久 | 亚洲在线视频 | 岛国伊人| 99精品欧美一区二区三区综合在线 | 日韩一区二区视频在线 | 亚洲 国产 另类 精品 专区 | 亚洲欧美精品久久 | 啊v在线视频 | 国产精品美女久久久久久不卡 | 91成人区 | 久久中文字幕一区 |