モケラ

Tech Sheets

mokelab

ContentProviderを使ったTodoリストアプリを作る

最終更新日:2015-07-07

Todoを扱うContentProviderの実装ができたので、早速これを使ったアプリを作ってみます。

ここまでの実装はここにあります。

アプリは、ログイン画面とリスト画面の2画面で構成します。ログイン画面はおまけみたいな感じではありますが。。。

まずはログイン画面。単にユーザーIDを入力してもらうだけにしています。ボタンをタップしたときの処理だけ紹介します。

public class LoginFragment extends Fragment {
    @Bind(android.R.id.edit)
    EditText mUsernameEdit;

    // 中略
    @OnClick(android.R.id.button1)
    void loginClicked() {
        String username = mUsernameEdit.getText().toString();
        if (TextUtils.isEmpty(username)) { return; }

        FragmentManager manager = getFragmentManager();
        FragmentTransaction transaction = manager.beginTransaction();

        transaction.replace(R.id.container, TodoListFragment.newInstance(username));

        transaction.commit();

    }
}

入力されたユーザー名を次のFragmentに渡しているだけですね。

次にメインとなるリスト画面。やや長いですがぜんぶ載せます。

public class TodoListFragment extends ListFragment {
    private static final String ARGS_USERNAME = "username";
    private static final int ID_LOADER = 1;

    // argument
    private String mUsername;

    @Bind(android.R.id.edit)
    EditText mEdit;

    public static TodoListFragment newInstance(String username) {
        TodoListFragment fragment = new TodoListFragment();

        Bundle args = new Bundle();
        args.putString(ARGS_USERNAME, username);
        fragment.setArguments(args);

        return fragment;
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        Bundle args = getArguments();
        mUsername = args.getString(ARGS_USERNAME);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View root = inflater.inflate(R.layout.fragment_list, container, false);

        ButterKnife.bind(this, root);

        // init adapter
        CursorAdapter adapter = new SimpleCursorAdapter(getActivity(), R.layout.item_todo, null,
                new String[]{TodoColumns.TODO}, new int[]{android.R.id.text1}, 0);
        setListAdapter(adapter);

        return root;
    }

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);

        loadTodo();
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();

        ButterKnife.unbind(this);
    }

    private void loadTodo() {
        LoaderManager manager = getLoaderManager();
        manager.initLoader(ID_LOADER, null, mCallback);
    }

    private LoaderManager.LoaderCallbacks<Cursor> mCallback = new LoaderManager.LoaderCallbacks<Cursor>() {
        @Override
        public Loader<Cursor> onCreateLoader(int id, Bundle args) {
            return new CursorLoader(getActivity(), Uri.parse("content://com.mokelab.todo.provider/users/" + mUsername + "/todos"),
                    null, null, null, null);
        }

        @Override
        public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
            CursorAdapter adapter = (CursorAdapter) getListAdapter();
            adapter.swapCursor(data);
        }

        @Override
        public void onLoaderReset(Loader<Cursor> loader) {
            CursorAdapter adapter = (CursorAdapter) getListAdapter();
            adapter.swapCursor(null);
        }
    };

    @OnClick(android.R.id.button1)
    void addClicked() {
        String todo = mEdit.getText().toString();
        if (TextUtils.isEmpty(todo)) {
            return;
        }

        ContentValues values = new ContentValues();
        values.put(TodoColumns.TODO, todo);
        getActivity().getContentResolver().insert(
                Uri.parse("content://com.mokelab.todo.provider/users/" + mUsername + "/todos"),
                values);
        mEdit.setText("");
    }
}

順に見ていきましょう。

まず、onCreate()で、引数として渡されたユーザーIDを取り出します。

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    Bundle args = getArguments();
    mUsername = args.getString(ARGS_USERNAME);
}

次に、onCreateView()でCursorAdapterをListAdapterとしてセットします。この時点でCursorは取得できていないので、第3引数にはnullをセットしておきます。

@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    View root = inflater.inflate(R.layout.fragment_list, container, false);

    ButterKnife.bind(this, root);

    // init adapter
    CursorAdapter adapter = new SimpleCursorAdapter(getActivity(), R.layout.item_todo, null,
            new String[]{TodoColumns.TODO}, new int[]{android.R.id.text1}, 0);
    setListAdapter(adapter);

    return root;
}

onActivityCreated()で、Loaderの初期化を行います。

private void loadTodo() {
    LoaderManager manager = getLoaderManager();
    manager.initLoader(ID_LOADER, null, mCallback);
}

LoaderCallbacksでは、CursorLoaderを生成します。CursorLoaderはContentProviderからデータを読み込むのに便利なLoaderです。データの取得が終わったら、CursorAdapterのswapCursor()で取得したCursorオブジェクトをセットします。これだけでTodoの読み込み部分は完了です。

private LoaderManager.LoaderCallbacks<Cursor> mCallback = new LoaderManager.LoaderCallbacks<Cursor>() {
    @Override
    public Loader<Cursor> onCreateLoader(int id, Bundle args) {
        return new CursorLoader(getActivity(), Uri.parse("content://com.mokelab.todo.provider/users/" + mUsername + "/todos"),
                null, null, null, null);
    }

    @Override
    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
        CursorAdapter adapter = (CursorAdapter) getListAdapter();
        adapter.swapCursor(data);
    }

    @Override
    public void onLoaderReset(Loader<Cursor> loader) {
        CursorAdapter adapter = (CursorAdapter) getListAdapter();
        adapter.swapCursor(null);
    }
};

最後に、データを追加する部分です。ContentResolverのinsert()を呼ぶだけなのでこちらも簡単ですね。

@OnClick(android.R.id.button1)
void addClicked() {
    String todo = mEdit.getText().toString();
    if (TextUtils.isEmpty(todo)) {
        return;
    }

    ContentValues values = new ContentValues();
    values.put(TodoColumns.TODO, todo);
    getActivity().getContentResolver().insert(
            Uri.parse("content://com.mokelab.todo.provider/users/" + mUsername + "/todos"),
            values);
    mEdit.setText("");
}

ContentProviderにinsert()でデータを追加すると、更新通知を実装するで実装した機能により、自動で再取得とリストの更新が行われます。

一覧に戻る