發表文章

目前顯示的是 4月, 2016的文章

Android使用Callback做為傳遞資料/通知的方法

在一個常見的實作上的情境:當使用者在執行某個行為之後,就執行某些行為。例如當API接收成功之後就跳轉到某個頁面,API接收失敗的時候顯示錯誤訊息,除了可以使用BroadcastReceiver,另外也可以使用Callback的方式達成。 以App常見的實作功能-接收API為例,實作的方式如下: 1.先建立一個Interface。 首先在interface裡面製作兩個function,一個是執行結束要執行的行為:loadComplete(),另一個是顯示訊息:showMsg(String msg) /** * Api執行完之後的callback */ public interface ApiCallback { void showMsg(String msg); //要顯示的訊息 void loadComplete(); //api執行完成 } 2.在觸發行為的class裡產生Callback實體。 舉例來說,如果是在API執行之後一定會有該API自己所屬的成功/失敗callback function(或稱method),也就是如果API接收成功了就執行某個function(以Volley來看是onResponse()),而失敗了就執行某個function(以Volley來看是onError())。 於是就可以在Volley的onResponse()加入interface裡的loadComplete(),而在onError()加入showMsg(String msg) public class MyApi{ public ApiCallback mCallback; public DailyNewsApi(Context context) { this.mContext = context; mCallback = (ApiCallback) mContext; } @Override public void onError(VolleyError error) { super.onError(error); mCallback.showMsg("登入失敗"); //傳送失敗訊息內容

使用者刪除手機裡的資料夾,再次建立相同檔名時出現錯誤:open failed: EBUSY (Device or resource busy)

在App開發的過程,如果有個資料夾是App在使用某些功能時必須要存在的,例如像是音樂下載存放後播放。但如果使用者發現手機新增了檔案就直接連同資料夾都一併刪除(或搬移位置),而App為了確保檔案的存在(例如才可以播放音樂),於是在設計上就會在進到該功能頁面的時候又立刻建立資料夾下載檔案,而此時就會發生沒有辦法建立資料夾的錯誤。 E/Error:: /storage/emulated/0/music/my_music.mp3: open failed: EBUSY (Device or resource busy) 會發生這個錯誤是因為相同名稱的資料夾如果被刪除之後又馬上建立相同名稱的資料夾就會被系統擋下來。 所以解決的方法就是建立不同的名稱的資料夾再改回正確的名稱就好。以下提供一個實作的函式: /** * 建立可以快速刪增的資料夾 * * @param path */ public static void createFolder(String path) { //使用系統時間做為名稱的暫時資料夾名稱 final File fakeDir = new File(Environment.getExternalStorageDirectory(), path + System.currentTimeMillis()); //真正想要儲存的資料夾名稱 File realDir = new File(Environment.getExternalStorageDirectory(), path); //如果真正的資料夾不存在才建立暫時資料夾 if (!realDir.exists()) { fakeDir.mkdirs(); fakeDir.renameTo(realDir); //暫時資料夾改名為真正的資料夾名稱 fakeDir.delete(); //刪除暫時資料夾 } } 而在使用上只要傳入路徑名稱就可以了 createFolder( "music" ); //建立一個名為music的資料夾 Reference: http://stackoverflow.com/questions/11539657/open-failed-ebus

如何實作Android文字(TextView)裡的超連結onClick監聽與排版

最近寫了比較多關於TextView的東西,才發現Android的TextView其實功能很強大,不是只有單純的文字格式,換換字型、改粗體、斜體、行距這些基本款,更可以使用Html的語法來做文字排版。 如果要使用Html做為TextView的排版方法如下: 1.將Html格式的文字放在Resource的String裡,並且在html格式的文字前後各加上了 <![CDATA[ 與 ]]> <string name="html"> <![CDATA[ <b><a href="https://www.youtube.com/watch?v=6xc3dHjPje0">說好的幸福呢</a></b> <br> 作詞:方文山<br> 作曲:周杰倫<br> <br> 妳的回話凌亂著 在這個時刻<br> 我想起噴泉旁的白鴿 甜蜜散落了<br> <br> 情緒莫名的拉扯 我還愛妳呢<br> 而妳斷斷續續唱著歌 假裝沒事了<br> <br> 時間過了 走了 愛情面臨選擇 妳冷了 倦了 我哭了<br> 離開時的不快樂 妳用卡片手寫著 有些愛只給到這 真的痛了<br> 怎麼了 妳累了 說好的 幸福呢<br> 我懂了 不說了 愛淡了 夢遠了<br> 開心與不開心一一細數著 妳再不捨<br> 那些愛過的感覺都太深刻 我都還記得<br> <br> 妳不等了 說好的 幸福呢<br> 我錯了 淚乾了 放手了 後悔了<br> 只是回憶的音樂盒還旋轉著 要怎麼停呢<br> ]]&

如何讓Android 文字(TextView)消除上下邊距

Android的Textview預設會依字體大小而在文字留了上邊距與下邊距,如此一來可以讓不同的TextView之間具有預設的間距,讓視覺上不會太過擁擠的感覺。 但如果有排版對齊的需求時就會產生困擾,例如像是在多個TextView使用了不同的字體大小但要又在TextView之間都留下相同間距的時候。 解決的方法,在Layout XML的TextView加上includeFontPadding、marginTop與marginBottom即可 <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom=" -5dp " android:layout_marginTop=" -5dp " android:includeFontPadding=" false " /> Reference: http://stackoverflow.com/questions/4768738/android-textview-remove-spacing-and-padding-on-top-and-bottom

更新Android Studio 2.0之後Gradle版本錯誤

圖片
終於等到官方釋出了Android Studio 2.0穩定版,這次版本推出了好幾項開發過程相當 好用的功能 ,所以是一定要升級的版本。 但從舊有的版本升級之後卻不能build code了,出現了下列的錯誤訊息: Error:(1, 1) A problem occurred evaluating project ':app'. > Failed to apply plugin [id 'com.android.application'] > Gradle version 2.8 is required. Current version is 2.2.1. If using the gradle wrapper, try editing the distributionUrl in /Documents/AndroidDev/source_code/project_name/gradle/wrapper/gradle-wrapper.properties to gradle-2.8-all.zip 上網查的結果,發現也有人提到這幾乎都是每次版本更新時常會發生Gradle版本不適合的老問題了,於是照著錯誤訊息中指出的檔案修改: 在Android Studio的左邊選單找到gradle/wrapper/gradle-wrapper.properties 開啟之後,找到原本的版本名稱(以本例的版本是2.2.1) 修改成2.8,但已經有人發生 版本要求為2.10 了,所以可以直接就先改成2.10了,而改成2.10之後也是確定可以正常使用的 接著還有可能會發生Gradle Plugin版本不適合的問題 Gradle Plugin更新完之後會發現classpath裡的gradle版本已經變成2.0.0 Reference: http://stackoverflow.com/questions/34605667/android-studio-gradle-version-gradle-version-2-8-is-required

Google Play Console上傳解譯混淆對映檔案: mapping.txt

圖片
Android App一直以來都有被反組譯的風險,網路上有很多的反組譯工具教學,甚至還有聽過直接把你的apk download下來之後,直接修改內容再發佈到第三方App商城的事情發生。所以建議在build apk時都要加入混淆的機制,至少能增加一些被破解的難度。 但是當你上傳混淆過後的apk到Google Play上之後,如果App在操作的過程發生了ANR或是閃退時,使用者透過按下了「回報」的機制讓開發者收到錯誤的訊息內容,但在Google Play Console所看到的debug程式碼也都是被混淆過的程式碼,也會增加工程師debug的難度。 於是Google提供了上傳混淆程式碼的函式對映表的方式,當有使用者回報閃退時,其回報的程式碼錯誤區段能夠透過對映表再度解譯為原來的程式碼內容。 取得對映表mapping.txt的方式只要當你執行build release的apk 完成之後,就可以在下列的路徑找到: app/build/outputs/mapping/release/mapping.txt 接著進入到Google Play Console的 當機與ANR/反混淆檔案 選擇所屬版本上傳mapping.txt檔案 上傳mapping.txt檔案之後就會出現如下圖的畫面 請注意: 1.每次Build apk之後所產生的mapping.txt都會產生新的同名檔案覆蓋 2.在Android Studio執行Build/Clean Project會把mapping.txt清除 所以每次build完release版本所產生的mapping.txt檔案要先備份起來,以便之後要上傳到Google Play Console Reference: http://developer.android.com/tools/help/proguard.html#decoding https://support.google.com/googleplay/android-developer/answer/6295281?hl=zh-Hant

如何讓Android 文字(TextView)使用自訂字型不卡頓

圖片
有時為了版面好看,或是想要表現出文青的氣息,會想要把App的字型做個統一的樣式呈現,取代掉Android系統內建的字型,於是就會有必須變更字型的需求。而實作的方式只要透過以下幾個步驟就可以完成: 1.先在assets資料夾建立fonts資料夾,並將字型檔複製到assets/fonts的目錄下 2.將文字設定為自訂的字型 private Typeface fontType; private TextView text; fontType = Typeface.createFromAsset(getActivity().getAssets(),"fonts/NotoSansCJKtc-Regular.otf"); text.setTypeface(fontType); 基本上到步驟2就已經完成文字使用自訂字型的功能了,但如果使用自訂字型的文字同時出現在ListView或是ViewPager,在滑動的時候就會發生卡頓的情形,所以建議繼續實作步驟3 3.新增靜態提供字型的class,保留產生的字型物件 public class TypeFaceProvider { private static Hashtable typeFaces = new Hashtable (3); public static Typeface getTypeFace(Context context, String fileName) { Typeface typeface = typeFaces.get(fileName); if (typeface == null) { String fontPath = "fonts/" + fileName; typeface = Typeface.createFromAsset(context.getAssets(), fontPath); typeFaces.put(fileName, typeface); } return typeface; } } 然後將Typeface改為使用靜態提供字型的class所產生的物件 pr

Android的內嵌網頁(WebView)如何實作Facebook分享

有在寫App的人大概都會知道,如果把網頁包在App裡面,雖然有時可以很快解決版面、內容與網站的頁面共用的好處,但如果網頁有一些使用JavaScript的行為,像是開新視窗(window.open)、警告視窗(alert)...等語法在Android的Webview就會出現一些問題了。 通常會有使用者來跟你說:為什麼同樣的網頁內容,我用手機的瀏覽器去操作,可以出現的功能在你的App裡面就沒有任何反應?(你有頭緒嗎?) 最近就遇到了網頁裡的Facebook分享按鈕在Android的Webview裡面按下後沒有產生任何反應,更可怕的是出現了在iOS裡面是可以正確執行的對照組。所以就只能自己想辦法實作了。 仔細看了一下FB分享按鈕在網頁的語法會發現是觸發了window.open的方法 <a href="javascript: void(0)" onclick="window.open('http://www.facebook.com/sharer.php?sdk=joey&u=http://www.cw.com.tw/article/article.action?id=5075515& display = popup & ref = plugin & src = share_button','_blank','width = 700, height = 650');"></a> 所以解決的方法就是去實作WebChromeClient的Callback: onCreateWindow(),攔截彈出視窗時做出相對應的處理。 /** * 實作WebChromeClient內容 */ private WebChromeClient webChromeClient = new WebChromeClient() { @Override public boolean onCreateWindow(WebView view, boolean isDialog, boolean isUserGesture,Message resultMsg)