読者です 読者をやめる 読者になる 読者になる

androidの5系の新しいapi(+Rxjava)の調査も兼ねて、小さいはてブアプリ作った

見出し通りの内容ですが、Androidは5.0(Api Level 21)でマテリアルデザインが採用されたこともあって見た目に関わるapiが色々増えました

5系対応のサンプルコードはそこそこみてたんですが実際に触ってみないとわからないことも多いし、仕事にそろそろマテリアル対応とかもありそうなので 土日を使って小さなアプリを作りながら色々触れてみることにしました

今回調査したのは、

  • 左上のクルクルする矢印アイコンの実装方法
  • リップルエフェクト(波紋のように広がるエフェクト)の実装方法
  • サポートライブラリがどこまで対応してるか
  • RecyclerViewの実装方法

加えて、最近流行っているRxJavaも気になっていたので、[ネットワーク通信] -> [リストアダプターに流し組む]部分をRxJava(+Retrofit)で実装しました

クルクルする矢印アイコンの実装方法

クルクルする矢印のアイコンはサポートライブラリで提供されていて、
利用するにはappcompat-v7をいれます

compile 'com.android.support:appcompat-v7:21.+'

あとはこんな感じのテンプレコードを書けば動きます。

drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
drawerToggle = new ActionBarDrawerToggle(this, drawerLayout, R.string.start, R.string.stop);
drawerToggle.setDrawerIndicatorEnabled(true);
drawerLayout.setDrawerListener(drawerToggle);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        return drawerToggle.onOptionsItemSelected(item) || super.onOptionsItemSelected(item);
    }

    @Override
    protected void onPostCreate(Bundle savedInstanceState) {
        super.onPostCreate(savedInstanceState);
        drawerToggle.syncState();
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        drawerToggle.onConfigurationChanged(newConfig);
    }

ActionBarDrawerToggleってv4のサポートライブラリの方にもあって、それに気づかないと結構ハマります

リップルエフェクト(波紋のように広がるエフェクト)の実装方法

リップルエフェクトもデフォルトのものは、SDKが提供してくれていて、
エフェクトを掛けたいviewのbackgroundに指定します

android:background="?android:attr/selectableItemBackground"

実はもう一種類あって

android:background="?android:attr/selectableItemBackgroundBorderless"

こっちはviewを跨いだ波紋が広がるエフェクトになるっぽい? のですが、minSDKが21なのでLollipopにしか使えません。

RecyclerViewの実装方法

Adapterを作るのはListViewを同じ、RecyclerView.Adapterの実装は簡略化すると概ねこんな感じ、

public class EntryAdapter extends RecyclerView.Adapter<EntryAdapter.ViewHolder> {
    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    // viewをinflateしてViewHolderを作成する
        View view = LayoutInflater.from(parent.getContext())
                    .inflate(R.layout.cell_xxx, parent, false);
        return new ViewHolder(view);
    }
    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
    // getView相当の処理(view.setText() etc...)
    }
    @Override
    public int getItemViewType(int position) {
        return // viewTypeを返す;
    }
}

昔のAdapterの実装とほとんど変わんないのですが、新しい概念としてViewTypeというのが追加されてて
複数のviewをレンダリングするタイプのリストを作成したい場合はgetItemViewTypeをOverrideしてよしなに出来る
Activity側はこんな感じ

RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(layoutManager);
entryAdapter = new EntryAdapter();
recyclerView.setAdapter(entryAdapter);
サポートライブラリがどこまで対応してるか

これは正直ちゃんと調べてないのでわからないですが、少なくとも上の3つはサポートライブラリで対応できました!!
(気になるの他に何かあったかな..)

RxJava

[ネットワーク通信] -> [リストアダプターに流し組む]はこんな感じに書ける
そこそこ複雑なリストの処理してるけど、とても完結でわかりやすく書ける
学習コスト低いのでコスパ的に考えるとかなりいい気がする 特にRetrofitがRxjava対応していてホント便利だった
使い方は、wikiサンプル見れば簡単な処理ならすぐ書けそう

        category.observable(app)
                .subscribeOn(Schedulers.newThread())
                .observeOn(AndroidSchedulers.mainThread())
                .doOnSubscribe(() -> {
                // something..
                })
                .onErrorReturn(throwable -> {
                // something..
                })
                .map(entries -> {
                // something..
                })
                .flatMap(Observable::from)
                .groupBy(entry -> {
                // something..
                })
                .subscribe(observable -> {
                    if (observable.getKey() == EntryType.onlyTitle) {
                        observable.subscribe(entryAdapter::add);
                    } else if (observable.getKey() == EntryType.WithImage) {
                        observable
                                .buffer(2)
                                .filter(// something )
                                .subscribe(entryAdapter::add);
                    }
                });
今回作ったアプリ

5.0用のサンプルアプリ程度の気持ちで作ってたんですが、
やる気が続いたら継続的に開発するつもりです