2016年9月29日 星期四

[Codility] TapeEquilibrium

// you can also use imports, for example:
// import java.util.*;

// you can write to stdout for debugging purposes, e.g.
// System.out.println("this is a debug message");

class Solution {
    public int solution(int[] A) {
        // write your code in Java SE 8
        int l = A.length;
        int max = 0;
        for(int i = l -1 ; i >= 0 ; i-- ){
            max += A[i];
            A[i] = max;
        }
        
        int tmp = A[0];
        for(int i = 0 ; i < l-1 ; i++ ){
            A[i] = tmp - (A[i+1] * 2);
            if(A[i] < 0)
            A[i] = -A[i];
        }
        
        int min = A[0];
        int ans = 0;
        for(int i = 1 ; i < l-1 ; i++){
            if(A[i] < min){
                min = A[i];
                ans = i;
            }
        }
        
        return min;
    }
}
Analysis summary


https://codility.com/demo/results/trainingUNYT7U-S2M/

2016年7月21日 星期四

【Android】APK Method Count

http://inloop.github.io/apk-method-count/

APK的Method數量有限制。

用這個網頁可以計算。

2016年5月10日 星期二

關於ActivityLifeCycleCallback

API文件在此。

這東西很有趣。

如果沒有它,「將共用資料擺在Application」這樣的認知或建議其實不太好用。



不過這是「我」。我認為應該要將Activity模組化後,統一套用「讀取或導入資料」的流程。

但是很多人只是需要「有個地方取用資料」。

將資料存在Application中後,用getApplication()取出即可......

很合理很有效率的想法!

但假設「不合用」或「不夠用」吧!

那我們就需要考慮一下LifeCycleCallback的用法。



這是個介面,裡面有完整的相對應了所有Activity LifeCycle的函數。

每個Activity的LifeCycle函數中,都會先在super()中執行所有被Application註冊的Callback,然後「才是」設計師複寫的物件內容。(LifeCycle不是建構子,其實設計師可以隨意調整super()執行的位置。)

(注意!是所有被註冊了的Callback都會被執行!)

(再注意!不是只有Application有能力註冊Callback,其他類別也有能力;相對的,也不是只有Application有能力反註冊Callback。因此一個Callback運作的開始和結束是很有彈性的!不會比Service差,但又比Service精準!)



所以假設......純假設.......

Callback中會在onResume啟動一個Thread,然後在onStop中將Thread關閉。(偶爾會發生從某一個Activity A返回前一個Activity時,Activity A的onDestroy會在下一個Activity的onResume之後才運作,這種時候可能會產生意外!如果允許Callback內產生多個Thread,那該關閉哪個Thread可能就是個要頭痛一下的問題了!...不是無解,也不複雜。)

這樣就可以達到讓背景任務可以順利跨Activity運行、而且又能對應當下的Activity產生變化。(例如視頻撥放的功能,可以將Activity視為「視頻線上存放點」的切換或記錄器,而下載功能和下載資料緩存則建立在Callback中,等於達到常駐的效果,而不會隨著每個Activity的啟動或關閉而有資源管理的問題。...這只是初步構想,還沒實驗過。)



再假設......純假設.......

每個Callback類別都有對應的Interface可以讓Activity實作,然後在Application中註冊多個Callback,只是每個Callback在執行對應的生命週期函數以前,都會檢查傳入的Activity是否有實作自己對應的Interface...如果沒有就不執行,那就可以大幅簡化Activity要處理的工作。



但對我來說,這個介面真正實用之處在於它讓一個跨「多Activity」甚至「多APP」的Thread可以精準的知道「何時有Activity可以取用」。

舉例...

就假設要設計個最簡單的APP內建有獨立邏輯和功能的計時器吧!

計時流程如果要精準可靠,那就不能因為Activity切換而損失效能或時間失準。(注意!它有獨特邏輯,所以不是直接把手機時間拿出來顯示就好。)所以不能採用「每個Activity獨立啟動Thread」的做法。

但在UI1中,時間顯示在右上角,在UI2中,顯示在正中央,而UI3卻又顯示在左下角...所以上面說要記得設定一個Interface讓每個Activity設定自己顯時間值的方法,如果有這樣做,就可以將這個Thread寫在一個Callback中,讓Application在產生Acitivity前就先運行這個Thread。



研究完用法思考了一下...

凡事要在背景常駐處理的都寫個Service...會不會對系統負擔太大呢!

畢竟Service是個功能完整的Context!但LifeCycleCallback只是個簡化介面的實作。

如此一來,Android預設的幾個主要功能類別其實就越來越模糊了!遵守Activity、Service、BroadCast...這類的類別去設計規劃APP的架構,可能反而會是個阻礙。

但同樣的理由...當一隻APP背景存在數十個額外設定的Callback時,效能是不是一樣會變差?

所以設計一項服務真的要把各個功能切割成多個APP(其中有一個是所謂的Main APP)來完成,這樣每個APP前景背景都會變得很單純穩定!

2016年5月9日 星期一

使用byte矩陣傳輸資料到NFC Tag

這是在Safari的官網上找到關於NFC資料的技術文件。主要是讓使用者可以在Web中經由Safari瀏覽器啟動Android的NFC功能後,再用byte矩陣自組要傳輸到Tag、或Tag Reader中的資料。

當初研究它的目的是想要可以讓Android手機可以用NFC Beaming功能來隨意模仿成Tag、具有特定ID,讓其他Tag Reader可以感應。

但奮戰了整整一天......最後是徒勞無功。在這裡寫下我的心得。



用Android的NdefRecord中的public NdefRecord (short tnf, byte[] type, byte[] id, byte[] payload)函數,雖然很快有基本的Beaming功能,但送出去的訊息ID遲遲都是0...而且是一個0,而不是一串0!(一個長度只有1的byte[]。)

所以就異想天開用public NdefMessage (byte[] data)的方式來組看看,或許ID顯示為0是NdefRecord物件的問題。




NFC的每一筆資料,稱為Message,可以由多組Record組成。

每一組Record又由RecordHeader和RecordPayLoad組成。

每個RecordPayLoad資料長度上限為2的32次方。除此以外沒有限制。(但似乎也不能為0。)

「文件中」說Header由6~9個程度不等的Byte矩陣組成,為何會有6和9的差異?因為其中有所謂ShortRecord和Non-ShortRecord的差異。如果是ShortRecord,則為6,反之則為9。

(為何要強調「文件中」...等一下解釋。先聲明這是文件中非常不精準的地方。)

RecordHeader中的第一個Byte稱為TNF+Flag(Message Flags),我帶入的是217。

因為一個Byte由八個bit組成,在這個欄位中,每個bit都有自己獨特的意義。而我用的是11011001。每個數字代表著一個bite,所以內容只有0或一,換算成十進位後數值是217。

第四個bit正好決定了這筆Record為ShortRecord或Non-ShortRecord,而我帶入的是1,也就表示「True」,所以PayLoadLength的部分只有一個Byte。要等一下計算玩PlayLoad長度後決定數值。

但如果TNF+Flag(Message Flags)是11001001,就會佔去四個Byte,因為第四個數值是0,也就表示這筆資料不是ShortRecord。(Record的長度是四個Byte或一個Byte的差異。)



開頭是{1,1},因為我的Message中只有一組Record,所以都是Begin兼End,如果是Begin,就是10,如果是End就是01。(假設共有三組Record,則第一組10,第二組00,第三組01。)



第三個0/1是Chunk...還是搞不懂這是什麼東西。

第五個0/1是ID Length,如果0,就表示沒有ID,自然也不需要設定ID Length,RecordHead就少了兩個欄位-----設ID Length的欄位和ID本身。

所以上面要強調「文件中」,因為如果ShortRecord為false,而ID Length又為True,則Header的長度上限絕對不只9個Byte。

第六到第八個0/1是TypeNameFormat,是一組的。三個bit可以表示0~7,而Type剛好有八種組合,Empty/Well-Known/URI.......一般都是用WellKnown和URI。(我帶入其他的數值都失敗。)



到此為止,資料很成功送出去,Read很成功的讀取到了我用這方式所寫入的資料。



但Header除了第一個Byte為TNF+Flag(Message Flags)以外,接著還有Type Length(一個Byte),PayLoadLength,(一或四個Byte,視資料是否為ShortRecord而定,)還有IDLength(一個Byte)。

1.TNF+Flag。(長度1)
2.TypeLength。(長度1)
3.PayLoadLength。(長度1)
4.IDLength。(長度1)

這六個Byte之後是所謂的長度浮動的階段,第一個是PayLoadType,它是一個字串轉換成Byte矩陣形式後插入,長度必須要精準計算後寫入TypeLength欄位中,(所以長度大小自然不能超過255。)但PayLoadType的命名邏輯文件中的解釋很模糊,但始終是那八大類,這只是個用來顯示的字串罷了!

接著就是所謂的ID。不管是數值或字串,它一樣也是轉換成Byte矩陣後計算長度插入,長度要寫在IDLength欄位中。

Activity無法接觸的非主線呈Thread可主動更新Activity內容

會特地寫這篇心得,是因為Handler Leaking一直困擾我。

在Activity可直接控制的範圍內觸發的Thread,可以用Handler.obj的方式來解決。

但如果是Activity完全接觸不到的Thread內,甚至是「第三方APP」內的Thread,這時要怎麼將Thread工作的結果回傳到Activity中?

在Guide文件「Display a location address」中曾經短暫提到的一個物件「ResultReciever」就是被設計來解決這個問題的工具。



問題是按照Google文件一慣的原則,它們完全不認為這種概念需要獨立成一個章節來介紹,仔細查了一下...確實只有這篇Guide文件有提到過這個物件,剩下的就是要進入個別API說明才會發現了。



這東西其實很簡單...

ResultReciever物件是個Parcelable介面的實作,將它當作參數傳入Intent,再經由Intent傳入獨立Thread或IntentService中,就可以在Thread結束時,(似乎是有能力偵測這個線程結束被關閉,)執行使用者實作的onRecieverResult(int code, Bundle data)中的內容。

(若是Activity可以直接控制影響的範圍,大可以直接啟動,不需要經由Intent。談到Intent,自然就是跨Activity,而且兩個Activity之間無法互通互相影響的情況。)



但是我原始的想法是在ActivityA中設置一個Intent Reciever,(通常是BroadCastReciever,)然後讓Activity接觸不到的Thread將工作結果也用Intent回傳。

如果有這個機制,這個方法就顯得很笨重多餘。

2016年4月28日 星期四

【Android】開啟第三方APP

讓APP的內容或服務可以被其他APP開啟跟呼叫,在Android上是很重要的一項功能,──雖然沒什麼人真的在做。

因為技術上它有很多Google進階設計時模糊曖昧的地方!API或文件都沒有精準說明,也沒有範例可以參考。

所以下面的筆記只是個人使用心得,離參考文件還有很長的距離...



在AndroidManifest檔中加入的Activity設定值標籤內,可以再加入intent-filter的標籤。

預備要被第三方APP呼叫的Activity中,必須要在intent-filter標籤內加入額外的參數。(會這樣說是因為基本用法中,除了靠點擊啟動的Activity需要加入main和launcher參數以外,其餘的Activity並不需要加入額外的參數,甚至連intent-filter都可以不需要。)


<intent-filter>
     <action android:name="android.intent.action.SEND"/>
     <action android:name="android.intent.action.VIEW"/>
     <category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
SEND跟VIEW似乎只要擇一加入即可,差別只在於Activity中如果有UI要顯示,「使用」這個Activity的Intent中若是傳入SEND,則這個UI不會被顯示。

Intent intent = new Intent(Intent.ACTION_VIEW);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);//!!!關鍵在這個Flag
intent.addCategory(Intent.CATEGORY_DEFAULT);           
ComponentName cn = new ComponentName("tw.android.demo2", "tw.android.demo2.MainActivity2");           
intent.setComponent(cn);
startActivity(intent);

其實呼叫第三方APP的Activity方法很多,但關鍵應該在於addFlag的動作!

(還沒機會使用到其他型態的Flag,如果有機會用到,會補上結果。)

另外,ComponentName的實體建構子中要傳入兩個參數,一個是第三方APP project名稱,一個則是Activity的完整專案路徑與名稱。

(會強調完整專案路徑與名稱,是因為邏輯上來說,Activity可以分散在多個子project路徑內,例如tw.android.demo2下可以有tw.android.demo2.test,但將Activity放在裏頭,不知道為何AndroidManifest檔內的設定會失敗...一直沒有機會來回頭釐清這一段的正確使用方式和原則。──好像有點本末倒置,不去先釐清更基本的東西,卻在研究比較進階的使用方法。)




另一個奇妙的問題是...當Activity被啟動後,啟動的目的為何?

絕對不是僅僅為了看個UI介面。(有時候會有選單來選擇資料回傳,這時候當然就是要操作UI。但這裡不是指這種情況。)

例如要使用不對外公開的API來跟後台交換資料,這時候就需要建立Thread來完成網路傳輸工作。

奇妙的是...

這種讓第三方啟動的Activity竟然無法在基本生命週期階段中啟動獨立Thread。(寫了個Thread程式,卻無法被啟動,但也沒看到錯誤訊息產生。)

所以這時候就需要使用Service,特別推薦IntentService。(前者可能要等任務完成、關閉Activity後才會跟著關閉,但後者會先在任務完成後關閉自己、同時執行關閉Activity的工作。)



........

怎麼使用IntentService?

別鬧了!去別的地方找資料。

2016年2月22日 星期一

在Android上用座標查詢地址原來這麼簡單!

無意間在StackOverFlow上逛到這篇文章...才知道原來這東西那麼好用!

簡單說:Android預設的物件GeoCoder(點擊可以轉到API)其實就可以幫設計師快速的把這個動作完成!

詭異的是我遲遲沒有找到相關的標準範例!結果原來是因為Google Guide教程中,關於「如何取得GPS座標」的部分已經轉換成使用GoogleApiClient,但後續取得地址的部分...雖然GoogleApiClient也有相關功能,可是在Google Guide中卻還是使用GoeCoder!

(只能說:習慣就好...)



這個物件設計讓我看了要說「好用」的原因...

第一,它直接使用座標,而不是相關系列的物件!

    List<Address> addresses = null;

    try {
        addresses = geocoder.getFromLocation(
                location.getLatitude(),
                location.getLongitude(),
                1);
    } catch (IOException ioException) {
        // Catch network or other I/O problems.
    } catch (IllegalArgumentException illegalArgumentException) {
    }

    
}
(其他時候,Google Guide的範例程式碼很繁雜!但這篇的卻是相較之下精簡,而我上面貼的這段是更精簡。因為這個功能並不需要多做無謂的說明...)


第二,承接第一點,這表示它不需要申請金鑰!在註冊功能上會省去很多手續。(但其實最新的Google Place API For Android在註冊上也很簡單!並沒有多複雜!)

第三,JavaScript的地址查詢API回傳的JSON資料結構非常複雜!

第四,跟Google Place API For Android相比,它可以完全適應自己設計的Thread。因為Google Place API需要使用CallBack,而且如果只是單純的地址查詢,Google Place API並不「精準」,會獲得很多無關的資訊。




補充說明:在Google Place API For Android中獲得PlaceID的方法。

其實就是額外使用JavaScriptAPI去獲得JSON資料而已!

目前這段功能顯然還未有完整物件化。