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

IT練習ノート

IT関連で調べたこと(実際は嵌ったこと)を書いています。

Android Custom Cursor Sample

追記

  • バージョンによっては動作しない。
    • column_keyに_idが必要
    • column数取得を実装する必要がある
  • ContentProviderを別APKにすると、Cursor利用側でキャッシュがされる。

ScreenShot

f:id:naotoogawa:20160110213450p:plain

Class

MainActivity-->MyAdapter (ItemLayout)<-->MyCursor<-->MyContentProvider

MainActivity

public class MainActivity extends Activity {

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

        setContentView(R.layout.activity_main);

        ContentResolver cr = getContentResolver();
        Uri uri = Uri.parse("content://com.example.test05");
        Cursor cursor = cr.query(uri, null, null, null, null);

        MyAdapter adapter = new MyAdapter(this, cursor, false);
        ListView listView = (ListView)findViewById(R.id.listView);
        listView.setAdapter(adapter);
    }
}

MyAdapter

public class MyAdapter extends CursorAdapter {

    private LayoutInflater mFactory;

    public MyAdapter(Context context, Cursor c) {
        super(context, c);
    }

    public MyAdapter(Context context, Cursor c, boolean autoRequery) {
        super(context, c, autoRequery);
        mFactory = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    }

    public MyAdapter(Context context, Cursor c, int flags) {
        super(context, c, flags);
        mFactory = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    }

    @Override
    public View newView(Context context, Cursor cursor, ViewGroup viewGroup) {
        ItemLayout view = (ItemLayout) mFactory.inflate(R.layout.item, viewGroup, false);
        return view;
    }

    @Override
    public void bindView(View view, Context context, Cursor cursor) {
        ItemLayout v = (ItemLayout)view;
        v.bindView( //
                cursor.getString(0), //
                cursor.getString(1), //
                cursor.getString(2) //
        );
    }
}

MyCursor

public class MyCursor implements Cursor {

    private List<Map<String, Object>> data;

    // -1
    private int pos = -1;

    public MyCursor(List<Map<String, Object>> data) {
        this.data = data;
    }

    @Override
    public int getCount() {
        return data.size();
    }

    @Override
    public int getPosition() {
        return pos;
    }

    @Override
    public boolean move(int i) {
        if (pos + i <= i && pos + i < getCount()) {
            pos = pos + i;
            return true;
        }
        return false;
    }

    @Override
    public boolean moveToPosition(int i) {

        Log.i("xxx", "MyCursor#moveToPosition pos=" + pos);

        if (0 <= i && i < getCount()) {
            pos = i;
            return true;
        }
        return false;
    }

    @Override
    public boolean moveToFirst() {
        if (data == null || data.isEmpty()) {
            return false;
        }
        pos = 0;
        return true;
    }

    @Override
    public boolean moveToLast() {
        if (data == null || data.isEmpty()) {
            return false;
        }
        pos = data.size() - 1;
        return true;
    }

    @Override
    public boolean moveToNext() {

        Log.i("xxx", "MyCursor#moveToNext pos=" + pos);

        if (data == null || pos >= data.size() - 1) {
            return false;
        }
        pos++;
        return true;
    }

    @Override
    public boolean moveToPrevious() {
        if (data == null || pos < 1) {
            return false;
        }
        pos--;
        return true;
    }

    @Override
    public boolean isFirst() {
        return pos == 0;
    }

    @Override
    public boolean isLast() {
        return pos == getCount();  // fix me
    }

    @Override
    public boolean isBeforeFirst() {
        return pos == -1;
    }

    @Override
    public boolean isAfterLast() {
        return pos == data.size() - 1;
    }

    @Override
    public int getColumnIndex(String s) {
        return 0;
    }

    @Override
    public int getColumnIndexOrThrow(String s) throws IllegalArgumentException {
        return 0;
    }

    @Override
    public String getColumnName(int i) {
        return null;
    }

    @Override
    public String[] getColumnNames() {
        return new String[0];
    }

    @Override
    public int getColumnCount() {
        return 0;
    }

    @Override
    public byte[] getBlob(int i) {
        return new byte[0];
    }

    @Override
    public String getString(int i) {

        Map<String, Object> item = data.get(pos);

        switch (i) {
            case 0:
                return String.valueOf(item.get("id")); // fix me
            case 1:
                return (String) item.get("name");
            case 2:
                return (String) item.get("address");
            default:
                throw new RuntimeException("invalid id " + i);
        }
    }

    @Override
    public void copyStringToBuffer(int i, CharArrayBuffer charArrayBuffer) {

    }

    @Override
    public short getShort(int i) {
        return 0;
    }

    @Override
    public int getInt(int i) {
        return 0;
    }

    @Override
    public long getLong(int i) {
        return 0;
    }

    @Override
    public float getFloat(int i) {
        return 0;
    }

    @Override
    public double getDouble(int i) {
        return 0;
    }

    @Override
    public int getType(int i) {
        return 0;
    }

    @Override
    public boolean isNull(int i) {
        return false;
    }

    @Override
    public void deactivate() {

    }

    @Override
    public boolean requery() {
        return false;
    }

    @Override
    public void close() {
        Log.i("XXX", "close !");

    }

    @Override
    public boolean isClosed() {
        return false;
    }

    @Override
    public void registerContentObserver(ContentObserver contentObserver) {

    }

    @Override
    public void unregisterContentObserver(ContentObserver contentObserver) {

    }

    @Override
    public void registerDataSetObserver(DataSetObserver dataSetObserver) {

    }

    @Override
    public void unregisterDataSetObserver(DataSetObserver dataSetObserver) {

    }

    @Override
    public void setNotificationUri(ContentResolver contentResolver, Uri uri) {

    }

    @Override
    public Uri getNotificationUri() {
        return null;
    }

    @Override
    public boolean getWantsAllOnMoveCalls() {
        return false;
    }

    @Override
    public Bundle getExtras() {
        return null;
    }

    @Override
    public Bundle respond(Bundle bundle) {

        return null;
    }
}

MyContentProvider

public class MyContentProvider extends ContentProvider {

    @Override
    public boolean onCreate() {
        Log.i("XXX", "onCreate");
        return false;
    }

    @Override
    public String getType(Uri uri) {
        Log.i("XXX" , "getType:" + uri);
        return null;
    }

    @Override
    public Uri insert(Uri uri, ContentValues contentValues) {
        Log.i("XXX" , "insert:" + uri + ", cv:" + contentValues);
        return Uri.parse("insert");
    }

    @Override
    public int delete(Uri uri, String s, String[] strings) {
        Log.i("XXX" , "delete:" + uri);
        return 1;
    }

    @Override
    public int update(Uri uri, ContentValues contentValues, String s, String[] strings) {
        Log.i("XXX" , "update:" + uri+ ", cv:" + contentValues);
        return 2;
    }

    @Override
    public Cursor query(Uri uri, String[] strings, String s, String[] strings2, String s2) {
        Log.i("XXX" , "query:" + uri);

        Cursor c = new MyCursor(getData());

        return c;
    }


    private List<Map<String, Object>> getData() {
        List<Map<String, Object>> ret = new ArrayList<Map<String, Object>>();
        for (int i = 0; i < 1000; i++) {
            ret.add(getItem(i));
        }
        return ret;
    }

    private Map<String, Object> getItem(int v) {
        String str = nextSessionId();
        Map<String, Object> m1 = new HashMap<String, Object>();
        m1.put("id", v);
        m1.put("name" , "name-" + v + "-" + str);
        m1.put("address" , "address-" + v + "-" + str);
        return m1;
    }

    private SecureRandom random = new SecureRandom();

    public String nextSessionId() {
        return new BigInteger(30, random).toString(32);
    }
}

ItemLayout

public class ItemLayout extends LinearLayout {

    private TextView tv1;
    private TextView tv2;
    private TextView tv3;

    public ItemLayout(Context context) {
        super(context);
    }

    public ItemLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public ItemLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

//    public ItemLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
//        super(context, attrs, defStyleAttr, defStyleRes);
//    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();

        tv1 = (TextView) findViewById(R.id.textView1);
        tv2 = (TextView) findViewById(R.id.textView2);
        tv3 = (TextView) findViewById(R.id.textView3);
    }

    public void bindView(String id, String name, String address) {
        tv1.setText(id);
        tv2.setText(name);
        tv3.setText(address);
    }

}

Activity Layout

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.example.test05.MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="40dp"
        android:text="CursorTest"
        android:id="@+id/textView2"
        android:textStyle="bold"
        android:textSize="30sp"
        android:textColor="#2d3043"
        android:layout_alignParentStart="true" />

    <ListView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/listView"
        android:layout_below="@+id/textView2"
        android:layout_alignParentEnd="true" />
    
</RelativeLayout>

Item Layout

<?xml version="1.0" encoding="utf-8"?>
<com.example.test05.ItemLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent" android:layout_height="50dp"
    android:orientation="horizontal"
    android:weightSum="1">

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:background="#ffffff"
        android:gravity="center"
        android:text="New Text1"
        android:typeface="monospace" />

    <TextView
        android:id="@+id/textView2"
        android:layout_width="86dp"
        android:layout_height="match_parent"
        android:layout_gravity="center_horizontal"
        android:layout_weight="0.26"
        android:gravity="center"
        android:text="New Text2"
        android:typeface="monospace" />

    <TextView
        android:id="@+id/textView3"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_gravity="right"
        android:layout_weight="0.68"
        android:gravity="center"
        android:text="New Text3"
        android:typeface="monospace" />

</com.example.test05.ItemLayout>