やりたいこと
・sqliteでデータとってきて、30行表示し、移動するときに「くるくる」を表示し、次に向かう。
・データの最後まできたら「これ以上データはない」的なメッセージを出す。
・sqliteだけじゃなくて、ネットからJSON取る場合にも汎用的に使いたい(これ重要)
作ったファイル
-
MyActivity.java(説明なし)
-
Member.java (取り扱うデータ)_id,name,urlだけ。
-
MemberAdapter.java (上記を扱うためのカスタムアダプタ)
-
MyDbHelper.java (DBのヘルパー)
-
MyDataControl.java (データの取得を担うクラス。たぶん肝)
-
footer.xml (くるくる表示)
-
row.xml (1行ずつのView)
その他
pull-to-refreshとかも付けたかったけど、複雑になるのでまた今度。
たぶん、refleshでadapter.add(item)じゃなくて、adapter.insert(item,0)とかやるとうまくいくのだろうと楽観視。
ソース
MyActivity.java
public class MyActivity extends Activity implements AbsListView.OnScrollListener{
//
//必要なもの初期化
private MyDbHelper myDbHelper; //dbhelper
private SQLiteDatabase db; //sqlite
private ArrayList<Member> members; //ArrayList
private ListView myListView; //ListView
private View footerView; //FooterView くるくる用
private AsyncTask<Integer,Void,ArrayList<Member>> myTask; //AsyncTask 追加処理を行う
private MemberAdapter adapter; //adapter
//カスタムのデータ取得クラス
private MyDataControl myDataControl;
//ページング関連
private int page_rows = 30;
private int page = 0;
private int offset = page_rows * page;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my);
//DBを取得
myDataControl = new MyDataControl(this);
//arrayを取得
members = new ArrayList(myDataControl.getPagingData(offset,page_rows));
//adapter
adapter = new MemberAdapter(this,0,members);
//ListView
myListView = (ListView)findViewById(R.id.myListView);
//Footer
footerView = getLayoutInflater().inflate(R.layout.footer,null);
myListView.addFooterView(footerView);
//adapter追加
myListView.setAdapter(adapter);
//scrollリスナ設定。これ忘れがち
myListView.setOnScrollListener(this);
}
@Override
public void onScrollStateChanged(AbsListView absListView, int i) {
}
@Override
public void onScroll(AbsListView absListView, int i, int i2, int i3) {
//最後なら
if(i3 == i + i2){
//データが無い
if(i3 >= myDataControl.getCount()){
myListView.removeFooterView(footerView);
//これ、連続発生するので本当はflgで表示制御した方がよい。本質ではないので、とりあえずこのまま。
Toast.makeText(this,"これ以上データはありません。",Toast.LENGTH_SHORT).show();
}else {
//データがある
addItems();
}
}
}
private void addItems(){
if(myTask != null && myTask.getStatus() == AsyncTask.Status.RUNNING){
//何もしない
return;
}
//ページをインクリメント
page++;
//非同期タスクを実行
//pageを渡すもglobal変数にしてあるので意味は無い(引数のテスト)
myTask = new MyAsyncTask(this).execute(page);
}
public class MyAsyncTask extends AsyncTask<Integer,Void,ArrayList<Member>>{
public MyAsyncTask(MyActivity androidAsyncTaskActivity){
}
@Override
protected ArrayList<Member> doInBackground(Integer... integers) {
//ダミーの待ち時間(但し、演出として普通でも使う)
try{
Thread.sleep(1000);
}catch(Exception e){
e.printStackTrace();
}
//pageを受けとる
//但し、gloal変数にしてあるので意味なし
Log.v("tama","params="+Integer.toString(integers[0]));
//offset計算
offset = page * page_rows;
//データを取得
ArrayList members = myDataControl.getPagingData(offset,page_rows);
return members;
}
@Override
protected void onPostExecute(ArrayList<Member> members){
//adapterに追加
adapter.addAll(members);
}
}
}
Member.java
public class Member {
private int id;
private String name;
private String url;
public int getId(){
return this.id;
}
public String getName(){
return this.name;
}
public void setName(String name){
this.name = name;
}
public String getUrl(){
return this.url;
}
public void setUrl(String url){
this.url = url;
}
}
MemberAdapter.java
public class MemberAdapter extends ArrayAdapter<Member> {
private LayoutInflater layoutInflater;
public MemberAdapter(Context context, int resource, ArrayList<Member> members) {
super(context, resource, members);
//inflaterを初期化(これ忘れがち)
this.layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
@Override
public View getView(int position,View convertView, ViewGroup parent){
if(convertView == null){
convertView = layoutInflater.inflate(R.layout.row,null);
}
Member member = (Member)getItem(position);
//本当はViewHolderにすべき(わかりやすさ重視)
//View
TextView name = (TextView)convertView.findViewById(R.id.text1);
name.setText(member.getName());
TextView url = (TextView)convertView.findViewById(R.id.text2);
url.setText(member.getUrl());
//Viewを戻す
return convertView;
}
}
MyDbHelper.java
public class MyDbHelper extends SQLiteOpenHelper {
//直接初期化
public MyDbHelper(Context context) {
super(context, "test.db", null, 2);
}
@Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
//_id
//name
//url : これは後で画像の取得に使うつもり
//create
sqLiteDatabase.execSQL("create table members(" +
"_id integer primary key autoincrement," +
"name text," +
"url text)");
//init(テストデータ生成)
for(int i=0;i<100;i++) {
String member_name = "member"+i;
String member_url = String.format("%03d",i);
sqLiteDatabase.execSQL("insert into members(name,url) values('"+member_name+"','http://www.bluecode.jp/test/image/"+member_url+".jpg')");
}
}
@Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i2) {
//delete
sqLiteDatabase.execSQL("drop table if exists members");
//
onCreate(sqLiteDatabase);
}
}
MyDataControl.java
public class MyDataControl {
//必要なものを初期化
MyDbHelper myDbHelper;
SQLiteDatabase db;
ArrayList<Member> members;
//コンストラクタ(DbOpenHelperが使うのでcontextをもらう)
public MyDataControl(Context context){
myDbHelper = new MyDbHelper(context);
}
//pagingしたデータをArrayList<Member>で返す
//これ以下をネットからJSONを取得してArrayListで返すようなコードに書き換えれば、WebAPIにも使える(はず)
public ArrayList<Member> getPagingData(int offset,int limit){
//DB
db = myDbHelper.getReadableDatabase();
//ArrayList初期化
members = new ArrayList<Member>();
//取得
//本当はContentProviderとか使うべきだけど、非同期プロセスから呼ばれるのでとりあえず直接取得。
Cursor cursor = db.query(
"members",
null,
null,
null,
null,
null,
null,
Integer.toString(offset)+","+Integer.toString(limit)
);
//ArrayListにコピー(なんか無駄)
while (cursor.moveToNext()){
Member member = new Member();
member.setName(cursor.getString(cursor.getColumnIndex("name")));
member.setUrl(cursor.getString(cursor.getColumnIndex("url")));
members.add(member);
}
//戻す
return members;
}
//全てのデータ数を返す(おしりの判定に使う)
public int getCount(){
Cursor cursor = db.query(
"members",
null,
null,
null,
null,
null,
null
);
int cnt = cursor.getCount();
return cnt;
}
}
footer.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical|center">
<ProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/progressBar" />
</LinearLayout>
row.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="3dp"
xmlns:android="http://schemas.android.com/apk/res/android">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_launcher"
android:id="@+id/image" />
<LinearLayout
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hoge"
android:id="@+id/text1"
android:textSize="14dp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="foo"
android:id="@+id/text2"
android:textSize="12dp" />
</LinearLayout>
</LinearLayout>
あーしんど。