23
25

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

JSON(Volley)+ListViewでページング。くるくる付き。

Posted at

sqlite版を作り、JSON版もほぼ同じに作りたかったけど、経験と能力不足で挫折。とりあえず動くコードをメモ。

###やりたいこと
・WebAPI(PHP)からJSONを取得し、ページング表示。移動(待ち)時間には「くるくる」を表示。
・データの最後まできたら「これ以上データはない」的なメッセージを出す。

###作ったファイル

  1. MyActivity.java (説明なし)
  2. Member.java(取り扱うデータ)
  3. MemberAdapter.java(カスタムアダプター)
  4. MyData.java(データを非同期で取得するクラス)
  5. footer.xml(フッター用レイアウト)
  6. row.xml(ListViewの1行ずつのレイアウト)

###課題・考察
sqliteを使う場合と統合ができなかった。。。それは後日の課題とする。
最初の読み込み時だけは、処理を変えたかったけど、可読性重視で特に何もしてない。
(データがないとonScrollが発生するので、そのまま読み込みに利用)

###ポイント
MyData.javaにMyActivity.javaの方から、Volleyに必要なContextとRequestQueue。そして、非同期でデータ追加の対象となるadapterを引数で渡してやってます。

###ソース

MyActivity.java
public class MyActivity extends Activity implements AbsListView.OnScrollListener{

    private RequestQueue myQueue;

    private ArrayList<Member> members;
    private MemberAdapter adapter;
    private ListView myListView;
    private View myFooter;

    private MyData myData;
    private AsyncTask<Void,Void,Void> myTask;

    //
    private int page = 0;
    private int page_rows = 20;
    private int offset = page * page_rows;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_my);

        //queue
        myQueue = Volley.newRequestQueue(this);

        //array list
        members = new ArrayList<Member>();

        //adapter
        adapter = new MemberAdapter(this,0,members);

        //ListView
        myListView = (ListView)findViewById(R.id.myListView);
        myListView.setAdapter(adapter);

        //footer
        myFooter = getLayoutInflater().inflate(R.layout.footer,null);
        myListView.addFooterView(myFooter);

        //リスナー設定(忘れがち)
        myListView.setOnScrollListener(this);

        //getdata(初期化)
        myData = new MyData(this,myQueue,adapter);
        //ここで最初のデータをとってもいいけど、とりあえず同じロジックであとまわし
        //myData.getData();

    }

    @Override
    public void onScrollStateChanged(AbsListView absListView, int i) {
        //
    }

    @Override
    public void onScroll(AbsListView absListView, int i, int i2, int i3) {
        if(i3 == i + i2){
            //データの最後を判別(本当はgetCount関数等を使って取得する)
            if(i3>=100){
                myListView.removeFooterView(myFooter);
                Toast.makeText(this,"これ以上データはありません。",Toast.LENGTH_SHORT).show();
                return;
            }
            addItems();
        }
    }

    //追加用関数
    private void addItems(){

        //すでに処理中であれば何もしない
        if(myTask != null && myTask.getStatus() == AsyncTask.Status.RUNNING){
            return;
        }

        //タスク実行
        myTask = new MyAsyncTask().execute();
    }

    //非同期クラス
    public class MyAsyncTask extends AsyncTask<Void,Void,Void>{

        @Override
        protected Void doInBackground(Void... voids) {

            //ダミーのくるくる表示
            try{
                Thread.sleep(1000);
            }catch(Exception e){
                e.printStackTrace();
            }
            offset = page * page_rows;

            //データを取得(そして追加)
            myData.getData(offset,page_rows);

            return null;
        }

        @Override
        protected void onPostExecute(Void aVoid) {
            super.onPostExecute(aVoid);

            //成功したらpageをインクリメント
            page++;

        }
    }
}

Member.java
public class Member {

    private String name;
    private String url;

    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);
        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);

        TextView name = (TextView)convertView.findViewById(R.id.name);
        name.setText(member.getName());
        TextView url = (TextView)convertView.findViewById(R.id.url);
        url.setText(member.getUrl());

        return convertView;
    }
}

まあ肝と言えば、肝のクラス。

MyData.java
public class MyData {

    private RequestQueue myQueue;
    private MemberAdapter adapter;

    private ArrayList<Member> members;

    //コンストラクタ
    //コンテキストと、Volley用のQueue、そして追加処理をおこなうためのadapterを受け取る
    public MyData(Context context,RequestQueue myQueue,MemberAdapter adapter) {

        this.myQueue = myQueue;
        this.adapter = adapter;
    }

    //データの取得と更新(offsetとlimitを受け取る)
    public void getData(int offset,int limit){

        members = new ArrayList<Member>();

        String url = "http://www.bluecode.jp/test/getMembers.php?offset="+offset+"&limit="+limit;

        JsonObjectRequest request = new JsonObjectRequest(Request.Method.GET,url,null,
                new Response.Listener<JSONObject>() {
                    @Override
                    public void onResponse(JSONObject jsonObject) {

                        try{
                            JSONArray json_members = jsonObject.getJSONArray("members");
                            for(int i=0;i<json_members.length();i++){
                                JSONObject json_member = json_members.getJSONObject(i);

                                String name = json_member.getString("name");
                                String url = json_member.getString("url");

                                Member member = new Member();
                                member.setName(name);
                                member.setUrl(url);

                                members.add(member);

                            }

                            //adapterに追加・反映
                            adapter.addAll(members);

                        }catch (Exception e){
                            e.printStackTrace();
                        }

                    }
                }
                ,
                new Response.ErrorListener(){
                    @Override
                    public void onErrorResponse(VolleyError volleyError) {
                        //とりあえず何もしない
                    }
                }
        );

        //Queueに追加(JSON取得処理)
        myQueue.add(request);
    }

}
footer.xml
<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal" android:layout_width="match_parent"
    android:layout_height="match_parent"
    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 xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="fill_parent"
    android:padding="3dp"
    android:layout_height="wrap_content">

    <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="fill_parent"
            android:layout_height="wrap_content"
            android:text="name"
            android:id="@+id/name" />

        <TextView
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:text="url"
            android:id="@+id/url" />
    </LinearLayout>
</LinearLayout>
23
25
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
23
25

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?