NiftyCloud mBaaS + Kotlin データストアへの読み書き


以前、NiftyCloud mBaaSをSwiftから使う情報がほとんどないので、自分でやってみたメモ書きを[こちら](http://qiita.com/hiro_hosono/items/8545a93af3ed905fe24c)にアップしました。
今度はAndroid対応することになったのですが、Androidは全く知らないし使ったこともなかったのでちょっと調べたところSwift類似の言語「Kotlin」を使うと幸せになりそうなので、早速採用してみました。

こちら↓のアプリAndroid版で使ってみました。
[OnWorkってこんなアプリです](http://meltingpot.co.jp/onwork_info/)
[Androidアプリはこちら](https://play.google.com/store/apps/details?id=jp.co.meltingpot.onwork)


##0.環境
　AndroidStudio 2.2.3 + Kotlin 1.0.6
　[MBaaS Android SDK Version2.2.4] (https://github.com/NIFTYCloud-mbaas/ncmb_android)

　
##1.準備
　0) Kotlinプラグインを組み込む　詳しいことは[先人の記事](http://qiita.com/Kogarasi/items/4bd0a37763b057e9d796)を参照してください。
　他にもいっぱい記事がありますが、基本的にプラグインインストールするだけです。
　*Android初心者の私はFindViewByIDの嵐を避けるためkotlin-android-extensionsも入れました。
　1) Android用SDKを組み込む　(NCMB.jarをlibsフォルダにコピー)
　2) manifestsやらgradleやらの設定は通常のAndroidと変わらないので、[本家のチュートリアル](http://mb.cloud.nifty.com/doc/current/tutorial/tutorial_android.html)を参照。

　3 ) MainActivityのJavaファイルをKotlinに変換
　　メニューから「Code」 > 「Convert Java file to Kotlin file」を実行するだけ。
　4 ) OnCreateにアプリケーションキー設定を追加

```language:Kotlin
   override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        //**************** APIキーの設定とSDKの初期化 **********************
       	NCMB.initialize(this.baseContext,"YOUR_APPKEY","YOUR_CLIENTKEY")

    }
```


##2.データストアからの読み出し

下記のクラスからcompanyIDをキーにしてcompanyNameを読みだして返す関数の例です。
クラス名：Company
フィールド：companyID　会社のID
フィールド：companyName　会社の名前


``` language:Kotlin
data class companyInfo (
    var companyID:String = "",
    var companyName:String = ""
){}

fun getCompanyInfo(companyID:String) : companyInfo {
    val myCompany = companyInfo()

    myCompany.companyID = companyID
    val query:NCMBQuery<NCMBObject> = NCMBQuery("Company")
    query.whereEqualTo("companyID",companyID)
    val results: List<NCMBObject> = try {
        query.find()
    } catch (e : Exception) { emptyList<NCMBObject>() }
    if (results.isNotEmpty()) {
        val result = results[0]
        myCompany.companyName = result.getString("CompanyName")
    }
    return myCompany

}


```


##3.データストアへの追加

下記のクラスへレコードを書き込む（追加する）関数の例です。
クラス名：Company
フィールド：companyID　会社のID
フィールド：companyName　会社の名前
 * companyInfoはcompanyID, companyNameを含むdata classとして定義してあります


``` language:Kotlin
fun addCompany(company:companyInfo) {

    val obj = NCMBObject("Company")

    obj.put("CompanyName", company.companyName)
    obj.put("companyID", company.companyID)

    try {
        obj.save()
    } catch (e : Exception) {
     println("Company data save error : " + e.cause.toString())
    }
}


```

##4.データストアの更新

下記のクラスからcompanyIDをキーにして登録済みのレコードのcompanyNameを更新する関数の例です。
クラス名：Company
フィールド：companyID　会社のID
フィールド：companyName　会社の名前

 * companyInfoはcompanyID, companyNameを含むdata classとして定義してあります


 __* フィールドのデータを初期化したい場合はnullを設定すれば良いらしいです。
   (Android SDKにはremoveがあるのでこれで良さげ)
 　管理画面から見ると(undefined)には戻りませんが等価の扱いということです。
 　ただし、位置情報フィールドは初期化不可。removeできちゃうけど読み出しでヌルポ__
 参照： https://github.com/NIFTYCloud-mbaas/UserCommunity/issues/272


``` language:Kotlin
fun updateCompany(company:companyInfo) {

    val query: NCMBQuery<NCMBObject> = NCMBQuery("Company")
    query.whereEqualTo("companyID", company.companyID)

    val results: List<NCMBObject> = try {
        query.find()
    } catch (e: Exception) {
        emptyList<NCMBObject>()
    }
    if (results.isNotEmpty()) {
        val obj = results[0]
        obj.put("CompanyName", company.companyName)
        obj.put("companyID", company.companyID)

        try {
            obj.save()
        } catch (e: Exception) {
            println("company data save error : " + e.cause.toString())
        }
    }
}


```

##5.SDKのバグ？

  **NCMBQuery.getDate で日付データを読み出す時にNullが入ったエリアを読み出すとリターン値がNullとならずにヌルポで落ちます。**
  
  とりあえず　try catchで回避してます。
  
``` language:Kotlin
fun getObjDate(obj:NCMBObject,key:String):Date? {
    var date:Date? = null

    date = try {
        obj.getDate(key)
    } catch (e : Exception) { null }
    return date
}

```

  **NCMBQuery.whereWithinKilometersのdistance引数がIntになっているため、１キロ単位でしか指定できません。iOSはDoubleだったので　0.1 (=100m)が指定できました。**
  
  とりあえず　距離計算して判定することで回避してます。
  
``` language:Kotlin
	//仕事場の位置 ** 現在地の近くの勤務地を取得
    val workPlaceGeo:Location  = result.workPlaceGeo // whereWithinKilometersで取得した場所
    val distance = currentLocation.distanceTo(workPlaceGeo) //currentLocationは現在地
    if (distance > 100f) { // 100m
      // 100m以上離れている場合の処理
    }

```

##6.その他
ご意見ご要望等あればコメントください。
ファイルストアと会員管理については随時投稿予定です。