Cody Blog

Software development

Parsing JSON string in Android

Given a json string, you could convert it to either JSONObject(str) or JSONArray(str). For example, This json response is from weather forecaset server:

http://api.openweathermap.org/data/2.5/forecast/daily?zip=545%2Ctw&mode=json&units=metric&cnt=7&appid=aa032e548c67daa9cd1bc64eec737960

The response json format is like this:

json

If you want to get the first max temperature value: 17.06:

    JSONObject weather = new JSONObject(weatherJsonStr);
    JSONArray daysWeather = weather.getJSONArray("list");
    JSONObject dayWeather = daysWeather.getJSONObject(0);
    JSONObject dayTemperature = dayWeather.getJSONObject("temp");
    int maxTemp = dayTemperature.getDouble("max");

Note that there may has a JSONException when the json tring ...

How to storing api keys in Android

You SHALL not save api key into version control system, but how can you manage your API keys?

There are some approaches had been discussed here. One is to saving the api key in gradle.properties. Before add secret to this file. you need add gradle.properties to .gitignore file. If you already commited this file to your git. remove gradle.properties from git first by this command:

git rm --cache gradle.properties

Next, Open your gradle.properties and appmend a new line:

yourapikey="THIS IS API TOKEN"

Modify build.gradle and add buildConfigField for your api key

android {
    compileSdkVersion ...

Permission model in Android 6.0

在 Android 6.0 之後,有了新的 permission model, 安裝 App 的權限可以不用在 Google Play 安裝的時侯就授權。而是等到使用者要使用這個功能的時侯,再詢問使用者。而權限分成兩種: normal permission 跟 dangerous permission 兩種。 normal permission 可以直接在 AndroidManifest.xml 直接定義,不會詢問使用者就可以直接取得權限,像是android.permission.INTERNET權限就屬於此類,主要是跟使用者的隱私比較無關的功能。如果想使用權限是屬於那一類的話,可以參考這個清單

檢查權限

首先都要先檢查是否有這個權限:

ContextCompat.checkSelfPermission(Context context, String permission)

例如,檢查是否有寫入行事曆的權限

ContextCompat.checkSelfPermission(thisActivity, Manifest.permission.WRITE_CALENDAR);

回傳值有兩種可能: PERMISSION_GRANTED(0)PERMISSION_DENIED(-1)

範例程式1: 請求單一權限

private static final int REQUEST_PERMISSION = 1;

private boolean checkPermission() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        final String permission = Manifest.permission.PERMISSION_YOU_WANT;
        if (checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) {
            if (shouldShowRequestPermissionRationale(permission)) {
                AlertDialog.Builder builder = new AlertDialog.Builder(this ...

Send HTTP Request in Android

In the most of time, you could just use HTTP library like Volley or OkHTTP. If you want to use native Android function call for some reasons, you should use HttpURLConnection. HttpClient has been deprecated since Android 6.0(sdk 23).

For HttpURLConnection , there is an excellent code snippet on here

Note Android don't allow network request happened on main UI thread. If you did this, a android.os.NetworkOnMainThreadException exception will be thrown out. Put them in AsyncTask or Service instead.

Build url:

urlBuilder.scheme("http");
urlBuilder.authority("api.openweathermap.org");
urlBuilder.appendEncodedPath("data/2.5/forecast/daily ...

初級日文學習回顧

a-1

學一個新的語言

今年7月到9月,我到了東京長沼日本語學校學習初級日文。除了上課的200個小時,加上課餘復習,這3個月的時間我至少投入了400小時在日文學習上。

第一次到外國學語言,也是第一次我在國外住了3個月。語言學校學習的好處就基本上整天都是全日語的環境。因為我們是初級班,大家會的日文很有限,一開始的下課,大家還是都用英文來聊天,但隨著學習到的日文愈來愈多,也就發現大家慢慢可以用日文來溝通了。

到語言學校學習可以很容易進入說日語的環境。學習新語言的過程其實就是要不斷的模仿、犯錯、修正。而語言學校則是一個安全、比較沒有壓力的環境,例如學到購物的日文時,就可以到學校的咖啡廳練習。在有系統的教學框架下按步就班學習,絕對會自己在學來得有效率。

不過上語言學校最大的缺點就是很貴。但換個角度想,也是因為自己投入了這些金錢跟時間。代表自己有這個決心來學習一個新的語言。所以我的心態就是既然來了,就好好學習,不要浪費。一個月約2萬5台幣的學費,換算下來每一堂課大約是400台幣的學費。班上的部份同學會在課堂上睡覺、或者是翹課。我是覺得蠻可惜的,也可能是因為花的不是自己的錢,所以比較無所謂吧。最後3個月下來,我每堂課都有出席。

record

最後學期成績順利過關(70分及格)

成績

到志工會話教室學日文

vulunteer

除了語言學校,我也有到日文教室上課。日本各地有志工的日本語教室(ボランティア日本語教室)可以參加。基本上都是免費,或是付場地費幾百塊日幣,就可以跟日本人會話交流,練習在語言學校學到的內容,也可以交到除了語言學校以外的朋友。我的小組是一位日本老師,跟一位日本女大學生的助教。學生則是有來自澳洲、印度等地的學生。

vulunteer

日本語長沼學校初級班 資訊分享

簡介

位於東京澀谷的日本語長沼學校是東京是最有名的語言學校之一。長沼學校創立於1948年,至今有近70年左右的歷史。

我上的日語綜合課程中的最基礎的課程,也就是從50音開始教起的初級班。班上有些同學是連五十音都不會就來上課。因為老師都有受過專業訓練,所以即使班上同學很多連50音都不會,也都可以進行全日語的授課。老師會透過手勢、表情表達、道具來教學,如果日文完全不會也不用擔心。

這次我是使用了短期滯在的90天簽證入境日本,一共上了三個月的課程。我把一些學校的資訊記錄在這邊,供未來有興趣到長沼學日文的同學參考。

如何報名

  1. 填寫長沼線上的表單
  2. 收到學校承辦人員的回覆之後,會傳送填寫個人資料檔案,再用電子郵件回傳回去。
  3. 學校承辦人員會寄匯款請求書,再拿這個請求書到銀行匯款即可。

基本上要報名長沼的話,可以不用透過代辦,因為長沼校方有懂中文的窗口,如果不會日文的話,可以透過 Email 直接用中文跟校方聯繫。

關於學費

會有課本學費二筆費用,以短期三個月為例:

  1. 初級班課本的費用約8千多日幣

  2. 單一學期三個月的學費約25萬日幣左右,其它課程費可參考官網

tuition

初級教材

長沼的初級課程是採用學校自編的教材「いつでもどこでも話せる日本語(隨時隨地開口說日語」: 課本

其實這本書,台灣大新出版社也有出版,不過跟我在日本上課的版本不一樣,學校在今年七月出了新版的課本。

  1. 課本: 包含上課會使用到會話、文型、單字,另外有提供會話的 MP3 檔案給同學下載
  2. 單字文法書: 依照學生的母語,有英文、繁體中文、簡體中文... 等版本可供選擇
  3. 作業本: 因為每天都有作業,用活頁夾的方式,方便把前一天作業抽出來交給老師批改

入學考試

長沼的班級分成上午班(9:00~12:30)下午班(13:30~17:00),一般是上午班比較熱門,因為下午可以安排其它的事情,像是打工或是出遊等等。長沼在報名的時侯沒辦法保證是上午班或是下午班。上午班跟下午班的名單基本上是按照入學考試後分班順序。所以如果偏好上午班的話,第一天記得要提早到學校。表定是上午9點~11點報到,但是如果想挑上午班或是下午班的話,建議當天8點半前就到學校 ...

Notes of using Django in Azure App Service

DebugConsole

There is an debug conolse that you can exectue some commands for Django related tasks. The debug console is:

https://{YOUR_PROJECT_NAME}.scm.azurewebsites.net/DebugConsole

Migrate django database in Azure

  1. Go to D:\home\site\wwwroot directory

  2. Exceute migrate command

    D:\home\site\wwwroot> .\env\Scripts\python.exe manage.py migrate

Create super user

echo "from django.contrib.auth.models import User; User.objects.create_superuser('admin', 'admin@email.com', 'your_password')" | python manage.py shell

Adjest timezone

Go to azure portal,

WEBSITE_TIME_ZONE

Set ...

使用 linphone 函式庫發生 exc_bad_access 的除錯經驗

exc_bad_access

在叫用 linphone 的函式庫時,發生 exc_bad_access的錯誤,因為這個錯誤往往發生的地方跟掛掉的地方是不一樣的,所以比較難除錯。

EXC_BAD_ACCESS

是因為對已經釋放的記憶體進行了非法操作,程式會直接 Crash,無法用 error handle catch 來處理。

exc_bad_access

Crash 片段

zombie

記錄發生 crash 的地方不只有一處,共同的特色就是都是掛在 linphone 的函式庫:

發生位置1 linphone_core_iterate():

@objc func iterate(){
    let lc = LinphoneManager.getLc()
    if  lc != nil{
        linphone_core_iterate(lc); /* first iterate initiates registration */
    }
}

發生位置2 linphone_core_iterate():

if let phone = phoneNumber, lc = LinphoneManager.lc {
    nameLabel.text = calleeName!
    linphone_core_invite(lc, phone)
}

透 Debug build 測試

因為預設從 linphone 網站下載的 iphone sdk 是沒有 debug symbol 的,所以在發生 crash 的時侯,只能看到看組合語言: acc EXC_I386_GPFLT

雖然有 linphone 的函式名稱,但是對於問題的幫助不。所以我就直接 build 一個 有 debug symbol 的 liblinphone-sdk,build debug sdk 步驟記錄在另一篇

經過有 debug build 的協助之後, crash 的資訊從原本的組合語言變成了 c 語言 ...

Build liblinphone-sdk for iOS

Install git, homebrew

install git, homebew if you have no one.

Clone ios-linphone

$ git clone git://git.linphone.org/linphone-iphone.git --recursive

Remember add --recursive to download submodule

Excute .prepare.py

$ ./prepare.py

You may need execute this command many time until you install all dependecies.

In my case, I installed these tools:

$ brew install imagemagick doxygen cmake intltool yasm automake coreutils wget optipng nasm 
$ brew install intltool

If it works, you will get the following message:

-- Configuring done
-- Generating done
-- Build files have been written to: /Users/cwliu/Dev@Local/WiAdvance/1603_GoodWox/liblinphone/linphone-iphone/WORK/ios-armv7/cmake
INFO: You ...

Using Haneke for Image Cache in Swift

如果要在 iOS 上,圖片是從網路下載回來的話,勢必要需要做快取,以避免每一次顯示都要重新載入,今天要介紹一套叫 Haneke的 Swift Library, Haneke 是使用 extension 的方法讓 UIImageView 多了一些方法可以做快取。

首先, 安裝可以透過 CocoPods,這邊不多詳述。使用之前記得要先 import:

import Haneke

如果想顯示一張網路上的圖片: http://i.imgur.com/thfn9Ml.jpg,最簡單用法就是

imageView.hnk_setImageFromURL("http://i.imgur.com/thfn9Ml.jpg")

它就會幫你做完下載、快取、重載的動作,相當的方便。另外,若想刪除所有的 image ache,可執行:

Haneke.Shared.imageCache.removeAll()

另外比較進階的用法,像是有一些圖片需要帶 HTTP Header 才有權限存取的話,這邊以加一個 Authorization 的 header 為例,先新增一個自訂的 NetworkFetcher

public class BearerHeaderNetworkFetcher<T: DataConvertible> : NetworkFetcher<T> {

    var token: String

    public override var session : NSURLSession {
        let configuration = NSURLSessionConfiguration.defaultSessionConfiguration()
        configuration.HTTPAdditionalHeaders = [
            "Authorization": self.token
        ];

        return NSURLSession(configuration: configuration)
    }

    override init(URL : NSURL) {
        self.token ...