LoginSignup
10
2

More than 5 years have passed since last update.

2016年Android界隈で話題になったと個人的に思うこと その1

Posted at
1 / 2

qnote Advent Calendar 2016 2日目を担当いたします。
チャン・ジュン(日本人)です。
よろしくどうぞ

今回は、今年Android界隈で話題になったことを...
ということでKotlinでAndroidアプリ書くとこんな感じというのを紹介していこうと思います。

ちなみに、どんなアプリで紹介するかと言いますと、昨年のAdvent Calendarで書いたGoogle画像検索を利用して画像をグリッド表示するだけのアプリです。
記事はこちら

何はともあれ

さて、Kotlinのプロジェクトを作るのはとても簡単です。
ただしKotlinのプラグインは必須なのでInstallしておいてください。

  1. まずは普通に新しいプロジェクトを作りましょう。
    • 最初に作るアクティビティは何でも良いです。
  2. プロジェクトができたらTools>Kotlin>Configure Kotlin in ProjectでプロジェクトでKotlinが使えるようにしましょう。
  3. Kotlinが使えるようになったらCode>Convert Java File to Kotlin FileでJavaファイルをKotlinファイルにコンバートしてもらいます。

おめでとうございます!
Kotlinで書かれたAndroidアプリができました!

google画像検索を利用して画像をグリッド表示してみる

それでは本題の実装部分ですが、今回もまた通信関係はVolleyに任せちゃいます。

事前準備として
manifestに<uses-permission android:name="android.permission.INTERNET"/>
build.gradleのdependenciesにcompile 'com.android.volley:volley:1.0.0'
を追記してください。

高階関数+ラムダでかなりスッキリ書ける

まずはリクエストを作ります。
Google画像検索でhtmlファイルを取得して画像URLを抽出するのでStringRequestを使います。
なお、KotlinファイルとJavaファイルが混在する環境を再現したかったのでJavaで書いています。

ImageRequest.java
public class ImageRequest extends StringRequest {

    private Map<String, String> mParams;
    private static final String URL = "http://www.google.co.jp/search";

    public ImageRequest(Response.Listener<String> listener, Response.ErrorListener errorListener, Map<String, String> mParams) {
        super(Method.GET, URL, listener, errorListener);
        this.mParams = mParams;
    }

    @Override
    public String getUrl() {
        return super.getUrl() + makeParameter();
    }

    private String makeParameter() {

        String param = "?tbm=isch";
        for (Map.Entry<String, String> entry : mParams.entrySet()) {
            param += "&" + entry.getKey() + "=" + entry.getValue();
        }

        return param;
    }
}

ということでMainActivity.ktからの呼び出しがこちら

MainActivity.kt
fun requestImage() {
    val params = createParameter()
    val request = ImageRequest(
        Response.Listener {
            //抽出とアダプターのセット
        },
        Response.ErrorListener {
            //リクエストに失敗
        }, params)

    queue.add(request)
}

paramsにはキーワードとoffsetが必要になると思います。
Javaで書かれたクラスもKotlinで書かれたクラスもKotlinではインスタンスの生成にnewは不要です。
また引数に関数を取ることができ(高階関数)、ラムダを渡せばかなり簡略化して書くことができます。
今回使用しているListenerは引数が1つのメソッド1つを実装するインターフェースなので、下記のようにメソッドの引数の記述を省略してitで表すことができます。

Response.ErrorListener {
    Toast.makeText(this@MainActivity, it.message, Toast.LENGTH_SHORT).show()
}

lateinit修飾子で初期化を先延ばしできる

MainActivity全体はこんな感じです。
Kotlinでは基本的にnullが許容されていないのでval queue: RequestQueueと書いただけでは赤線が引かれます。
そこでlateinit修飾子をつけることで初期化を先延ばしにできるのですが、初期化しなくてもランタイムまでエラーが出ないので取り扱いには要注意です。

MainActivity.kt
class MainActivity : AppCompatActivity() {

    lateinit var queue: RequestQueue
    val imageUrlList = ArrayList<String>()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val toolbar = findViewById(R.id.toolbar) as Toolbar
        setSupportActionBar(toolbar)

        val fab = findViewById(R.id.fab) as FloatingActionButton
        fab.setOnClickListener { view -> Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG).setAction("Action", null).show() }

        queue = Volley.newRequestQueue(applicationContext)
        requestImage()
    }

    fun requestImage() {
        val params = createParameter()
        val request = ImageRequest(
                Response.Listener {
                        val regex = "<img.+?src=\"(.+?)\".+?>"
                        val pattern = Pattern.compile(regex)
                        val matcher = pattern.matcher(it)

                        while (matcher.find()) {
                            imageUrlList.add(matcher.group(1))
                        }

                        if (imageUrlList.size < 100) {
                            requestImage()
                        }else {
                            val recyclerView = findViewById(R.id.image_grid) as RecyclerView
                            val layoutManager = GridLayoutManager(this@MainActivity, 4)
                           recyclerView.layoutManager = layoutManager
                            recyclerView.adapter = GridAdapter(this@MainActivity)
                        }
                },
                Response.ErrorListener {
                    Toast.makeText(this@MainActivity, it.message, Toast.LENGTH_SHORT).show()
                }, params)

        queue.add(request)
    }

    fun createParameter(): HashMap<String, String> {
        val params = HashMap<String, String>()
        params.put("q", "cat")

        if (imageUrlList.size > 0 && imageUrlList.size < 100) {
            params.put("start", imageUrlList.size.toString())
        }
        return params
    }
}

Kotlinファイルのクラスが持っているグローバル変数をJavaで参照するには...

それではMainActivityのコードを踏まえてGridAdapterを見てみましょう。

GridAdapter.java
public class GridAdapter extends RecyclerView.Adapter<GridViewHolder> {
    private ScrollingActivity mActivity;
    public GridAdapter(ScrollingActivity activity) {
        mActivity = activity;
    }
    @Override
    public GridViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        return new GridViewHolder(new NetworkImageView(mActivity));
    }

    @Override
    public void onBindViewHolder(GridViewHolder holder, int position) {
        holder.getImageView().setImageUrl(mActivity.getImageUrlList().get(position), new ImageLoader(mActivity.getQueue(), new GridImageCache()));
    }

    @Override
    public int getItemCount() {
        return mActivity.getImageUrlList().size();
    }

}

正直言って良いコードではありませんが...
さておき、ポイントはmActivity.getImageUrlList()mActivity.getQueue()です。
MainActivityにはgetterの実装などありませんが自動的にgetterが生成されています。
逆にJavaでgetterを作っている変数についてはrecyclerView.adapterのように取得できますし、セットする場合にはrecyclerView.adapter = 〜で代入をするような記述で済みます。

※GridImageCache、GridViewHolderクラスはテンプレート通りな感じですので割愛いたします。

まとめ

勉強会に参加するとよく耳にしたKotlinという言語ですが、実際の業務で全てをKotlinで書いているという話はまだ聞きません。
一部コードでKotlinを利用することに対してリスクを考えている人に、混在する状態でも意識することなく実装を進めることができるということが伝われば良いなと思います。

最後に

その2を書くかどうかはまだ未定...

10
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
2