Android Market公開を目指してAndroidアプリを開発する!(翻訳履歴保存編)では、翻訳結果をSQLiteに保存するようにしたので、今回は、その結果を参照する機能を実装していきたいと思います。
データベースは前回のサンプルで作成したものを利用します。
今回のサンプルは、ArrayAdapterとListViewコントロールを使って、翻訳履歴を一覧表示するだけという単純なのものにしました。
まず、前回作ったData Access Object(DAO)に、翻訳履歴を取得する処理を追加します。
public Cursor find(String[] columns, String order, String limit) {
SQLiteDatabase db = connection.getWritableDatabase();
Cursor cursor = db.query(false, ITranslate.TABLE_NAME, columns, null, null, null, null, order, limit);
return cursor;
}
次に、翻訳結果の情報を格納しているTranslateModelクラスにtoString()関数をオーバーライドします。
@Override
public String toString() {
return translated;
}
後は、SQLiteから取得した翻訳結果をArrayAdapterクラスに格納して、それをListViewコントロールにセットします。
package jp.flashcast.translator.android;
import jp.flashcast.translator.android.dao.TranslateDao;
import jp.flashcast.translator.android.model.TranslateModel;
import android.app.Activity;
import android.database.Cursor;
import android.os.Bundle;
import android.provider.BaseColumns;
import android.widget.ArrayAdapter;
import android.widget.ListView;
public class TranslatorSample5 extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
TranslateDao dao = new TranslateDao(this);
ArrayAdapter<TranslateModel> adapter = new ArrayAdapter<TranslateModel>(this, android.R.layout.simple_list_item_1);
addTranslateModel(adapter, dao.find(null, BaseColumns._ID + " DESC", null));
ListView view = (ListView)findViewById(R.id.histories);
view.setAdapter(adapter);
}
private void addTranslateModel(ArrayAdapter<TranslateModel> adapter, Cursor cursor) {
if (cursor != null) {
if (cursor.getCount() > 0) {
while (cursor.moveToNext()) {
TranslateModel model = new TranslateModel();
model.setId(cursor.getInt(0));
model.setOriginal(cursor.getString(1));
model.setTranslated(cursor.getString(2));
model.setSrcLanguage(cursor.getString(3));
model.setDstLanguage(cursor.getString(4));
model.setDt(cursor.getString(5));
adapter.add(model);
}
}
}
}
}
TranslateModelクラスにtoString()関数をオーバーライドしたことで、翻訳結果だけが一覧に表示されるようになります。
画面レイアウトのXMLはこんな感じです。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<ListView
android:id="@+id/histories"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
</LinearLayout>
実行結果はこちら。
あまりにシンプルすぎるので、もうちょっと工夫したいと思います。
- ListViewの1行に翻訳前と翻訳後、翻訳した時間を表示し、削除ボタンもつける。
- 件数が増えてくると画面が長くなりすぎるので、一覧の下に「もっと読む」みたいな機能をつけて、はじめは特定の件数だけ表示する。
では、これを実現するにはどうするか?
ArrayAdapterの親クラスであるBaseAdapterを継承したクラスと、ListViewクラスを継承したクラスを実装して実現します。
前者については、こちらが非常に参考になりました。
ListViewを拡張する方法 | public static void main
まず、1行のレイアウトにあたるXMLを用意します。
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content"> <LinearLayout android:orientation="vertical" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" > <TextView android:id="@+id/original" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_gravity="left" android:layout_marginLeft="10sp" android:singleLine="true" android:textSize="15sp" android:textStyle="bold" /> <TextView android:id="@+id/translated" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_gravity="left" android:layout_marginLeft="10sp" android:singleLine="true" android:textSize="12sp" /> <RelativeLayout android:layout_width="wrap_content" android:layout_height="wrap_content"> <TextView android:id="@+id/dt" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:layout_marginRight="10sp" android:textSize="12sp" /> </RelativeLayout> </LinearLayout> <ImageView android:id="@+id/delete" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical|center_horizontal" android:layout_marginRight="5sp" /> </LinearLayout>
次に、ArrayAdapterの親クラスであるBaseAdapterを継承したクラスを作ります。1行のレイアウトはgetView()関数の中で設定(42行目)します。
package jp.flashcast.translator.android.adapter;
import java.util.ArrayList;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.OnClickListener;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import jp.flashcast.translator.android.R;
import jp.flashcast.translator.android.manager.HistoryManager;
import jp.flashcast.translator.android.model.TranslateModel;
import jp.flashcast.translator.android.view.TranslateListView;
public class TranslateAdapter extends BaseAdapter {
private LayoutInflater inflater;
private ArrayList<TranslateModel> list;
private HistoryManager manager;
public TranslateAdapter(Context context, ArrayList<TranslateModel> list, HistoryManager manager) {
this.list = list;
this.manager = manager;
this.inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
public int getCount() {
return list.size();
}
public Object getItem(int position) {
return list.get(position);
}
public long getItemId(int position) {
return list.get(position).getId();
}
public View getView(int position, View convertView, ViewGroup parent) {
convertView = inflater.inflate(R.layout.list_item, null);
TextView original = (TextView)convertView.findViewById(R.id.original);
TextView translated = (TextView)convertView.findViewById(R.id.translated);
TextView dt = (TextView)convertView.findViewById(R.id.dt);
ImageView image = (ImageView)convertView.findViewById(R.id.delete);
original.setText(list.get(position).getOriginal());
translated.setText(list.get(position).getTranslated());
dt.setText(list.get(position).getDt());
image.setImageResource(android.R.drawable.ic_menu_delete);
image.setId(list.get(position).getId());
image.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
manager.delete(v.getId());
int max = manager.getHistoriesCount();
int len = manager.setTranslateAdapter(TranslateAdapter.this, true);
int pos = HistoryManager.HISTORY_LIST_VIEW_COUNT * (manager.getPage() - 1);
TranslateListView view = ((TranslateListView)v.getParent().getParent());
view.setAdapter(TranslateAdapter.this);
view.setFooterVisible(!(len == max));
view.setSelection((max > pos) ? pos : max);
}
});
return convertView;
}
public void add(TranslateModel model) {
list.add(model);
}
public void clear() {
list.clear();
}
}
55~68行目が削除ボタンクリック時の処理になります。
続いて、後者のほうです。
件数が増えてくると画面が長くなりすぎるので、一覧の下に「もっと読む」みたいな機能をつけて、はじめは特定の件数だけ表示する。
こちらのサイトが非常に参考になりました。
tappli blog: [Android] ListViewとFooterView
サンプルソースがダウンロードできるのはとてもありがたいです!
ListViewを継承したクラスを作ります。
package jp.flashcast.translator.android.view;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ImageView;
import android.widget.ListView;
import jp.flashcast.translator.android.R;
public class TranslateListView extends ListView {
private View footer;
private boolean visible;
public TranslateListView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public void addFooterView(View footer) {
super.addFooterView(footer);
if (this.footer != null) {
removeFooterView(this.footer);
}
this.footer = footer;
ImageView img = (ImageView)this.footer.findViewById(R.id.more);
img.setImageResource(android.R.drawable.ic_menu_more);
}
public void setFooterVisible(boolean visible) {
if (this.footer != null) {
if (!visible) {
removeFooterView(this.footer);
}
}
this.visible = visible;
}
public boolean isFooterVisible() {
return this.visible;
}
}
実行結果はこちら。
●初期表示
※ ここでは、翻訳履歴が少なくてもいいように、2件づつ表示されるようににしています。
●一覧の一番下の行(もっと読むのような)を押した後
●削除ボタンを押して履歴をすべて削除した後
さっきよりも、使い勝手も良くなったのではないかと思います!



