ユーザーの情報をAzure Searchに保管してありまして、それをAndroidでList表示したいと思います。

Azure Search に関してはまた後程詳しく書きたいと思いますが、簡単にいうとAzureで提供されているテキスト検索サービスになります。ここにIndexしておくと、高速で結果をだしてくれるイケてるサービスです。 https://azure.microsoft.com/ja-jp/services/search/

Azure SearchをAPI経由で利用するときはこちらのドキュメントを参照。 https://docs.microsoft.com/ja-jp/azure/search/search-fiddler

APIの呼び方に関してはAndroid – Retrofit を使ってWiki Search もご参照ください。

ss10180503-1.jpg

Searchサービスのトップページに行くとベースURLが記載してあります。

APIキーは左メニューの「Keys」より取得するとこができます。

ss10180503-2.jpg

Indexのフィールドはこんな感じです。

ss10180503-3.JPG

 

コードからたたく前にAPIが正常に叩けているかPostmanを使って確認。

ss20180503-4.png

問題なく叩けました、ではでは、一旦今はid と nameだけ表示してみたいと思います。

早速叩いてみましょう。

appレベルgradleにて 今回使うCardView、RecyclerView、Retrofit、RxJavaを追加します。

dependencies {
    implementation 'com.android.support:cardview-v7:27.1.1'
    implementation 'com.android.support:design:27.1.1'
    implementation 'com.android.support:recyclerview-v7:27.1.1'
    implementation 'com.android.support.constraint:constraint-layout:1.1.0'
    implementation 'com.android.support:support-v4:27.1.1'

    /*Retrofit2*/
    implementation "com.squareup.retrofit2:retrofit:2.3.0"
    implementation "com.squareup.retrofit2:adapter-rxjava2:2.3.0"
    implementation "com.squareup.retrofit2:converter-gson:2.3.0"

    compile "io.reactivex.rxjava2:rxandroid:2.0.1"
}

次はデータモデルのクラス Model.kt

package com.a5.a5cp_k1

object AzureSearchModel{
    data class SearchResult(
            var value: ArrayList<Result>
           )
    data class Result(
            val id: String,
            val name: String
    )
}

次はAPIのインターフェイスのIApiAzureSearchService.kt

package com.a5.a5cp_k1

import io.reactivex.Observable
import retrofit2.http.GET
import retrofit2.http.Headers
import retrofit2.http.Query

public interface IApiAzureSearchService {
    @Headers("content-type: application/json",
        "api-key: <Your API Key Here>")
    @GET("/indexes/idxprofiles/docs")
    fun getData(@Query("search") search: String,
                @Query("count") count: String,
                @Query("api-version") version: String,
                @Query("top") top: Int) : Observable<AzureSearchModel.SearchResult>;
}

次はレイアウト、まずはメインのレイアウトとなるactive_azure_search_result.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".AzureSearchResultActivity">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/AzureSearchRecyclerView"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginEnd="8dp"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>

RecyclerViewの中身となるfragment_azure_search_result.xml

<?xml version="1.0" encoding="utf-8"?>

<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"

    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginEnd="8dp"
    android:layout_marginStart="8dp"
    android:layout_marginTop="16dp">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <TextView
            android:id="@+id/TextSearchResultId"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginBottom="10dp"
            android:layout_marginTop="10dp"
            android:text="TextView" />

        <TextView
            android:id="@+id/TextSearchResultName"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginBottom="10dp"
            android:layout_marginTop="10dp"
            android:text="TextView" />

    </LinearLayout>
</android.support.v7.widget.CardView>

次にデータアダプターとなるSearchResultDataAdapter.kt

package com.a5c.a5cp_k1

import android.support.v7.widget.RecyclerView
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.graphics.Color

import kotlinx.android.synthetic.main.fragment_azure_search_result.view.*

class DataAdapter (private val dataList : ArrayList<AzureSearchModel.Result>, private val listener : Listener) : RecyclerView.Adapter<DataAdapter.ViewHolder>() {

    interface Listener {

        fun onItemClick(AzureSearchModel: AzureSearchModel.Result)
    }

    private val colors : Array<String> = arrayOf("#EF5350", "#EC407A", "#AB47BC", "#7E57C2", "#5C6BC0", "#42A5F5")

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {

        holder.bind(dataList[position], listener, colors, position)
    }

    override fun getItemCount(): Int = dataList.count()

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {

        val view = LayoutInflater.from(parent.context).inflate(R.layout.fragment_azure_search_result, parent, false)

        return ViewHolder(view)
    }

    class ViewHolder(view : View) : RecyclerView.ViewHolder(view) {

        fun bind(AzureSearchModel: AzureSearchModel.Result, listener: Listener, colors : Array<String>, position: Int) {

            itemView.TextSearchResultId.text = AzureSearchModel.id
            itemView.TextSearchResultName.text = AzureSearchModel.name
            itemView.setBackgroundColor(Color.parseColor(colors[position % 6]))

            itemView.setOnClickListener{ listener.onItemClick(AzureSearchModel) }
        }
    }
}

そして最後にメインのアクティビティ AzureSearchResultActivity

package com.a5.a5cp_k1

import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.support.v7.widget.RecyclerView
import android.util.Log
import android.widget.Toast
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.schedulers.Schedulers
import io.reactivex.android.schedulers.AndroidSchedulers

import retrofit2.converter.gson.GsonConverterFactory
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory
import retrofit2.Retrofit

import com.a5cupids.a5cp_k1.DataAdapter
import com.a5cupids.a5cp_k1.R.id.AzureSearchRecyclerView
import kotlinx.android.synthetic.main.activity_azure_search_result.*
import android.support.v7.widget.LinearLayoutManager

class AzureSearchResultActivity() : AppCompatActivity(), DataAdapter.Listener{

    private val TAG = AzureSearchResultActivity::class.java.simpleName
    private val BASE_URL = "<URL Azure Search Endpoint Base URL>"
    private var mCompositeDisposable: CompositeDisposable? = null
    private var mAndroidArrayList: ArrayList<AzureSearchModel.Result>? = null
    private var mAdapter: DataAdapter? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_azure_search_result)

        mCompositeDisposable = CompositeDisposable()

        initRecyclerView()

        loadJSON()
    }
    private fun initRecyclerView() {
        AzureSearchRecyclerView.setHasFixedSize(true)
        val layoutManager : RecyclerView.LayoutManager = LinearLayoutManager(this)
        AzureSearchRecyclerView.layoutManager = layoutManager
    }

    private fun loadJSON() {

        val requestInterface = Retrofit.Builder()
                .baseUrl(BASE_URL)
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .addConverterFactory(GsonConverterFactory.create())
                .build().create(IApiAzureSearchService::class.java)

        mCompositeDisposable?.add(requestInterface.getData(search="John",version="2017-11-11",count="true",top=10)
                .observeOn(AndroidSchedulers.mainThread())
                .subscribeOn(Schedulers.io())
                .subscribe(this::handleResponse, this::handleError))
    }

    private fun handleResponse(azureSearchResponse: AzureSearchModel.SearchResult) {

        mAndroidArrayList = azureSearchResponse.value
        mAdapter = DataAdapter(mAndroidArrayList!!, this)

        AzureSearchRecyclerView.adapter = mAdapter
    }

    private fun handleError(error: Throwable) {

        Log.d(TAG, error.localizedMessage)

        Toast.makeText(this, "Error ${error.localizedMessage}", Toast.LENGTH_SHORT).show()
    }

    override fun onItemClick(AzureSearchModel: AzureSearchModel.Result) {

        Toast.makeText(this, "${AzureSearchModel.name} Clicked !", Toast.LENGTH_SHORT).show()
    }

    override fun onDestroy() {
        super.onDestroy()
        mCompositeDisposable?.clear()
    }
}

 

検索結果が表示されました、OK。

Screenshot_20180503-124319.png


参考にしたページ

JsonのParseがうまくいってなかったようで、こちらを参照https://stackoverflow.com/questions/20991386/expected-begin-array-but-was-begin-object-at-line-1-column-2

Headの設定方法などなどこちらを参照しました
https://qiita.com/SYABU555/items/3b280a8e81d2cc897383

Kotlin Data Classに関してはこちらを参照
https://kotlinlang.org/docs/reference/data-classes.html

広告

コメントを残す

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください