2009年11月15日日曜日

LDReader ピンに対応しました

関連記事

ども。LDReader をピンに対応させて ver 0.0.5 としました。このブログにコメントいただいちゃったので^ ^
以下スナップショットです。



ちょと見づらいですが、記事タイトル右にピンアイコンがあります。このアイコンをクリックするかメニューから「Pin」を選択するとピンをつけたり外したりできます。

ピンは本家同様に一覧でみることができ、ブラウザで閲覧することができます。
その他、記事 1件の URL をクリップボードにコピーしたり、全件の URL リストをメールで送れるようにしときました。

簡単なバージョンアップですが、今回は少し悩んだ点があります。

単純に実装するとすれば、ピン操作は常にサーバに対して追加や削除を実行し、一覧は最新をサーバから持ってくれば良いです。しかし、これだと地下鉄のようなオフライン環境ではピンを追加することができません。

そこで次のような pin テーブルを作成して、ユーザの操作をまず action として保存し、それから通信を行うようにしました。追加の場合は 1:ACTION_ADD, 削除の場合は 2:ACTION_REMOVE, サーバから取得した場合は 0:ACTION_NONE とします。
create table if not exists pin (
_id integer primary key,
uri text,
title text,
action integer, -- 0:ACTION_NONE, 1:ACTION_ADD, 2:ACTION_REMOVE
created_time integer
)

ピンの追加はロジックはこんな感じ。
public boolean pinAdd(String uri, String title)
throws IOException, ReaderException {
if (!isLogined()) {
login();
}
try {
ContentResolver cr = this.context.getContentResolver();
// NOTE: 事前に uri が重複するピンアクションを削除
cr.delete(Pin.CONTENT_URI, Pin._URI + " = ? and " + Pin._ACTION
+ " > " + Pin.ACTION_NONE, new String[]{uri});
// NOTE: ピンアクションを追加。
ContentValues values = new ContentValues();
values.put(Pin._URI, uri);
values.put(Pin._TITLE, title);
values.put(Pin._ACTION, Pin.ACTION_ADD);
values.put(Pin._CREATED_TIME, (long) (System.currentTimeMillis() / 1000));
Uri pinUri = cr.insert(Pin.CONTENT_URI, values);
// NOTE: 端末がオフラインの場合はここで終了
if (!isConnected()) {
return true;
}
// NOTE: サーバと http 通信。失敗したら IOException などがスローされる。
boolean success = this.client.pinAdd(uri, title);
if (success) {
// NOTE: 通信が成功したら既存の重複ピンを削除して、
// 1:ACTION_ADD を 2:ACTION_NONE に更新。
cr.delete(Pin.CONTENT_URI, Pin._URI + " = ? and " + Pin._ACTION
+ " = " + Pin.ACTION_NONE, new String[]{uri});
values.put(Pin._ACTION, Pin.ACTION_NONE);
cr.update(pinUri, values, null, null);
}
return success;
} catch (ParseException e) {
throw new ReaderException("json parse error", e);
}
}

このままでは、端末がオフラインのときには 1:ACTION_ADD と 2:ACTION_REMOVE が溜まります。
そこで回線がオンラインになったら実行される処理にピンの同期処理を追加します。
public int syncPins() throws IOException, ReaderException {
if (!isLogined()) {
login();
}
ContentResolver cr = this.context.getContentResolver();
// NOTE: 1:ACTION_ADD と 2:ACTION_REMOVE の検索。
String where = Pin._ACTION + " > " + Pin.ACTION_NONE;
String order = Pin._ID + " asc";
Pin.FilterCursor cursor = new Pin.FilterCursor(
cr.query(Pin.CONTENT_URI, null, where, null, null));
try {
while (cursor.moveToNext()) {
// NOTE: 順番にピンアクションを再現
Pin pin = cursor.getPin();
if (pin.getAction() == Pin.ACTION_ADD) {
pinAdd(pin.getUri(), pin.getTitle());
} else {
pinRemove(pin.getUri());
}
Uri uri = ContentUris.withAppendedId(Pin.CONTENT_URI, pin.getId());
cr.delete(uri, null, null);
}
} finally {
cursor.close();
}
// NOTE: サーバからピン一覧を全件取得。
PinsHandler pinsHandler = new PinsHandler();
try {
this.client.handlePinAll(pinsHandler);
} catch (ParseException e) {
throw new ReaderException("json parse error", e);
}
return pinsHandler.counter;
}

関連するソースはこのへん。
@see org.jarx.android.livedoor.reader.Pin
@see org.jarx.android.livedoor.reader.PinActivity
@see org.jarx.android.livedoor.reader.ReaderManager

このピンの実装によってずいぶんと使い勝手が向上したように感じます。ありがとうございます。
次はウィジェットを実装予定です。

0 件のコメント: