編輯:關於android開發
使用Bmob的時候,如果需要用到支付功能,就需要讓應用去安裝一個支付插件。而一般的做法是將插件放置在assets目錄中,當用戶需要支付,先檢查是否能支付,不能的話,提示安裝插件。代碼:
1 public class InstallHelper { 2 private static final String TAG = "InstallHelper"; 3 private Context mContext; 4 5 InstallHelper(Context context) { 6 mContext = context; 7 } 8 9 void installAssetApk(String fileName) { 10 try { 11 InputStream is = this.mContext.getAssets().open(fileName); 12 File file = new File(mContext.getExternalCacheDir()+ File.separator + 13 "demo.apk"); 14 if (file.exists()) { 15 file.delete(); 16 } 17 file.createNewFile(); 18 FileOutputStream fos = new FileOutputStream(file); 19 byte[] bytes = new byte[1024]; 20 int i; 21 while ((i = is.read(bytes)) > 0) { 22 fos.write(bytes, 0, i); 23 } 24 fos.close(); 25 is.close(); 26 Intent intent = new Intent(Intent.ACTION_VIEW); 27 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 28 intent.setDataAndType(Uri.parse("file://" + file), "application/vnd.android" + "" + 29 ".package-archive"); 30 mContext.startActivity(intent); 31 } catch (IOException e) { 32 e.printStackTrace(); 33 } 34 } 35 }
我們不能直接執行assets下的安裝包,所以這裡的做法是先獲得Assets目錄的輸入流。接著創建一個文件,這個文件用來存放我們從assets目錄下讀出的安裝包內容。上述代碼中的12和13行中,我們通過getExternalCacheDir()來獲取主要存放的目錄,再通過File.separator來插入一個路徑分隔符,最後填上文件名來作為整個文件的絕對路徑。這裡有一個地方要說明,先看下面兩個方法:
getExternalCacheDir():獲取應用目錄下的cache目錄,不需要讀寫權限,應用刪除時也會刪除
getExternalStorageDirectory():獲取主外部儲存的根目錄,需要讀寫權限,應用刪除不會刪除
因為這個插件不需要共享給其他應用,所以我們需要使用第一個方法。如果使用了第二個,則會破壞掉用戶外部儲存的目錄結構,畢竟無端的多出了一個文件,用戶感覺當然是不好的。
接著判斷文件是否存在,若存在則重新建立。再創建一個byte數組來進行數據讀寫操作的輔助,不斷地從輸入流中讀入數據,寫到文件中。但是這裡有一個問題要注意,我們傳輸的是一個安裝包,只要最後傳輸的文件和assets目錄下的安裝包有一點不同,那麼這個安裝包都是不能使用的(安裝會提示解析出錯)。這裡要留意的地方就是22行,這個write方法不能寫錯。
如果我們直接使用:
fos.write(bytes); // 相當於fos.write(bytes, 0, bytes.length),也就是把整個bytes數組寫入輸出流
則這個傳輸就不正確了,這裡先想想為什麼?可以看到,我們定義了一個局部變量i來獲取每次讀入的大小,只要這個i的值不為-1,則循環一直進行。但是試想最後一次循環的時候,假設數據只有500個byte,那麼我們直接調用fos.write(bytes)則是相當於把整一個bytes數組都寫進輸出流,但是實際上我們只需要前500個。
當讀寫完全後,我們可以通過Intent來打開這個安裝包,寫法就是上面那樣。
另一個內容就是檢查一個應用是否已經安裝,例如我們在調用微信分享的時候,如果用戶手機中沒有微信,那麼App將會沒任何反應,這不會是是我們希望看到的,所以一般會先判斷微信是否已經安裝(其他應用類似)。
判斷一個App是否已經安裝,我在StackOverFlow中看到的很多方法都是直接的使用PackageManager來獲取所有Activity對應的PackageInfo,代碼如下:
private boolean isWechatInstall() { List<PackageInfo> installedPackages = getPackageManager().getInstalledPackages (PackageManager.GET_ACTIVITIES); for (PackageInfo p : installedPackages) { if (p.packageName.equals("com.tencent.mm")) { return true; } } return false; }
實際上這樣做是不行的。原因是系統中的應用Activity對應的Package是很多的,如果在短時間內對這些信息進行包裝,則會拋出異常並終止處理(一般處理30個左右就會自動終止),因為這個異常不是RuntimeException,所以我們的App也不會Crash掉,只是結果不正確。
正確的做法應該是這樣:
private boolean isAppInstalled(String packageName) { PackageManager pm = getPackageManager(); boolean installed; try { pm.getPackageInfo(packageName, PackageManager .GET_ACTIVITIES); installed = true; } catch (PackageManager.NameNotFoundException e) { installed = false; } return installed; }
直接根據包名獲取其PackageInfo對象,如果不存在,則在拋出的異常中返回false即可。
setting菜單界面的形成--未優化,setting菜單界面-- 代碼: first_preference.xml: 1 <?xml versi
Android接入微信支付完全解析,太全了~ 今天來聊聊,android中接入微信支付的需求,肯定有人會說,這多簡單呀,還在這裡扯什麼,趕快去洗洗睡吧~~ 那我就不
flexboxlayout,flexbox 提到FlexboxLayout大家估計有點模糊,它是谷歌最近開源的一個android排
Kotlin的數據類:節省很多行代碼(KAD 10),kotlin很多行作者:Antonio Leiva 時間:Jan 25, 2017 原文鏈接:https://ant