2015-12-18

[Golang] 用Go (golang) 寫Web Server! 使用go-restful package. Hello go-restful!

1. 安裝go
https://golang.org/doc/install
https://golang.org/dl/

    *如果有安裝舊版的要先移除
    *Mac版的pkg只要抓下來執行一直按下一步就安裝好。
        他會幫你把go安裝在/usr/local/go,
        並把/usr/local/go/bin加到環境變數PATH當中。
        記得要把Terminal關掉重開才會吃到新的PATH。

2.  準備一個HelloWebServer的Workspace
        1. 新增一個資料夾當作這個程式的Workspace, ex. ~/HelloWebServer/
        2. 把這個folder path加入環境變數,
             ex. 執行 $ export GOPATH=$HOME/HelloWebServer
        3. 在work folder底下加入src/HelloWebServer/hellowebserver.go
            內容為

2015-11-12

[Mokito] 使用Mokito寫測試的筆記 (Note for writing test cases by Mokito)


Test Class Template
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricGradleTestRunner;
import org.robolectric.annotation.Config;

import static android.os.Build.VERSION_CODES.LOLLIPOP;

@Config(sdk = LOLLIPOP, constants = BuildConfig.class)
@RunWith(RobolectricGradleTestRunner.class)
public class MyTest {

    // something to mock
    @Mock TypeA A;
    @Spy TypeB B = new TypeB();
    // ...

    // Set up
    @Before public void setUp() throws Exception {
        initMocks(this);    // create mock objects, ex. A and B above
        // ... do so other init things
    }

    // Tear down
    @After public void tearDown() {
        // ... do so tear down things
    }

    // Test Case (which should not throw exception)
    @Test public void testCase1() throws Exception {
        // do something
    }

    // Test Case (expect exception)
    @Test(expected=YouExceptException.class) public void testException1() {
       // something would throw YouExceptException.class exception
    }

    // Test Case (expect exception)
    @Test public void testException2() throws Exception {
        try {
            // something should throw exception
            // import org.assertj.core.api.Assertions;
            Assertions.failBecauseExceptionWasNotThrown(YouExpectException.class);
        } catch (YouExpectException e) {
        }
        // verify other things here
    }

    // Test Case (with timeout)
    @Test(timeout=100) public void infinity() {
       // something should not run longer than 100ms
    }
    
}

2015-11-02

[Android][RxJava] Run something async on non-UI thread, then back to MainThread to do something after that.


當你有某些東西要Async地在background、而且是non-UI thread運作
(例如:Android要連接網路Network、http之類的時候)

但是做完又要回到Main Thread
(例如:從網路or anywhere拿到資料之後要更新UI)

就可以用以下的Pattern來寫


Async.fromCallable(new Callable() {
    // T is the type you want to send back to MainThread
    @Override public T call() throws Exception {
        // do something that you want it async run on Schedulers.io()
        return [object in type T];
    }
}, Schedulers.io())  
// specify the thread you want async work to run on it, here we use Schedulers.io()

    .observeOn(AndroidSchedulers.mainThread())  // then back to MainThread
    .subscribe(new Subscriber() {
        // run on MainThread
        @Override public void onCompleted() {

        }

        @Override public void onError(Throwable e) {

        }

        @Override public void onNext(T obj) {

        }
    });

2015-10-29

[Android] an Text search Adapter for AppCompatAutoCompleteTextView or AutoCompleteTextView

這是一個可以自動完成的TextView(AutoCompleteTextView)所需要的Adapter

原本的ArrayAdapter的自動完成只會搜尋到以已輸入的字串為開頭的字串。
(因為ArraryAdapter的Filter是用startWith去找字串)
例如:List當中有"安全"、"安心"、"保安"、"偏安"、"討厭"
輸入"安",只會搜尋出"安全"、"安心"
而"保安"、"偏安"就搜尋不到
"討厭"也是一樣搜尋不到

以下這個改寫過的Adapter則是只要有包含已輸入的字串都會顯示出來。
例如:List當中有"安全"、"安心"、"保安"、"偏安"、"討厭"
輸入"安",會搜尋出所有有"安"的String"安全"、"安心"、"保安"、"偏安"
而"討厭"裡面沒有"安"所以就搜尋不到



Usage:
AppCompatAutoCompleteTextView mAutoCompleteText;
List<String> list;

// find view by id
// ...

mAutoCompleteText.setAdapter(new AutoCompleteAdapter(getContext(),
            android.R.layout.simple_spinner_item, list));


2015-09-11

[Android] 如何改變DatePicker的Divider的顏色 (How to change the divider color of the DatePicker)


這是一個可以自己從xml指定Divider的顏色的DatePicker

可以把像下圖這樣的Spinner DatePicker的Divider從藍色換成別的自己指定的顏色
We can change the divider color of DatePicker from blue to any other color you want.



首先要先在resource的drawable當中加入一個shape
把"THE_COLOR_YOU_WANT"換成你想要的顏色

2015-08-04

[Android] 字串比較的兩種方式的比較 Comparison of Two ways of String Comparison: TextUtils.equals() and String.equals()


字串比較的兩種方式的比較
Comparison of Two ways of String Comparison:

TextUtils.equals() and String.equals()

[Android] 檢查參數Check arguments: Preconditions.checkArgument(), checkNotNull()



http://docs.guava-libraries.googlecode.com/git-history/release/javadoc/com/google/common/base/Preconditions.html

[Java] String.valueOf() 和 Integer.toString(), Long.toString, Double.toString的差異. 為何String.valueOf()比較好?Why String.valueOf() is better than toString()?



為何String.valueOf()比 Integer.toString(), Long.toString, Double.toString好?
Why String.valueOf() is better than toString()?

1. If a value is null.

toString() would throw NullPointerException.
String.valueOf() would return a String "null".

當輸入值為null, String.valueOf()不會發生Exception.

2.
像這樣的一個function
public String example1(int num, boolean boo) {
 return Integer.toString(num) + Boolean.toString(boo);
}

如果參數的type改變了, 那麼implemention就也要跟著改變
If the type of num and boo is changed, the the implementation have to change depends on the type of num and boo.

但如果使用String.valueOf() 那麼就不用改變implementation了

像下面這個function, 就算參數的type一直改, function implementation也都不用改
You don't have to change implementation when the type of num and boo is changed.

public String example2(int num, boolean boo) {
  return String.valueOf(num) + " " +  String.valueOf(boo);
 }

3.

2015-06-27

[Android] 從鈴聲的URI取得鈴聲的標題名稱. Get ringtone title from ringtone uri




String getRingtoneTitle(String ringtoneUriString) {
    
    String defaultRingtoneTitle = "No Ringtone";
    Uri ringtoneUri = null;
    try {
        ringtoneUri = Uri.parse(ringtoneUriString);
    } catch (Exception ignored) {
        Logcat.w(ignored, "Settings parse notification ringtone uri fail."
            + "ringtoneUriString = ", ringtoneUriString);
    }
    if (ringtoneUriString.isEmpty() || ringtoneUri == null) {
        return defaultRingtoneTitle;
    }
    Context context = getContext();
    Ringtone ringtone = RingtoneManager.getRingtone(context, ringtoneUri);
    if (ringtone == null) {
        return defaultRingtoneTitle;
    }
    return ringtone.getTitle(context);
}

[Android] 如何設定"提醒"的聲音、閃光、震動形式. How to set the Sound, Lights, and Vibrate of a Notification

If you don't want any ringtone, don't set Notification.DEFAULT_SOUND to setDefault(), and don't call setSound(ringtoneUri) of NotificationCompat.Builder.

 If you just want default ringtone, call setDefault(Notification.DEFAULT_SOUND);

 If you just want default vibrate, call setDefault(Notification.DEFAULT_VIBRATE);

 If you just want default lights, call setDefault(Notification.DEFAULT_LIGHTS);

If you need a custom ringtone, call setSound(ringtoneUri), but don't call setDefault(DEFAULT_ALL) or setDefault(DEFAULT_SOUND).
Because setDefault(DEFAULT_ALL) or setDefault(DEFAULT_SOUND) make setSound(ringtoneUri) useless.

Check here about how to use Ringtone Picker to get a ringtone Uri.
http://codeviki.blogspot.tw/2015/06/android-show-ringtone-picker-activity.html

Check here about how to get ringtone title from ringtone Uri.
http://codeviki.blogspot.tw/2015/06/android-get-ringtone-title-from-ringtone-uri.html


static Notification buildNotification(
 boolean vibrateEnabled,
 boolean lightsEnabled,
 String ringtoneUriString)
{
 int defaults = 0;

 // set vibrate to defaults
 if (vibrateEnabled) {
  // use default vibrate pattern
     defaults |= Notification.DEFAULT_VIBRATE;
 }

 // set lights to defaults
 if (lightsEnabled) {
     // use default light blink pattern
     defaults |= Notification.DEFAULT_LIGHTS;
 }

 // parse ringtone
 Uri ringtoneUri = null;
    try {
        ringtoneUri = Uri.parse(ringtoneUriString);
    } catch (Exception ignored) {
        Logcat.w(ignored, "Parse notification ringtone uri fail. "
            + "ringtoneUriString = ", ringtoneUriString);
        // if parse ringtone fail, use default ringtone
        defaults |= Notification.DEFAULT_SOUND;
    }
 
 NotificationCompat.Builder builder =
     new NotificationCompat.Builder(context)
         .setSmallIcon(R.drawable.my_notification_icon)
         .setContentTitle("title")
         .setContentText("contentText")
         .setAutoCancel(true)
         .setDefaults(defaults);

 // if ringtoneUriString is empty string, the uri won't be null
    if (!ringtoneUriString.isEmpty() && ringtoneUri != null) {
     builder.setSound(ringtoneUri);
 }

 return builder.build();
}

[Android] 顯示讓使用者選擇鈴聲的對話方塊. Show Ringtone Picker Activity

// just define a unique int for this ringtone picker activity
public static final int RINGTONE_PICKER_REQUEST = 10;

void showRingtonePicker() {
    Intent intent = new Intent(RingtoneManager.ACTION_RINGTONE_PICKER);
    intent.putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, RingtoneManager.TYPE_NOTIFICATION);
    intent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_DEFAULT, true);
    intent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_SILENT, true);
    Activity activity =getActivity();
    if (activity == null) {
        return;
    }
    try {
        activity.startActivityForResult(intent, RINGTONE_PICKER_REQUEST);
    } catch (ActivityNotFoundException ignored) {
        Logcat.e(ignored, "Settings showRingtonePicker error");
    }
}
To get the result of ringtone picker, override onActivityResult in Activity.
@Override public boolean onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode != RINGTONE_PICKER_REQUEST || resultCode != Activity.RESULT_OK) {
        return false;
    }
    Uri ringtoneUri = data.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI);
    // if user choose "no ringtone" in the ringtone picker, the ringtoneUri would be null.

    String ringtoneUriString = "";
    if (uri != null) {
        ringtoneUriString = uri.toString();
    }
    
    // TODO : save the ringtoneUri or ringtoneUriString to anywhere you want
    
    return true;
}

2015-05-18

[Android] 讀取放在專案內的assets資料夾中的檔案到一個String變數當中. Read files in assets to String



If we have a file named "licenses.html" under [your project]/src/main/assets/ ,
you can use the following function to read its content to a String.

String readLicensesHtml() {
    StringBuilder buf = new StringBuilder();
    InputStream stream;
    BufferedReader in;
    String str;
    try {
        stream = getAssets().open("licenses.html");
        in = new BufferedReader(new InputStreamReader(stream, "UTF-8"));
        while ((str = in.readLine()) != null) {
            buf.append(str);
        }
        in.close();
    } catch (IOException ignored) {
        Log.e(DEBUG_TAG, ignored.getMessage(), ignored);
    }
    return buf.toString();
}



[Android] 在AlertDialog當中顯示HTML格式的字串. Show HTML String in a AlertDialog


Show HTML String in a AlertDialog.

But not all html tag is supported.
See HTML tags supported by TextView.
https://commonsware.com/blog/Android/2010/05/26/html-tags-supported-by-textview.html


/**
 * Show HTML String is AlertDialog
 */
static void showHtmlDialog(Context context, String title, String htmlString) {
    new AlertDialog.Builder(context)
            .setTitle(title)
            .setMessage(Html.fromHtml(htmlString))
            .setPositiveButton(android.R.string.ok, null)
            .show();
}



Usage :
showHtmlDialog(this, "This is HTML", "<html><body>This is HTML</body></html>");

[Andoird] 在Android Studio的專案中使用Robolectric做測試. Add Robolectric to an Android Studio Project


Reference:

Robolectric Homepage
http://robolectric.org/getting-started/

A good Tutorial of Setting up Robolectric
https://github.com/codepath/android_guides/wiki/Robolectric-Installation-for-Unit-Testing



1. modify the Top-level build.gradle.
Add robolectric gradle plugin to dependencies.

dependencies {
        ...

        classpath 'org.robolectric:robolectric-gradle-plugin:1.0.1'
    }


2. modify the app-level build.gradle.
Add following line

apply plugin: 'org.robolectric'

...

dependencies {
    ...

    testCompile 'junit:junit:4.12'
    testCompile 'org.robolectric:robolectric:2.4'
 
}


3. Add test file under [Your Project]/app/src/test/[test files]
The test folder is at the same level with the "main" folder.

4. Write the test files

import org.junit.Test;
import org.junit.runner.RunWith;

import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;

@Config(emulateSdk = 18)
@RunWith(RobolectricTestRunner.class)
public class TestFile {

    @Test
    public void testIt() {
        // failing test gives much better feedback
        // to show that all works correctly ;)
        assertEquals(false, true);
    }
}

5. run the test command "./gradlew test" to run test



2015-05-17

[Android] 動態改變GridView的欄位個數的方法. Change the numColumns of GridView at run time


This is how to change the number of columns of a GridView at run time.


int GRID_ITEM_WIDTH = 300;  // the rough width of the grid item.

mGridView = (GridView) findViewById(R.id.gridView);
mGridView.getViewTreeObserver().addOnGlobalLayoutListener(
    new ViewTreeObserver.OnGlobalLayoutListener() {
        boolean isFirst = true;
        @Override
        public void onGlobalLayout() {  // this callback called when the width of view is available
            if (isFirst) {  // this callback would be called several times, run the following code only at the first time it called
                isFirst = false;
                int width = mGridView.getWidth();
                int numColumns = 1;
                
                if(width > GRID_ITEM_WIDTH){
                    numColumns = width/GRID_ITEM_WIDTH;        
                }
                mGridView.setNumColumns(numColumns);
            }
        }
    }
);



[Android] 使用Picasso來解圖到Bitmap. Decode an Image to Bitmap by Picasso


This is how to decode an image to Bitmap by Picasso.

Picasso is a library for downloading and cashing image.
Reference:
http://square.github.io/picasso/



import android.graphics.Bitmap;
import com.squareup.picasso.Picasso;

String mImgUrl = "http://url.to.your.image.on.internet";
Bitmap bm = Picasso.with(mContext)
                        .load(mImgUrl)
                        .get();





[Android] 由圖片網址解圖為Bitmap. Decode an Image to Bitmap by its URL on internet


This is how to decode an image to Bitmap by its URL on internet.


import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import java.io.InputStream;
import java.net.URL;

String mImgUrl = "http://url.to.your.image.on.internet";
Bitmap bm = BitmapFactory.decodeStream((InputStream) new URL(mImgUrl).getContent());



[Android] 範例: 使用SQLiteOpenHelper以及UriMatcher的ContentProvider. A simple example of ContentProvider which uses SQLiteOpenHelper and UriMatcher

This is a simple example of ContentProvider which uses SQLiteOpenHelper to create a database.


1.  Define a Database Contract.
It contains the following information about a Database.
(1) Authority
(2) Table names
(3) column names of each Table
(4) content Uri

[Android] 讀寫SharedPreference. Read and Write SharedPreference

This is a simple note for reading and writing Android SharedPreference.

Reference:
https://developer.android.com/guide/topics/data/data-storage.html#pref
https://developer.android.com/reference/android/content/SharedPreferences.html



1. define a name for the SharedPreference file

public static final String PREFS_NAME = "MyPrefsFile";


2. define a name for each column of the SharedPreference

public static final String PREFS_KEY_BOOLEAN_SILENT = "silentMode";

3. Read data from SharedPreference

// Read preferences
SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);
boolean silent = settings.getBoolean(PREFS_KEY_BOOLEAN_SILENT, false);

4. Write data to SharedPreference

boolean mSilentMode = true;

// Write preferences
SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);
SharedPreferences.Editor editor = settings.edit();
editor.putBoolean(PREFS_KEY_BOOLEAN_SILENT, mSilentMode);
/* put other columns to SharedPreference before commit */
// Commit the edits!
editor.commit();





[Java] 解讀JSON格式的字串. Parse JSON String

This is example code to parse JSON String by Java.


import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;


String jsonString;

/* Put you JSON String to jsonString */

JSONArray myJsonArray = null;
try {
    myJsonArray = new JSONArray(jsonString);
} catch (JSONException ignored) {
    Log.e(DEBUG_TAG, "json parse Error!!");
    return;
}


for (int i = 0; i < myJsonArray.length(); i++) {
    try {
        // get each element of the array
        JSONObject oneObject = myJsonArray.getJSONObject(i);
        if (oneObject == null) {
            continue;
        }
        
        // get items from the element...
        String column01 = oneObject.getString("column01");
        String column02 = oneObject.getString("column02");
        JSONArray column03 = oneObject.getJSONArray("column03");
        
        /* do something  */

    } catch (JSONException ignored) {
        Log.e(DEBUG_TAG, "json parse Error!!");
    }
}




[Android] 從網路下載資料到字串. Download a String from internet

This is a Util class to download a string from internet.

Usage:
ConnectivityManager connMgr = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
String myString = Utils.downloadUrl("http://change.this.to.your.url", connMgr);

2015-05-16

[Blogger] 讓文章圖片看起來像縮圖相簿(Make images in Blogger post look like thumbnail album)



想要把Blogger的Post內的圖片都變成像下面這樣好像是一個縮圖相簿的感覺的話。
按照以下步驟就可以囉!



搭配上Blogger的"在燈箱中展示圖片功能",
就可以讓Blogger Post看起來像是縮圖相簿了!




2015-05-15

[Android] 使用RecyclerView和CardView做出一個格狀圖片瀏覽器. Use RecyclerView and CardView for a Grid Image Viewer


This is a Grid image viewer to view images from internet.
You could change it to view image resources or files yourself.

It uses Picasso to load images.
http://square.github.io/picasso/



1. add dependencies to build.gradle
dependencies {
 ...
    compile 'com.android.support:recyclerview-v7:21.0.3'
    compile 'com.android.support:cardview-v7:21.0.3'
}


2. Activity member variable
private static final int GRID_COLUMN = 3;
private RecyclerView mRecyclerView;
private GridAdapter mAdapter;