Wednesday, June 25, 2014

Conversion to Dalvik format failed with error 1的可能性

文章攢寫時間︰2014/06/26 14:53

一、問題

今天在使用正式keystore編譯Android Project輸岀成apk時,
遇到Conversion to Dalvik format failed with error 1

網路上已經提過非常多的解法,
但因為造成這個問題的原因非常多,
所以找到的solution不一定能解決問題。

二、解決辦法

這幾年遇到這個問題很容易的發生原因都是專案裡用的第3方套件在proguard時,
因為腳本沒寫齊全造成無法正常編譯成Dalvik格式導致產不了apk。

就我現在的例子來說,
我用了android的support v7兼容性套件來繪製Notification(訊息通知欄),
但我並沒有在腳本檔proguard.cfg或proguard-project.txt替support v7寫混淆腳本,
導致Conversion to Dalvik format failed with error 1。

底下附上support v4要添加的proguard腳本
-libraryjars /你的lib jar檔路徑/android-support-v4.jar
-keep class android.support.v4.** { *; }  
-keep interface android.support.v4.app.** { *; }  
-keep public class * extends android.support.v4.**  
-keep public class * extends android.app.Fragment
-dontwarn android.support.v4.**

攢寫完腳本後我就可以正常export APK檔了。

相關文章︰

Tuesday, June 24, 2014

@TargetApi 和 @SuppressLint 的差別

文章攢寫時間︰2014/06/25 14:10

Android自從加入Lint工具後,
會自動幫開發者們檢查是否在不對的版本使用超岀版本的api。
倘若此事成立,
Android Lint就會跳岀來問你要在此scope上方加上@TargetApi還是@SuppressLint。

剛才在stackoverflow論壞看到一個很有趣的解釋︰
@TargetApi(NN) says "Hey, Android! Yes, I know I am using something newer than what is allowed for in my android:minSdkVersion. That's OK, though, 'cause I am sure that I am using Build (or something) such that the newer code only runs on newer devices. Please pretend that my minSdkVersion is NN for the purposes of this (class|method)".
@TargetApi 意思是說︰「嘿!Android兄,我知道我現在正用一些比我AndroidManifest.xml裡android:minSdkVersion還要新的的API。我想這是沒問題的。因為我很確定我的編譯環境是在新的SDK和新的機器上,我minSdkVersion設那麼低其實只是假的啦(為了在Google Play上被更多人看到我的App)!

@SuppressLint, to address the same error, says "Hey, Android! Yes, I know I am using something newer than what is allowed for in my android:minSdkVersion. Quit complaining.".
@SuppressLint 則是指︰「嘿!Android兄,我知道我現在正用一些比我AndroidManifest.xml裡android:minSdkVersion還要新的的API。不要再跟我碎唸了!

Hence, given a choice of @TargetApi(NN) or @SuppressLint, go with @TargetApi(NN). There, if you start using something newer than NN -- and therefore your existing version-checking logic may be insufficient -- you will get yelled at again.
因此,如果要在@TargetApi或@SuppressLint裡做選擇,盡量選@TargetApi就是了。

Friday, April 25, 2014

使用Webview時,遇到Uncaught ReferenceError: is not defined.

文章攢寫時間︰2014/04/25 16:50
Admob使用版本︰Goole Play Service 4.0版

一、問題

今天在Debug模式下,
可以正常和網頁透過Javscript interface溝通,
但是一旦使用正式金鑰釋岀apk時,
卻遇到

"Uncaught TypeError: Object [object Object] has not method 'xxxxx'", source: http://xxxxxx

的問題。

二、解決辦法

這個問題也是因為proguard沒有宣告規則導致的問題。
需要在proguard.cfg檔裡宣告如下
# 添加以下的程式碼才能讓webview的javascript能正常運作
-keep public class com.yourpackage.WebViewActivity$yourwebview_interface
-keep public class * implements com.yourpackage.WebViewActivity$yourwebview_interface
-keepclassmembers class com.yourpackage.WebViewActivity$yourwebview_interface { 
    ; 
}
-keepattributes JavascriptInterface

舉個例來看, 下面是我在Java裡使用Webview的簡單例子
 private void setWebview(){
webView.getSettings().setJavaScriptEnabled(true);
  webView.addJavascriptInterface(new WebViewHandler(), "handler");
  webView.setWebViewClient(new WebViewClient() {
  
  @Override
  public void onPageFinished(WebView view, String url) {
   LogPrint.i(TAG, "onPageFinished ,url: "+url);

   //呼叫網頁當下頁面的js函式:getVXML(),然後網頁js會呼叫回來下方的函式︰receiveValueFromJs()
   webView.loadUrl("javascript:getVXML()");

   super.onPageFinished(view, url);
  }
  
          @Override
          public boolean shouldOverrideUrlLoading(WebView view, String url) {
            return super.shouldOverrideUrlLoading(view, url);
          }
  
     });      
     webView.loadUrl(webViewUrl);
        }

     class WebViewHandler {
  //網頁當下頁面的js函式:getVXML()會呼叫這隻Native函式︰receiveValueFromJs(String data)
  public void receiveValueFromJs(String data) {

  }
 }

那麼,
在proguard.cfg檔裡,
則要宣告混淆規則如下︰
# 添加以下的程式碼才能讓webview的javascript能正常運作
-keep public class com.yourpackage.WebViewActivity$WebViewHandler
-keep public class * implements com.yourpackage.WebViewActivity$WebViewHandler
-keepclassmembers class com.yourpackage.WebViewActivity$WebViewHandler { 
    ; 
}
-keepattributes JavascriptInterface

填寫完混淆規則後,
輸岀正式金鑰的apk檔,
這時候Webview javascript interface就能繼續正常使用了。

Tuesday, December 31, 2013

串接Admob時岀現The Google Play services resources were not found.

文章攢寫時間︰2013/12/31 17:45
Admob使用版本︰Goole Play Service 4.0版

一、問題

今天在串接Admob時,
遇到
The Google Play services resources were not found. Check your project configuration to ensure that the resources are included.
的錯誤,
Admob廣告一直沒有岀現。

二、解決辦法

請在values\strings.xml裡,
填上你的ad_unit_id...


Monday, December 30, 2013

Tapjoy與Proguard的親密接觸

文章攢寫時間︰2013/12/31 11:40

一、前言
話說等一下即將邁入2014年,
各位安卓猿們有沒有安排跨年計劃,
亦或待在家專心趕code呢?
先祝大家新的一年健康快樂、事業順利啊!

言歸正傳,
這幾天在寫code時,
遇到了Tapjoy在Proguard編譯岀來的apk檔裡發生的問題。

二、問題

為了不要讓Java檔一下子就被破解,
Android提供了Proguard工具。

這幾天在使用tapjoy機制時,
運行時遇到了因為程式Proguard後,
導致找不到tapjoy library resources的NullPointerException問題。

三、解決辦法

只要在proguard腳本檔(proguard-project.txt)裡添加兩行即可解決
-keep class com.tapjoy.** { *; }
-keepattributes JavascriptInterface

相關文章︰

Tuesday, October 29, 2013

IAB-V3使用經驗小記(陸續新增)

文章攢寫時間︰2013/10/29 15:45

Google Play in-app billing V3的使用經驗記錄於下︰
1.如果將應用程式內商品退費,短期內似乎不能再購買此商品(20131029觀察中)

Tuesday, September 24, 2013

[電影]賈伯斯 觀後感(無爆雷)

文章攢寫時間︰2013/09/25 10:42

「賈伯斯」好看嗎?

這是在看完電影「賈伯斯」特映會後,最多人問我的一句話。

它不是Local商業片,不像鋼鐵人3,不像大尾鱸鰻,不像總舖師,
它是一部描述一個人的傳奇、一個人一生的電影,
因此在劇本的設計上通常是不用太刻意製造笑點或哭點的,
只要忠實的陳述岀人、事、時、地、物和有故事核心,
就已經是傳記類故事合格的表達方式。

1)人 - 賈伯斯何許人也?
2)事 - 賈伯斯發生什麼事?
3)時 - 賈伯斯的經歷?
4)地 - 賈伯斯在哪裡創業、哪裡成功?
5)物 - 賈伯斯發明了些什麼改變了世界?

(文章看到這裡,連我都打了一聲哈欠)

如果電影裡的故事都是真實故事,
那麼依我看,
賈伯斯是一個『糟糕透了』的人。

賈伯斯他是為了事業,將最親愛的人不顧的人。
他是一個眼光狹獈至極不懂得分享成功的人。
他是為了一件事的成功,忽略了其它所有感受和看法的人。

成功有許多的方式、途徑,
絕對沒有哪一條路是對、是好,

他的執著、他的偏執、他的狂妄、他的理念,
他的「簡單、清楚、力與美學」的工業設計理念,
很多決策他必須要相信他自己、認同他自己,
而這條路,就像他的創業夥伴在離開他前哭著對他說︰
「我知道你是那麼地孤單。」


成功不是僥倖、不是運氣,
我看到的是他對於理念的執著、
一個科技企業人看事的遠光、
還有一顆永遠不安逸於現況的心。

這部戲不需要果粉才能看,
因為它是一部傳記,
描述了一個人成功的故事和一生。

沒有賈伯斯就沒有Apple,
沒有Apple就不會有Android,
因此,
賈伯斯不僅是Apple之父,
他也是Android之父、
更是智慧型手機之父。

不安逸於現況、永遠要比別人看地更遠、對一件認為是對的事情的堅持與執著⋯
這些想法都在我內心不斷地共鳴著。


這部戲不是Local商業片,
所以你絕對不會從你朋友口中聽到「賈伯斯超好看的,你趕快去看」這類的話。
因此片商也很聰明的直接在宣傳海報上打了一排字︰「歡迎企業包場。」


我最終還是流下了男兒淚,
一個成功的人,
一路上...真的...很孤獨。

Saturday, June 1, 2013

升級ADT22後專案開不了,報NoClassDefFoundError錯誤。

文章攢寫時間︰2013/06/01 19:04

一、問題

升級ADT到v.22後,
原本能開的專案突然開不了,
還報NoClassDefFoundError的紅字錯誤給我們看。

二、解決辦法

原來在v.22 Android團隊將專案會用到的libs再度收納到了Android Private Library,
所以需要將Android Private Library開起來。


Android Team的Andreas Stutz在他的G+好心的提醒我們升級到ADT 22會產生NoClassDefFoundError錯誤
更弔詭的是
還有網友說還要繼續把專案關起來再打開,
才能恢復正常...

附上操作流程︰
1.專案點擊右鍵
2.Build Path-> Configure Build Path -> Order and Export
3.選取Android Private Libraries方塊,並按OK
4.清除你的專案[Project]-->[Clean]
5.編譯你的專案

Saturday, May 25, 2013

Game Service串接注意事項(更新中)

文章攢寫時間︰2013/05/25 14:20

1.需要在Android Menifest.xml裡<application>和<activity>中間宣告
 

 
否則會遇到java.lang.IllegalStateException: A fatal developer error has occurred. Check the logs for further information. 的錯誤。

2.在values資料夾要放置ids.xml宣告你的app_id和成就以及排行榜相關的id

3.注意在Google Api Console的使用額度(quota)

Wednesday, May 22, 2013

Google I/O 2013 - Custom View筆記

文章攢寫時間︰2013/05/22 18:40

Google I/O 2013 - Custom View筆記

  1. View的繪製流程可以直接draw(),但也可以先onMeasure()再onLayout()再draw(),onMeasure()和onLayout()一定會是同步發生。
  2. 要客製化做出自已的View,一定是implements ViewGroup。
  3. ViewGroup不僅是一個容器,還是一個管理子View的控件。
  4. 客製View的第1個流程︰requestLayout() - 這個函式告訴系統你現在有一個View需要被計算和繪製。
  5. 把requestLayout()想成是一個草稿,在這個時間點你可以改變你的View大小、可以改變View在hierachy的層級⋯等等。
  6. 呼叫了requestLayout()後,對於整個View的層級影響是很大的,它可以影響到它的父視圖的計算、父父視圖的顯示⋯。
  7. 客製View的第2個流程︰實作onMeasure() - 用這個函式來決定你的View的大小,還有你這個View之後裝的子View的大小。
  8. onMeasure()是一個不斷循環的函式(recursive process)
  9. onMeasure()的責任是要去找出並量出子View的合適大小
  10. 量出View的大小的方法︰MeasureSpec
  11. MeasureSpec的第1種工具︰精確的指定大小(MeasureSpec.EXACTLY)
  12. MeasureSpec的第2種工具︰依子View的大小做判斷給出理想範圍(MeasureSpec.AT_MOST)
  13.  MeasureSpec的第3種工具︰不指定大小(MeasureSpec.UNSPECITIED),最常見的例子就是ScrollView和ListView。
  14. 客製View的第3個流桯︰onLayout() - 將你在onMeasure()裡定義好的大小,去計算所有子View即將存放的螢幕所在位置。
  15. ViewGroup專用的尺寸定義工具︰LayoutParams
  16. 如果沒有指定LayoutParams,如果你用的是FrameLayout,那麼系統會配予match_parent屬性。
  17. Drawing - Android的介面渲染工具。
  18. invalidate(),跟requestLayout()不同的地方在於,如果你的View有動畫、有變形...,可以使用這個函式來請求重繪。
  19. 使用Drawing渲染工具的方式 - 實作函式onDraw()
  20. 如果你的View都會由子View去繪圖,那麼就可以setWillNotDraw(true)讓系統去跳過onDraw()這個流程。
  21. dispatchDraw()被負責繪製子view,包含變形、動畫⋯等等的事件。
以上為聆聽筆記,如有誤煩請回應告知。

Monday, May 20, 2013

R檔不見了

R檔記錄了Android Project裡各種資源的位址,
是很重要的資料。
這份資料是自動產生的,
會存在於gen資料夾底下。

如果發現沒有R檔通常使用[Project]-->[Clean],
R檔都能回來。

如果仍然回不來,
請先確定res目錄底下的所有資源都沒問題了(沒有紅色xx),
再執行一次[Project]-->[Clean]。

R檔才會出現...

Monday, November 5, 2012

測量物件寬高

有時候在getWidth和getHeight無法起作用,
Romain Guy提到因為物件還沒畫出來,
因此此值會回傳0。

因同事的努力,
翻牆到有一位網友j研究了怎樣才會取到物件的寬和高。
用法是這樣的
  1.  final ImageView imageView = (ImageView) findViewById(R.id.imageview);        
  2.         
  3.       //------------------------------------------------方法一  
  4.       int w = View.MeasureSpec.makeMeasureSpec(0,View.MeasureSpec.UNSPECIFIED);  
  5.       int h = View.MeasureSpec.makeMeasureSpec(0,View.MeasureSpec.UNSPECIFIED);  
  6.       imageView.measure(w, h);  
  7.       int height =imageView.getMeasuredHeight();  
  8.       int width =imageView.getMeasuredWidth();  
  9.       textView.append("\n"+height+","+width);  
詳文請參見連結

Friday, September 7, 2012

ListView裡的OnItemClickListener失去作用(失效)

一、Problem
今天在實作ListView,自訂義一個Adapter繼承BaseAdapter後,
發現ListView原本的OnItemClickListener失去作用。

二、Description
上圖是ListView的其中一橫條,
為了讓內容豐富,
用了2個ImageView(圖片)和2個TextView(文字)元件。
有時候為了讓ListView的內容豐富,
我們常會自訂義一個Layout來讓ListView的內容多元,
但也因為多元,
如上圖所示,ImageView和TextView預設都有自己獲得Focus的能力,
這些元件搶走了原本List獲得焦點的能力。

每一條ListView在點擊時,
原本都擁有自己的Focus,
因此ListView的點擊才有效用。

如果我們希望List被點擊後,
讓OnItemClickListener仍有作用,
該怎麼做呢?

三、Solution
外國論譠描述要改善子元件不影響原來ListView獲得Focus最快的方式就是在自訂義的Layout中,附上一個屬性︰

下片這段程式碼就是上面List_Item內容的Layout佈局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/LinearLayout1"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@drawable/feeback_item_bg"
    android:gravity="center_vertical"
    android:descendantFocusability="blocksDescendants">

    <TextView
        android:id="@+id/textView2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="3dp"
        android:layout_marginLeft="10dp"
        android:text="題編"
        android:textColor="#FFFFFF"
        android:textSize="8sp" />


    <ImageView
        android:id="@+id/imageView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/feedback_q" />

<TextView
        android:id="@+id/textView3"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:paddingBottom="5dp"
        android:singleLine="false"
        android:text="題目內容"
        android:textColor="#000000" />


    <ImageView
        android:id="@+id/imageView2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/feedback_a" />

    <TextView
        android:id="@+id/textView1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_weight="2"
        android:inputType="text|textMultiLine"
        android:paddingRight="20dp"
        android:text="答案"
        android:textColor="#000000" />

</LinearLayout>

如上面紅色標註,
Android有提供一個快捷方式讓Layout裡的子元件全部失焦,
就是使用
android:descendantFocusability="blocksDescendants"

註︰
1.當我在使用這個屬性時,
仍然無法讓OnItemClickListener發揮作用,
後來才發現我的TextView裡原本有設定一個屬性android:inputType="textMultiLine"
外國網友討論說這是一個Android的BUG,
此屬性一旦宣告,
又會讓上面紅色的宣告失去效果。
我把inputType="textMultiLine"拿掉,
整個問題才被解決。 
2.最好用RelativeLayout的方式,使用僅一層Layout的架構客製這個list_item,
不僅在滑動有效率,也不會有這篇產生的問題。

Saturday, September 1, 2012

在EC2發送Android推播產生中文亂碼

一、Problem
這幾天試驗在亞馬遜Amazon AMI(CentOS)上發送Android的GCM(推播系統)給用戶,
卻一直遇到手機收到中文亂碼的問題。

二、Solution
  1. 安裝中文字元集 yum install fonts-chinese
  2. 設定系統語系檔 #vi /etc/sysconfig/i18n LANG="en_US.UTF-8" 修改為 LANG="zh_TW.UTF-8"
  3. 重新開機

Wednesday, August 29, 2012

購買in-app billing,Google Play視窗開了2次

今天遇到一件事,
至從增加Subscription服務後,
Dungeons在request購買時,
畫面會先跳出找不到項目,
然後又跳出in-app billing商品列表,
I encountered a problem when I was using Google In-app billing today that is when I request purchase, Google Play Billiing view shows twice.
First, It shown "Can't find Item" dialog then shown me the in-app billing product item what I set.

爬文才發現問題出在Google Play Billing的Sample Code:Dungeons.java出了一個邏輯上的錯誤,
那就是︰
Finally I figure out the cause is logic in in-app billing sample code:Dungeons.java.
Wrong code is on below:


 @Override
    public void onClick(View v) {
        if (v == mBuyButton) {
            if (Consts.DEBUG) {
                Log.d(TAG, "buying: " + mItemName + " sku: " + mSku);
            }

            if (mManagedType != Managed.SUBSCRIPTION &&
                    !mBillingService.requestPurchase(mSku, Consts.ITEM_TYPE_INAPP, mPayloadContents)) {
                showDialog(DIALOG_BILLING_NOT_SUPPORTED_ID);
            } else if (!mBillingService.requestPurchase(mSku, Consts.ITEM_TYPE_SUBSCRIPTION, mPayloadContents)) {
                // Note: mManagedType == Managed.SUBSCRIPTION
                showDialog(DIALOG_SUBSCRIPTIONS_NOT_SUPPORTED_ID);
            }

        } else if (v == mEditPayloadButton) {
            showPayloadEditDialog();
        } else if (v == mEditSubscriptionsButton) {
            editSubscriptions();
        }
    }

紅色那段的邏輯錯誤,
造成Google Play視窗被開啟兩次,
只要將那段改成
 if (mManagedType != Managed.SUBSCRIPTION &&
                    !mBillingService.requestPurchase(mSku, Consts.ITEM_TYPE_INAPP, mPayloadContents)) {
                showDialog(DIALOG_BILLING_NOT_SUPPORTED_ID);
            } else if (mManagedType == Managed.SUBSCRIPTION && !mBillingService.requestPurchase(mSku, Consts.ITEM_TYPE_SUBSCRIPTION, mPayloadContents)) {
                // Note: mManagedType == Managed.SUBSCRIPTION
                showDialog(DIALOG_SUBSCRIPTIONS_NOT_SUPPORTED_ID);
            }
即可改善Billing視窗開了2次的問題。 
If modify code as above will fix this bug.

Friday, August 10, 2012

輸出時出現Dalvik的UNEXPECTED TOP-LEVEL EXCEPTION: java.lang.IllegalArgumentException

今天將isLibrary的專案Build出來時,
遇到一個
UNEXPECTED TOP-LEVEL EXCEPTION:
java.lang.IllegalArgumentException: already added: Lcom/xxx/sample/R$attr;
的錯誤,
結果在Library裡將bin目錄底下的com/xxx/sample/刪掉,
就能正常Build出程式了。

Monday, July 9, 2012

Fragment筆記

撰寫日期︰2012/07/09 16:55
修改時間︰2015/10/26 14:07
修改次數︰5
一、前言
Android在3.0時就已經推出了Fragment(片斷)這個元件,可惜因為Android3.0以上的市占一直不高,因此一直沒有很完整的使用範例,但是因為最近我在用兼容套件,它能幫我們在Android2.x就使用Fragment,我也剛好用到,順便在這裡把我的學習心得記錄下來。

二、文章開始

1.淺談Fragment
Fragment,它屬於一個完整的Activity使用介面的其中一部份,想像一下,我們可以將多個fragments放在一個Activity底下,達到多區塊的程式能在一個或多個Activity間彼此靈活運用、互相溝通。(可以把它看成是一個子Activity,它們可以在很多個不同的Activity中同複使用)。

Fragment必需被崁在Activity裡面,它的生命週期也完全受到Activity的影響。什麼意思呢?假設今天Activity被Destroy()掉了,Fragment也會跟著被Destroy()掉。
然而,如果Activity運行中,你可以針對Activity裡的數個Fragment做個別獨立的控制,像是新增一個個的Fragment,甚至是移除掉它們。
當你執行fragment transaction時,你還能夠將你新增的Fragment添進back stack(背景堆疊,請見我2010年寫的文章)這個被Activity管理的機制中。每個back stack寫入時機皆發生在fragment transaction發生的時間點上,back stack允許使用者使用手機的返回鍵返回fragment transaction的狀態。

當你新增了一個fragment到你的Activity Layout的同時,它就被常駐進Activity裡ViewGroup的View階層中,它們還能夠自訂義應該要擁有怎麼樣的Layout。
你可以在Activity的Layout中去定義Fragment的擺放位置(使用<fragment>這個tag標籤),當然,也可以使用coding的方式,將Fragment放進Activity已存在的ViewGroup裡。然而,Fragment並不是一定需要成為Activity Layout的一部份的,因為Android也允許Fragment在一個無自屬UI狀態下,當成Activity的"隱性工作人員(invisible worker)"。酷吧!

2.設計原理
Android在3.0(API level 11)的時候介紹了這個Fragments元件,主要是用來支援在large screen(平板)裡多種動態及彈性的UI互動。因為平板的螢幕通常比手持裝置還要大,因此,也得到了許多能夠合併或在畫面中做改變的空間。Fragment因為能夠到幫你處理複雜的view階層(View hierarchy)運算,包括將一個Activity的layout傳至fragments中,因此你能在程式執行時期(Runtime)夠修改Activity的樣貌,也能夠讓Activity去管理並保留每一個fragment被改變的狀態,如同前面所說,存在back stack(背景堆疊)中。

提了那麼多,我在這裡做點假設。想像一下,有一隻APP可以在畫面的左邊顯示文章列表,右側則是顯示文章的內容,這2個都是fragment組成,而且還同時存在一個Activity中,酷吧?
每一個fragment都擁有各自的生命週期回呼函式(lifecycle callback),而且也能處理他們各自輸入事件,因此,fragment跟一般的Activity(一頁拿來讀文章列表,另一個Activity拿來讀內容)是很不一樣的。看看底下的圖1就知道了。
圖1. 此範例說明了如何在一個平板的Activity中,使用2個UI模組,但又能在手持裝置中分開使用。

你應該將每個Fragment模組化,並且讓它們能在Activity中重複使用。因為每個Fragment都定義了自己的layout、操作行為和自己的生命週期回呼函式。然而,因為你可以在多個Activity中去使用單一個Fragment,你就必須去設計得讓它們是能被重複使用的,並且盡量避免設計從A fragment直接手動存取B fragment。這件事很重要,因為一個被模組化的fragment能夠允許你在不同的螢幕中去做不同的排列組合。
當你的APP是設計給平板和手持裝置使用時,你就能利用你能使用的螢幕空間,去做最好且客製化的畫面呈現優化。舉例來說,手持裝置也許需要將多個fragment分散成一個一個的UI畫面,並讓它們存在各自的Activity中。但是因為你用了fragment,當你在用平板尺寸開發時,你就能崁進2個Fragments,然而,手持裝置卻因為空間不足,因此無法讓2個Fragments並存。所以手持裝置的Activity A只能放文章列表,Activity B則是放文章內容。也因為用了Fragment,這隻APP就能在手持和平板上共存,並且相容得很好。

3.建立一個Fragment
要建立一個Fragment,你必須繼承Fragment(或者繼承Fragment的子類別)。Fragment類別的程式碼看起來跟Activity很像,它擁有和Activity雷同的call back(回呼函式),像是onCreate()、onStart()、onPause()和onStop()。事實上,如果你要將你已經開發的APP轉移植到fragment中,你只要將這些code從你Activity的callback函式轉放到各自的fragment回呼函式中就可以了。

在使用Fragment時,通常你會需要實作至少3個生命週期回呼函式,它們是︰

onCreate() - 這個回呼函式是系統在建立Fragment時會呼叫的函式,你應該在這個回呼函式中初始化一些必要的元件,好讓fragment之後在pause或stopped、resumed時能使用。
onCreateView() - 系統會在要畫fragment的使用介面的第1時間去呼叫這個回呼函式。如果你有自訂義的view,你必須在這個回呼函式中return 一個自訂義的view(而且必須回傳為root),當然,如果Fragment沒有自己的View,你就回傳null吧!
onPaue() - 當使用者要離開時,系統會呼叫它。當你要儲存什麼值時,就在這個時機去儲存吧!

大部份的APP應該實作至少上述3種回呼函式。但是其實每個Fragment都有更多的回呼函式是你應該要去處理的。等等還會提到。

三、其它

官方文檔已將Fragment翻譯成中本版,
前往閱讀。

Thursday, May 24, 2012

Google Play Subcription(auto renew)訂閱型服務上線!

Google Play訂閱型服務於美國時間2012/5/24發出了技術公報,
底下簡單列出幾項重點︰

  • 一定要先將APP上線(published)才能使用subscription服務
  • 一個APP內可含多種資費,售價一定要高於0.00
  • subcription的沙箱模式幾週後才會在開發者控制臺上線
  • 價格一旦訂了,就無法更改(更改的功能也要等幾週後開發者控制臺改版才提供)
  • 如果舊資費已上線,使用者也在使用了,後期如果調整資費,subcription仍會以舊資費向使用者扣款。
  • subcription的訂閱期間分2種-月租型年繳型
  • 透過Google Wallet跟使用者扣款
  • 每期的扣款都會寄一封e-mail通知使用者
  • Google會持續地跟同一張信用卡扣款
  • 關於退費,必須從Google Play-->[我的應用程式]裡去解約,不提供直接從APP做解約的動作
  • 當使用者按了退款,會算到週期結束才結束subcription服務(30或31天,視大小月而定)
  • 特殊狀況下,萬一使用者直接找廠商解約,還是可以透過自己的server並使用server-side API去跟Google做API方式的直接解約
  • subcription只支援有支援in-app-billing的國家
  • (台灣也算在內,請見官方in-app-billing支援國家列表)
  • Google Play app版本號必須在3.5以上,Android版號必須在2.2以上
  • 當使用者移除app時,Google會發出警告通知︰這隻APP仍在subcription服務下,並會詢問是否要解除該訂閱
  • subcription的退費模式遵照in-app-billing,需直接找廠商處理。
  • 即使退費了,服務仍會在使用者手機上維持1個月的cycle。
  • subcription一樣有30%的抽成

Friday, May 18, 2012

果合中介的廣告無法貼齊APP邊緣

就是這個xx
剛才發現果合的中介廣告,
陸出的廣告無法貼齊APP的邊緣,
多了5mm。

找很久才發現原因是因為果合後臺有提供一個close button,
那個button用了版面5pixel。