星期三, 3月 02, 2016

簡介透過GCM達成推播功能 (二)

如何取得Sender ID?


進入Google developers console並登入帳號。
如果此帳戶有已建立的專案,登入後會看到已建立的專案的資訊。
如果此帳戶無建立任何專案,登入後會看到建立專案的資訊。

建立專案
專案名稱欄位那填入專案名稱,此名稱由開發人員自訂。


取得Sender ID
專案建立完成後,便可以在首頁->資訊主頁上找到兩個專案ID,一個ID是由英文字母和數字組成;另一個由數字組成。純數字組成的專案ID就是Sender ID。





如何取得API Key?


進入Google developers console並登入帳號。

建立憑證
由左側選單中API管理員進入憑證頁面。
點選建立憑證選擇API金鑰。接著選擇伺服器API金鑰。



填入名稱和伺服器IP位址,建立金鑰。


建立完成後,此金鑰為API Key。




啟用Google API
在首頁->資訊主頁上找到使用Google API進入。


選擇欲使用之Google API。


啟用Google Cloud Messaging。





其他方法

另外從configure your API project也可以取得Sender ID和API Key。



星期二, 3月 01, 2016

簡介透過GCM達成推播功能 (一)

簡介透過GCM達成推播功能 (一)


透過GCM程式開發人員能從伺服器發送資料到應用程式上。以下簡介GCM。


架構

整體架構由三個部件組成。
1.      Google GCM connection server。
2.      App server
3.      Client App



證書

在GCM中使用的IDs和Token是用來確保各方已經認證,如此訊息便能傳送到正確的地方。

1.      Sender ID – 不會重複的數值。在Google Developer Console中配置API專案時取得。註冊時使用,GCM用來辨識App server已被允許傳送訊息到Client app。
2.      API Key – API Key儲存在App server,讓已認證的App server存取Google服務。在HTTP中,API Key被包含在POST請求的標頭中。
3.      Application ID – Client app用來註冊已便能接收到訊息。它是平台獨立的,在Android平台上利用package name作為Application ID。
4.      Registration Token – 由GCM針對Client app產生的ID,允許Client app接收訊息。另外特別需要注意的是Registration Token必須被保密。



GCM的作用?

Google Cloud Messaging(GCM)是處理應用程式伺服器(App Server)與手機應用程式(Client App)間的訊息之傳送、路由與排隊的服務。





如何透過GCM實現推播?



1.      Android裝置向GCM傳送Sender ID和Appilcation ID進行註冊。
2.      註冊成功。GCM向Android裝置回傳Registration Token。
3.      Android裝置接收到Registration Token,向伺服器傳送Token。
4.      伺服器將Registration Token存入資料庫,待往後使用。

a.      當需要進行推播時,伺服器向GCM傳送訊息與Registration Token。
b.      GCM利用Registration Token向Android裝置傳遞訊息。

星期五, 10月 30, 2015

Bitmap的壓縮

Bitmap在Activity間傳送時,進行壓縮。

ByteArrayOutputStream stream = new ByteArrayOutputStream();
bmp.compress(Bitmap.CompressFormat.PNG, 100, stream);
byte[] bytes = stream.toByteArray();

星期四, 10月 01, 2015

利用指令將本地端專案加入GitHub

利用指令將本地端專案加入GitHub

1.在本地專案目錄下,開啟Git Bash,輸入git init指令,建立此專案的本地端數據庫。

2.建立完本地數據庫後,輸入git add .指令,將所有修改過的或新增的檔案add到stage狀態。

3.輸入git commit -m 'first commit'指令,commit所有已經stage的檔案。

4.輸入git remote add origin remote repository url指令,提示本地端數據庫將會被push的位置。

5.輸入git push origin master指令,將專案push到GitHub。

星期五, 9月 25, 2015

在OneDrive雲端空間建立Git遠端數據庫

在OneDrive雲端空間建立Git遠端數據庫


1.在OneDrive目錄下新增新資料夾,命名為TestGit

2.進到TestGit點擊右鍵,開啟Git Bash

3.在Git Bash中輸入命令,git init --bare

4.執行指令後,TestGit內會建立一些資料如hook、info、object等(建立遠端數據庫)

5.在除了OneDrive目錄以外的目錄下點擊右鍵,開啟Git Bash

6.在Git Bash中輸入指令,git clone file///c/Users/user/OneDrive/TestGit

7.執行指令後,建立TestGit目錄(建立本地端數據庫)

8.完成以上步驟就可以進行push、pull等等將專案資料進行版本管理



除了OneDrive也可以選擇其他雲端空間如GoogleDrive、Dropbox,將遠端數據庫建立在雲端空間。


建立TestGit目錄(本地端數據庫)後,就可以將專案建立在TestGit目錄下,利用git完成版本控制。

星期日, 5月 24, 2015

Android Interface Definition Language (AIDL) (一)

Android Interface Definition Language (AIDL)


行程間通訊(IPC,Inter-Process Communication),指至少兩個行程或執行緒間傳送資料或訊號的一些技術和方法。在Android系統中提供一些方法進行IPC,AIDL為其中一種方法。

AIDL (android interface definition language) 與其他你可能已經使用過的IDLs相似,它允許你在client和service兩者上編寫介面(interface)用來在彼此之間進行行程間通訊。在Android上,一個行程按理是無法存取其他行程的記憶體,所以說,它們需要將它們的物件分解為作業系統可以理解的原始狀態,封送(marshell)物件跨過邊界。編寫進行封送的程式是乏味的,所以Android利用AIDL處理好了。

注意,只有在如果你允許來自其他應用程式的用戶端存取你的服務(service)及想在你的服務(service)中處理多執行緒,使用AIDL是必須的。如果你不需要在跨不同應用程式間實現並行IPC,你應該藉由實現一個Binder建立你的介面(interface),或者你想進行IPC,但不需要處理多執行緒,利用一個Messager實現你的介面(interface)。無論如何,在你實現AIDL前確保你理解bound service了。

在你開始設計你的AIDL介面(interface)前,注意調用AIDL介面(interface)是函式直接調用,你不應該做出假設在執行緒中調用函式的可能。發生情況不同依據是否來自在本地行程或遠端行程中的一個執行緒的調用。特別是
  • 執行在相同執行緒中的本地行程產生的調用正在調用,如果此執行緒是你的主要使用者介面執行緒(UI thread),此執行緒繼續在AIDL介面中執行。如果此執行緒是其他執行緒,是在你的服務(service)中執行你的程式的其中之一執行緒。因此,如果只有本地的執行緒正在存取服務(service),你可以完全地控制在服務中執行的執行緒(但是,如果是這樣的話,你不應該使用AIDL,但應該實現一個Binder來建立介面來取代之)。
  • 來自遠端行程的調用被一個執行緒池(thread pool)調度,該平台在你自己的行程中維護,你必須為來自未知執行緒的調用作準備,可能在同一時間許多調用發生,換句話說,AIDL的實現必須是完全地執行緒安全(thread-safe)。
  • oneway關鍵字改變遠端調用的行為。當使用時,遠端調用不會阻塞,它會簡易地送交易資料並立即回傳,介面的實現終究會接收它如來自Binder執行緒池正規的遠端調用。如果oneway備用在本地調用,不會有任何影響且調用仍是同步的。







星期一, 9月 01, 2014

Creating a Content Provider (二)

Implementing the ContentProvider Class

ContentProvider實例藉由處理其他應用程式的請求,管理對結構化資料的存取。所有存取的格式最終呼叫ContentResolver,然後呼叫具體的ContentProvider的方法去取得存取。


Required methods

ContentProvider抽象類別定義了六個抽象方法,這些方法必須實作作為你的子類別的一部份。這些所有的方法除了onCreate()外都會被客戶端應用程式呼叫,以嘗試存取你的content provider。

query()
從你的content provider擷取資料。利用參數選擇查詢的資料表、回傳的行與列、結果的排序。回傳資料為一個Cursor物件。
insert()
插入新的row到你的content provider。利用參數選擇目標資料表及獲取column值去使用。回傳薪插入的row的content URI。
update()
更新已存在於你的content provider的row。利用參數選擇資料表與rows來更新以及取得被更新的column值。回傳被更新的row的數量。
delete()
從你的content provider刪除rows。利用參數選擇資料表與rows來刪除。回傳被刪除rows的數量。
getType()
回傳對應到一個content URI的MIME型態。詳細說明在Implementing Content Provider MIME Types。
onCreate()
初始化你的content provider。Android系統建立你的content provider之後,立即呼叫此方法。注意到你的content provider不會被建立,直到ContentResolver嘗試存取它。
注意到這些方法都有一個相同的特徵,與ContentResolver的方法同名。

這些方法的實作應考慮以下內容:

  • 這些所有方法除了onCreate()以外都可以同時被多個執行續呼叫,所以它們必須是thread safe。詳細說明在Processes and Threads。
  • 避免在onCreate()方法中執行冗長的操作。延遲初始化任務直到它們真的被需要,詳細於Implementing the onCreate() method討論。
  • 雖然你必須值做這些方法,你的程式碼不必任何事都做,除了回傳預期的資料型態。例如,你想要預防其他應用程式在某些資料表上插入資料。達成方式可以忽略對insert()的呼叫並回傳0。


Implementing the query() method

ContentProvider.query()方法必須回傳Cursor物件,或是如果失敗,丟出一個Exception。如果你是使用SQLite資料庫做為資料的儲存,你可以簡單地回傳Cursor,此Cursor是SQLiteDatabase類別其中一個query()方法的回傳。如果查詢無符合條件的row,你應該回傳一個Cursor實例,它的getCount()方法回傳值為0。只在如果查詢過程中內部發生錯誤時,回傳null。

如果你不是使用SQLite資料庫做為資料儲存,使用具體的Cursor子類的其中之一。例如,MatrixCursor類別實作一個Cursor,在Cursor中每一row是一個Object陣列。用此類別,使用addRow()方法新增新的row。

記住了,Android系統必須能夠與Exception通信跨過處理程序的邊界。Android可以執行以下exceptions,它們對於處理查詢錯誤有幫助。
  • IllegalArgumentException (如果你的provider接收到一個無效的content URI時,你可能選擇丟出此例外)
  • NullPointerException

Implementing the insert() method

insert()方法用來插入新的row到適當的資料表,利用在ContentValues參數中的值。如果column名稱沒有在ContentValues參數中,你可想要在你的provider程式碼中或你的資料庫綱目中,為它提供預設值。

該方法應該回傳新的row的content URI。建構content URI,使用withAppendedId()方法,將新的row的_ID(或其他主鍵)值附加到資料表的content URI上。



Implementing the delete() method

delete()方法不必實際刪除來自資料儲存中的row,如果與你的provider正使用sync adapter,你應該考慮在被刪除的row標記"delete"標籤,而不是移除整個row。sync adapter可以確認被刪除的row並從provider刪除它們之前將它們從伺服器中移除。


Implementing the update() method

update()方法採用與insert()方法相同的ContentValues參數,相同於使用在delete()方法和ContentProvider.query()方法的selection和selection Args參數。如此可能允許你在這些方法中重複使用程式碼。


Implementing hte onCreate() method

當Android系統啟動provider,Android系統呼叫onCreate()。在此方法中,你應該只執行快速運行的初始化任務,並延遲資料庫的建立和資料的加載,直到provider實際接收到對於資料的請求。如果你在onCreate()方法中執行冗長任務,將會減緩provider的啟動,換言之,將會減緩provider對於其他應用程式的反應。

例如,如果你使用SQLite資料庫,可以在ContentProvider.onCreate()建立一個新的SQLiteOpenHelper物件,然後在你第一次打開資料庫時建立SQLite資料表。促使該事,第一時間你可以呼叫getWritableDatabase()方法,它會自動地呼叫SQLiteOpenHelper.onCreate()方法。

以下兩片段示範ContentProvider.onCreate()與SQLiteOpenHelper.onCreate()之間的互動。第一片段ContentProvider.onCreate()方法的實作。

public class ExampleProvider extends ContentProvider

    /*
     * Defines a handle to the database helper object. The MainDatabaseHelper class is defined
     * in a following snippet.
     */
    private MainDatabaseHelper mOpenHelper;

    // Defines the database name
    private static final String DBNAME = "mydb";

    // Holds the database object
    private SQLiteDatabase db;

    public boolean onCreate() {

        /*
         * Creates a new helper object. This method always returns quickly.
         * Notice that the database itself isn't created or opened
         * until SQLiteOpenHelper.getWritableDatabase is called
         */
        mOpenHelper = new MainDatabaseHelper(
            getContext(),        // the application context
            DBNAME,              // the name of the database)
            null,                // uses the default SQLite cursor
            1                    // the version number
        );

        return true;
    }

    ...

    // Implements the provider's insert method
    public Cursor insert(Uri uri, ContentValues values) {
        // Insert code here to determine which table to open, handle error-checking, and so forth

        ...

        /*
         * Gets a writeable database. This will trigger its creation if it doesn't already exist.
         *
         */
        db = mOpenHelper.getWritableDatabase();
    }
}
下一片段是SQLiteOpenHelper.onCreate()實作,包含一個Helper類別。

..
// A string that defines the SQL statement for creating a table
private static final String SQL_CREATE_MAIN = "CREATE TABLE " +
    "main " +                       // Table's name
    "(" +                           // The columns in the table
    " _ID INTEGER PRIMARY KEY, " +
    " WORD TEXT"
    " FREQUENCY INTEGER " +
    " LOCALE TEXT )";
...
/**
 * Helper class that actually creates and manages the provider's underlying data repository.
 */
protected static final class MainDatabaseHelper extends SQLiteOpenHelper {

    /*
     * Instantiates an open helper for the provider's SQLite data repository
     * Do not do database creation and upgrade here.
     */
    MainDatabaseHelper(Context context) {
        super(context, DBNAME, null, 1);
    }

    /*
     * Creates the data repository. This is called when the provider attempts to open the
     * repository and SQLite reports that it doesn't exist.
     */
    public void onCreate(SQLiteDatabase db) {

        // Creates the main table
        db.execSQL(SQL_CREATE_MAIN);
    }
}