![Android插件化的思考——仿QQ一鍵換膚,思考比實(shí)現(xiàn)更重要_第1頁](http://file3.renrendoc.com/fileroot_temp3/2022-3/2/cedf026c-a8c1-4707-a761-e02243a2f000/cedf026c-a8c1-4707-a761-e02243a2f0001.gif)
![Android插件化的思考——仿QQ一鍵換膚,思考比實(shí)現(xiàn)更重要_第2頁](http://file3.renrendoc.com/fileroot_temp3/2022-3/2/cedf026c-a8c1-4707-a761-e02243a2f000/cedf026c-a8c1-4707-a761-e02243a2f0002.gif)
![Android插件化的思考——仿QQ一鍵換膚,思考比實(shí)現(xiàn)更重要_第3頁](http://file3.renrendoc.com/fileroot_temp3/2022-3/2/cedf026c-a8c1-4707-a761-e02243a2f000/cedf026c-a8c1-4707-a761-e02243a2f0003.gif)
![Android插件化的思考——仿QQ一鍵換膚,思考比實(shí)現(xiàn)更重要_第4頁](http://file3.renrendoc.com/fileroot_temp3/2022-3/2/cedf026c-a8c1-4707-a761-e02243a2f000/cedf026c-a8c1-4707-a761-e02243a2f0004.gif)
![Android插件化的思考——仿QQ一鍵換膚,思考比實(shí)現(xiàn)更重要_第5頁](http://file3.renrendoc.com/fileroot_temp3/2022-3/2/cedf026c-a8c1-4707-a761-e02243a2f000/cedf026c-a8c1-4707-a761-e02243a2f0005.gif)
版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
1、Android插件化的思考仿QQ一鍵換膚,思考比實(shí)現(xiàn)更重要!關(guān)于QQ的換膚,他們的實(shí)現(xiàn)思路我不是很清楚,但是你可以看一下這張換膚的截圖我們想使用哪個(gè)主題就直接下載就好了,這一實(shí)現(xiàn)的過程我們大致的可以猜想:首選是下載到本地指定文件夾,然后通過插件加載到我們的apk,最后應(yīng)用為皮膚,邏輯大致是這樣的邏輯了,那我們是不是應(yīng)該動(dòng)動(dòng)手啊動(dòng)動(dòng)腦?首選我們新建一個(gè)工程好了PlugInSample一.實(shí)現(xiàn)思路其實(shí)說起來,這個(gè)插件的實(shí)現(xiàn)思路,確實(shí)是比較的麻煩,思來想去,還是一種辦法比較靠譜,首先,我們刻意去獲取手機(jī)上所有的安裝的/未安裝的程序,過濾掉沒用的,留下我們的插件apk,我們的插件apk怎么去辨別呢?我
2、們可用通過設(shè)置sharedUserId,然后用實(shí)體類把插件名稱和包名保存下來,有了包名,就比較好說了,我們可用獲取插件的上下文,也就是createPackageContext,然后就可以做點(diǎn)壞事了,我們可以去剖析我們的R文件因?yàn)镽文件里面都是靜態(tài)的原因,我們很容易聯(lián)想到反射機(jī)制,是的,我們可以再一次過濾掉無用的信息,通過我們的PathClassLoader去加載,訪問我們的內(nèi)加載器反射到我們的圖片ID,也就是后面的那段數(shù)字,然后,嘿嘿,就可以使用了,是不是思路比較清晰了?這里要注意的就是圖片命名統(tǒng)一,這樣就比較號(hào)過來,那具體我們應(yīng)該怎么做?二.PlugIn主程序我們寫一個(gè)Spinner,每次切
3、換就直接換膚怎么樣?OK,每次換的時(shí)候就從插件APK里加載我們的圖片資源,看起來是比較順暢的邏輯,那我們具體該怎么做呢? 1.初始化 /* * 初始化View */ private void initView() /初始化控件 mSpinner = (Spinner) findViewById(R.id.mSpinner); 當(dāng)然,我這剛應(yīng)用就一個(gè)View,但是實(shí)際開發(fā)當(dāng)中可不止,所以步驟一定要明了2.獲取所有的插件 /* * 獲取手機(jī)里的插件 * * return */ private List findPlugIn() mList = new ArrayList(); /獲取相關(guān)信息 Pa
4、ckageManager mPackageManager = getPackageManager(); /獲取卸載/未安裝的安裝包信息 List mUninstallPackage = mPackageManager.getInstalledPackages(PackageManager.GET_UNINSTALLED_PACKAGES); /遍歷拿到我們的信息 for (PackageInfo info : mUninstallPackage) String pkgNmae = info.packageName; /獲取shareId,根據(jù)id判斷是否是我們的ID String shareU
5、serId = info.sharedUserId; if (!TextUtils.isEmpty(shareUserId) /如果id相同 if (shareUserId.equals(com.liuguilin.share) /且排除自己的包名 if (!pkgNmae.equals(getPackageName() /這個(gè)就是我們的插件了 String lable = mPackageManager.getApplicationLabel(info.applicationInfo).toString(); PlugInBean bean = new PlugInBean(); bean.
6、setLabelNmae(lable); bean.setPackagNmae(pkgNmae); mList.add(bean); return mList; 這里就是過濾了一下,通過sharedUserId去拿到我們的插件APK了,然后就可以拿到我們的包名和應(yīng)用名,他返回給我們一個(gè)數(shù)據(jù)集/所有的插件 List allPlugIn = findPlugIn();3.加載皮膚數(shù)據(jù) /* * 加載皮膚 * * param allPlugIn */ private void LoadSkin(List allPlugIn) /遍歷 for (PlugInBean bean : allPlugIn)
7、 HashMap mMap = new HashMap(); mMap.put(lable, bean.getLabelNmae(); mMap.put(package, bean.getPackagNmae(); mData.add(mMap); /建立Adapter并且綁定數(shù)據(jù)源 mAdapter = new SimpleAdapter(this, mData, android.R.layout.simple_list_item_1, new Stringlable, new intandroid.R.id.text1); /設(shè)置數(shù)據(jù) mSpinner.setAdapter(mAdapte
8、r); /設(shè)置監(jiān)聽事件 mSpinner.setOnItemSelectedListener(this); 我們通過剛才的數(shù)據(jù)集便可以把我們拿到的數(shù)據(jù)給直接顯示出來了,這里其實(shí)可以判斷一下size是否為0,如果為0的話也就沒有插件,OK,我們?cè)O(shè)置adapter和監(jiān)聽,做到這里,其實(shí)你可以運(yùn)行一下,雖然我們現(xiàn)在什么都沒有,我們要做的還有很多4.獲取插件Context /* * 選中監(jiān)聽事件 * * param adapterView * param view * param i * param l */ Override public void onItemSelected(AdapterVie
9、w adapterView, View view, int i, long l) PlugInBean bean = mList.get(i); /插件的包名 String packageNmae = bean.getPackagNmae(); Context mContext = null; try /無視警告 訪問代碼 mContext = createPackageContext(packageNmae, CONTEXT_IGNORE_SECURITY | CONTEXT_INCLUDE_CODE); catch (PackageManager.NameNotFoundException
10、 e) e.printStackTrace(); /獲取圖片 getImg(packageNmae, mContext); /通過ID加載插件的圖片 getWindow().setBackgroundDrawable(mContext.getResources().getDrawable(mListId.get(i); Override public void onNothingSelected(AdapterView adapterView) 這里的代碼就比較有意思,一定要仔細(xì)看,我們首先拿到選中的item的包名,通過我們的createPackageContext拿到我們的上下文,通過這兩個(gè)
11、我們可用拿到我們的資源ID,也就是R清單里面的ID,然后直接設(shè)置window的背景,這里為了好看才設(shè)置window的背景,實(shí)際上你要設(shè)置的是你根布局的背景,那好,我們來看一下如何通過插件的上下文和包名拿到R清單的資源ID5.獲取插件圖片 / 返回圖片R文件ID / 反射R文件 /* * 獲取插件圖片 / 返回圖片R文件ID / 反射R文件 * * param packageNmae * param mContext */ private void getImg(String packageNmae, Context mContext) /類加載器反射插件 PathClassLoader pat
12、hClass = new PathClassLoader(mContext.getPackageResourcePath(), ClassLoader.getSystemClassLoader(); /反射 $ 訪問類加載器 try Class forNmae = Class.forName(packageNmae + .R$drawable, true, pathClass); /拿到所有圖片的id Field files = forNmae.getDeclaredFields(); for (Field id : files) /過濾 / 這里的命名可以注意一下 if (id.getNam
13、e().startsWith(img) int drawId = 0; /這就是我們圖片R下的ID drawId = id.getInt(R.drawable.class); mListId.add(drawId); catch (ClassNotFoundException e) e.printStackTrace(); catch (IllegalAccessException e) e.printStackTrace(); 這里我們做了很多事情,首選是拿到我們的類加載器去反射我們的插件,然后通過Class去拿我們的資源,這里注意packageNmae是我們的文件目錄,他下面的R文件,$代
14、表類部類的意思,他下面的drawable子節(jié)點(diǎn),然后再一次過濾,過濾之后我們可用遍歷一遍拿到我們的ID用List保存起來,也就有了我們選中的時(shí)候的設(shè)置,好的,到這里主程序算是編寫完成了,不過要注意的是,記住要添加sharedUserId啊,至關(guān)重要!android:sharedUserId=com.liuguilin.share11我們現(xiàn)在運(yùn)行也是空的,無意義,我們直接來寫我們的插件吧!三PlugInApk插件插件的編寫很簡單,我們新建一個(gè)PlugInApk的工程工程里要做的事情就三件1.添加sharedUserIdandroid:sharedUserId=com.liuguilin.shar
15、e2.更改name這就取決于你了,比如我這里是Angelababy的主題,我就把名字改成Angelababy3.把圖片放在drawable文件夾下好的,做完這三部,我們本能的把插件運(yùn)行一下,運(yùn)行之后,我們?cè)俅螁?dòng)主程序,你會(huì)看到.其實(shí)我們主程序里啥也沒有,對(duì)吧,但是的卻加載進(jìn)來了,這就說明我們的插件化算是圓滿實(shí)現(xiàn)了,那我們多來點(diǎn)主題看看最終的效果是什么樣子的?通過這個(gè)思路確實(shí)可以加載到圖片,但是這個(gè)邏輯依舊有些不完美,不過最重要的,思考比實(shí)現(xiàn)更重要,對(duì)吧,后續(xù)的也就是一步步的優(yōu)化了,希望大家和我一起探討一下!當(dāng)上完整的代碼MainActivitypackage com.liuguilin.pl
16、uginsample;import android.content.Context;import android.content.pm.PackageInfo;import android.content.pm.PackageManager;import android.os.Bundle;import android.support.v7.app.AppCompatActivity;import android.text.TextUtils;import android.view.View;import android.widget.AdapterView;import android.wi
17、dget.SimpleAdapter;import android.widget.Spinner;import java.lang.reflect.Field;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;import dalvik.system.PathClassLoader;public class MainActivity extends AppCompatActivity implements AdapterView.OnItemSelecte
18、dListener /下拉 private Spinner mSpinner; /數(shù)據(jù)源 private SimpleAdapter mAdapter; /插件數(shù)據(jù) private List mList; /加載的皮膚數(shù)據(jù) private ListMap mData = new ArrayList(); /資源id private int drawId = 0; Override protected void onCreate(Bundle savedInstanceState) super.onCreate(InstanceState); setContentView(R.layout.ac
19、tivity_main); initView(); /所有的插件 List allPlugIn = findPlugIn(); /加載皮膚數(shù)據(jù) LoadSkin(allPlugIn); /* * 加載皮膚 * * param allPlugIn */ private void LoadSkin(List allPlugIn) /遍歷 for (PlugInBean bean : allPlugIn) HashMap mMap = new HashMap(); mMap.put(lable, bean.getLabelNmae(); mMap.put(package, bean.getPacka
20、gNmae(); mData.add(mMap); /建立Adapter并且綁定數(shù)據(jù)源 mAdapter = new SimpleAdapter(this, mData, android.R.layout.simple_list_item_1, new Stringlable, new intandroid.R.id.text1); /設(shè)置數(shù)據(jù) mSpinner.setAdapter(mAdapter); /設(shè)置監(jiān)聽事件 mSpinner.setOnItemSelectedListener(this); /* * 獲取手機(jī)里的插件 * * return */ private List find
21、PlugIn() mList = new ArrayList(); /獲取相關(guān)信息 PackageManager mPackageManager = getPackageManager(); /獲取卸載/未安裝的安裝包信息 List mUninstallPackage = mPackageManager.getInstalledPackages(PackageManager.GET_UNINSTALLED_PACKAGES); /遍歷拿到我們的信息 for (PackageInfo info : mUninstallPackage) String pkgNmae = info.packageN
22、ame; /獲取shareId,根據(jù)id判斷是否是我們的ID String shareUserId = info.sharedUserId; if (!TextUtils.isEmpty(shareUserId) /如果id相同 if (shareUserId.equals(com.liuguilin.share) /且排除自己的包名 if (!pkgNmae.equals(getPackageName() /這個(gè)就是我們的插件了 String lable = mPackageManager.getApplicationLabel(info.applicationInfo).toString(
23、); PlugInBean bean = new PlugInBean(); bean.setLabelNmae(lable); bean.setPackagNmae(pkgNmae); mList.add(bean); return mList; /* * 初始化View */ private void initView() /初始化控件 mSpinner = (Spinner) findViewById(R.id.mSpinner); /* * 選中監(jiān)聽事件 * * param adapterView * param view * param i * param l */ Override
24、 public void onItemSelected(AdapterView adapterView, View view, int i, long l) PlugInBean bean = mList.get(i); /插件的包名 String packageNmae = bean.getPackagNmae(); Context mContext = null; try /無視警告 訪問代碼 mContext = createPackageContext(packageNmae, CONTEXT_IGNORE_SECURITY | CONTEXT_INCLUDE_CODE); catch
25、 (PackageManager.NameNotFoundException e) e.printStackTrace(); /獲取圖片 getImg(packageNmae, mContext); /通過ID加載插件的圖片 getWindow().setBackgroundDrawable(mContext.getResources().getDrawable(drawId); /findViewById(R.id.mLinearLayout).setBackgroundDrawable(mContext.getResources().getDrawable(drawId); Overrid
26、e public void onNothingSelected(AdapterView adapterView) /* * 獲取插件圖片 / 返回圖片R文件ID / 反射R文件 * * param packageNmae * param mContext */ private void getImg(String packageNmae, Context mContext) /類加載器反射插件 PathClassLoader pathClass = new PathClassLoader(mContext.getPackageResourcePath(), ClassLoader.getSystemClassLoader(); /反射 $ 訪問類加載器 try Class forNmae = C
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(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ì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 湘教版數(shù)學(xué)八年級(jí)上冊(cè)《2.3 等腰三角形》聽評(píng)課記錄1
- 工程公司個(gè)人年末總結(jié)
- 大班班務(wù)工作總結(jié)下學(xué)期
- 中秋節(jié)主題活動(dòng)總結(jié)
- 特許經(jīng)營協(xié)議書范本
- 地上附著物轉(zhuǎn)讓協(xié)議書范本
- 社區(qū)團(tuán)購合作店鋪協(xié)議書范本
- 民辦學(xué)校聘用合同范本
- 中圖版地理七年級(jí)下冊(cè)5.2《地方文化特色對(duì)旅游的影響》聽課評(píng)課記錄
- 海南省2024七年級(jí)道德與法治上冊(cè)第一單元少年有夢第三課夢想始于當(dāng)下課后練習(xí)新人教版
- 《統(tǒng)計(jì)學(xué)》完整袁衛(wèi)-賈俊平課件
- GB/T 657-2011化學(xué)試劑四水合鉬酸銨(鉬酸銨)
- FZ/T 25001-1992工業(yè)用毛氈
- 《上消化道出血診療指南》講稿
- 電商部售后客服績效考核表
- 小提琴協(xié)奏曲《梁?!纷V
- 人教版高中化學(xué)必修一第一章《物質(zhì)及其變化》教學(xué)課件
- 復(fù)工復(fù)產(chǎn)工作方案范本【復(fù)產(chǎn)復(fù)工安全工作方案】
- HyperMesh100基礎(chǔ)培訓(xùn)教程
- 現(xiàn)代機(jī)械強(qiáng)度理論及應(yīng)用課件匯總?cè)譸pt完整版課件最全教學(xué)教程整套課件全書電子教案
- 農(nóng)村信用社個(gè)人借款申請(qǐng)審批表
評(píng)論
0/150
提交評(píng)論