2016年3月4日 星期五

Android 開發筆記 - 使用 Java Reflection 製作 Event Handler 流程控制

在 Android 上練習一些題目時,有碰到一連串 function call 的需求,特別是把每項工作做成 RISC 架構後,出現了重複使用的可能性,假設有 A, B, C, D 四個函式,有時任務是 A->B->D,有時是 B->C->A 的流程,這時就想找一個可以彈性設置任務流程的機制,有一點像 C/C++ 的 function pointer 或 virtual function 可以動態決定對象的機制,就隨意亂打關鍵字,想知道有沒可能得知 function name 後可以呼叫 function 做事,就找到 Java Reflection :http://docs.oracle.com/javase/tutorial/reflect/member/methodInvocation.html

於是乎,在 Java 環境中透過 ArrayList 記錄此次工作依序將執行的任務,每次挑一個出來用,就達成任務了 :P

紀錄一下(此例各個函式在此例沒有傳遞參數):

class Job {
private String tag = "Job";
private List<String> mFunctionNameList = new ArrayList<String>();

void callFunctions() {
if (mFunctionNameList.size() > 0) {
String methodName = mFunctionNameList.get(0);
mFunctionNameList.remove(0);
try {
Job.this.getClass().getDeclaredMethod(methodName).invoke(this);
} catch (Exception e) {
}
}
}

// call A -> C -> D
void task1() {
mFunctionNameList.clear();
mFunctionNameList.add("A");
mFunctionNameList.add("C");
mFunctionNameList.add("D");
callFunctions();
}

// call B -> C -> A
void task2() {
mFunctionNameList.clear();
mFunctionNameList.add("B");
mFunctionNameList.add("C");
mFunctionNameList.add("A");
callFunctions();
}

void A() {
Log.d(tag, "call A");
}
void B() {
Log.d(tag, "call B");
}
void C() {
Log.d(tag, "call C");
}
void D() {
Log.d(tag, "call D");
}
}

Android 開發筆記 - 從 Java 端傳遞 HashMap 物件 Android NDK/ JNI C/C++ 操作變更內容

C/C++ Code:

#include <jni.h>

extern "C" {

jobject Java_YourPackageName_updateHashMap(JNIEnv *env, jobject thiz, jobject hashmap) {
    if (!hashmap)
        return hashmap;

    jclass mapClass = env->GetObjectClass(hashmap);
    jmethodID obj_put = env->GetMethodID(mapClass, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");

    if (mapClass && obj_put) {
        jstring key = env->NewStringUTF("Haha");
        jstring value = env->NewStringUTF("Hehe");
        env->CallObjectMethod(hashmap, obj_put, key, value);
        env->DeleteLocalRef(key);
        env->DeleteLocalRef(value);
    }

    return hashmap;
}
}


Android Java code:

public native HashMap updateHashMap(HashMap<String, String>map);
static {
        System.loadLibrary("native");
}

void usage() {
HashMap<String, String> mHashMap = new HashMap<String, String>();

        Log.d(tag, "HashMap size: "+mHashMap.size());
updateHashMap(mHashMap);
        Log.d(tag, "HashMap size: "+mHashMap.size());

        Iterator it = mHashMap.entrySet().iterator();
        while (it.hasNext()) {
            Map.Entry pair = (Map.Entry)it.next();
            Log.d(tag, "HashMap key: ["+pair.getKey()+"], value: ["+pair.getValue().toString()+"]");
        }
}

Android 開發筆記 - 使用 Android NDK / JNI 回傳 HashMap 物件至 Java 端

C/C++ Code:

#include <jni.h>

extern "C" {

jobject Java_YourPackageName_getHashMap(JNIEnv *env, jobject thiz) {

    jclass mapClass = env->FindClass("java/util/HashMap");
    jmethodID obj_init = env->GetMethodID(mapClass, "<init>", "(I)V");
    jmethodID obj_put = env->GetMethodID(mapClass, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
    jobject hashMap = env->NewObject(mapClass, obj_init, 1);

    /*
    const char * input_data = "HelloWorld";
    int input_data_length = strlen(input_data);

    jbyteArray data = env->NewByteArray(input_data_length);
    env->SetByteArrayRegion(data, 0, input_data_length, (const jbyte *)input_data);
    env->CallObjectMethod(hashMap, obj_put, (jbyteArray)data, (jbyteArray)data);
    env->DeleteLocalRef(data);
    */
    jstring key = env->NewStringUTF("Hello");
    jstring value = env->NewStringUTF("World");
    env->CallObjectMethod(hashMap, obj_put, key, value);
    env->DeleteLocalRef(key);
    env->DeleteLocalRef(value);

    //env->DeleteLocalRef(hashMap);
    return hashMap;
}

}


Android Java code:

public native HashMap getHashMap();
static {
        System.loadLibrary("native");
}

void usage() {
HashMap<String, String> mHashMap = getHashMap();

        Log.d(tag, "HashMap size: "+mHashMap.size());
        Log.d(tag, "HashMap data with key(Hello): "+mHashMap.get("Hello"));
        Iterator it = mHashMap.entrySet().iterator();
        while (it.hasNext()) {
            Map.Entry pair = (Map.Entry)it.next();
            Log.d(tag, "HashMap key: ["+pair.getKey()+"], value: ["+pair.getValue().toString()+"]");
        }
}

設定 Nginx 透過 proxy_pass 存取 Apache web server + SVN + DAV 服務 @ Ubuntu 14.04

這個故事是這樣的,當所有的 server deploy 都用預設用 nginx 後,有個成員跳出來說要用 SVN over HTTP 服務時,就發現必須架設 Apache Web server ,因為 SVN over HTTP 的相關模組就只有 Apache Web server 才有,所以就變成此況的窘境了。

總之,架設 Apache web server 很容易,而安裝 mod_dav_svn 也差不多:

$ sudo apt-get install subversion libapache2-mod-svn apache2
$ sudo vim /etc/apache2/ports.conf
從 Listen 80 改成 Listen 8000,避開跟 Nginx 預設 80 port 衝到
$ sudo vim /etc/apache2/sites-available/000-default.conf
從 <VirtualHost *:80> 改成 <VirtualHost *:8000>
$ sudo a2enmod dav_svn authz_svn
$ sudo vim /etc/apache2/conf-available/svn.conf
<Location /svn>
        DAV svn
        SVNParentPath /path/svn
        AuthzSVNAccessFile /path/svn_access
        AuthType Basic
        AuthName "Web svn"
        AuthUserFile /path/svn_auth
        Require valid-user
</Location>
$ sudo service apache2 restart


接著設定 Nginx:

location /svn/ {
proxy_pass http://127.0.0.1:8000/svn/;
}

# 更新:假設 svn repo 裡有 .ht 開頭的檔案,可能會被 nginx 條件擋下
location ~ /svn/.*\.ht {
proxy_pass http://127.0.0.1:8000/;
}


如此一來即可搞定。

2016年2月29日 星期一

關閉 Android Transfer 自動開啟服務 @ Mac OS X 10.11.3

好一陣子,每次手機插上 Mac OS X Usb 後,就會自動彈跳 Android Transfer ,有些不方便 :P 解法就是關閉相關程式,例如重新命名:

$ kill `pgrep "Android File Transfer Agent"`
$ cd $HOME/Library/Application\ Support/Google/Android\ File\ Transfer && mv Android\ File\ Transfer\ Agent.app/ Android\ File\ Transfer\ Agent-DISABLE.app/
$ cd /Applications/Android\ File\ Transfer.app/Contents/Resources/ && mv Android\ File\ Transfer\ Agent.app/ Android\ File\ Transfer\ Agent-DISABLE.app/


之後,有需要 Android Transfer 時,就自行去點擊開啟他吧!