之前一段时间在做列表的交互功能,UI要求做成GridView,后来又要求做成每一页固定的可以翻页的GridView。下面贴个Demo:

  Demo:可翻页的GridView(错误)



import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import android.os.Bundle;
import android.app.Activity;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.GridView;
import android.widget.SimpleAdapter;

public class MainActivity extends Activity 
{
    int line = 2;
    int column =6;
    int page = 1;
    ArrayList<Map<String,Object>> sublist = new ArrayList<Map<String,Object>>();
    SimpleAdapter adapter_01;
    GridView gv;
    
    @Override
    public void onCreate(Bundle savedInstanceState) 
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        final Button pagedown = (Button)findViewById(R.id.pagedown);
        final Button pageup = (Button)findViewById(R.id.pageup);
                
        gv = (GridView)findViewById(R.id.gv);       
        gv.setNumColumns(column);
        gv.setVerticalSpacing(50);
                
        final String [] number = new String[]
                {
                "1","2","3","4","5","6"
                ,"7","8","9","10",
                "11","12","13","14","15","16","17","18","19","20",
                "21","22","23","24","25","26"
                ,"27","28","29","30",
                "31","32","33","34","35","36","37","38","39","40"
                };
        final ArrayList<Map<String,Object>> list = new ArrayList<Map<String,Object>>();
       
        for(int i=0;i<number.length;i++)
        {
            Map<String,Object> listitem = new HashMap<String,Object>();            
            listitem.put("id", number[i]);
            list.add(listitem);
        }
        
        sublist = getlist(list, page, line, column);
        pageup.setClickable(false);
        if(sublist.size()<line*column) pagedown.setClickable(false);
        adapter_01 = new SimpleAdapter(this
                ,sublist
                ,R.layout.list
                ,new String[]{"id"}
                ,new int[]{R.id.tv});
        gv.setAdapter(adapter_01);

        pagedown.setOnClickListener(new OnClickListener() 
        {            
            public void onClick(View v) 
            {                            
                page++;
                sublist.clear();
                sublist = getlist(list, page, line, column);
                gv.setAdapter(adapter_01);
                adapter_01.notifyDataSetChanged();
                Log.v("sublist",""+sublist);
                pageup.setClickable(true);
                if(sublist.size()<line*column) 
                {
                    pagedown.setClickable(false);
                }
                else 
                {
                    pagedown.setClickable(true);
                }
            }
        });
        
        pageup.setOnClickListener(new OnClickListener() 
        {            
            public void onClick(View v) 
            {
                page--;
                sublist.clear();
                sublist = getlist(list, page, line, column);
                gv.setAdapter(adapter_01);
                adapter_01.notifyDataSetChanged();
                Log.v("sublist",""+sublist);
                pagedown.setClickable(true);
                if(page==1)
                {
                    pageup.setClickable(false);
                }
                else 
                {
                    pageup.setClickable(true);
                }
            }
        });
    
    }
    public ArrayList<Map<String,Object>> getlist(ArrayList<Map<String,Object>> list,int page,int line,int column)
    {        
        ArrayList<Map<String,Object>> sublist = new ArrayList<Map<String,Object>>();       
        for(int k=0,i=(page-1)*line*column;i<list.size()&&k<line*column;i++,k++)
        {
            sublist.add(list.get(i));           
        }
        return sublist;
    }
}



  以上程序本来是要实现GridView翻页显示,每一页显示一个2行6列的子GridView——即第一页显示1~12,第二页显示2~24,以此类推。但是单击pagedown按钮翻页,发现显示了一个空白页。查看sublist的Log输出:

java mognodb存储时间_java mognodb存储时间

sublist的内容确实已经更新了,可是为什么没有显示出来?怀疑的对象也只能是adapter了。之前也用过adapter的notifydatasetchanged()方法更新list,并没有出现类似的问题,百思不得其解后,先找了个方法先把功能实现了,以进行后续的工作:



1 pagedown.setOnClickListener(new OnClickListener() 
 2         {            
 3             public void onClick(View v) 
 4             {                            
 5                 page++;
 6                 sublist = getlist(list, page, line, column);
 7                 SimpleAdapter adapter_01 = new SimpleAdapter(MainActivity.this
 8                         ,sublist
 9                         ,R.layout.list
10                         ,new String[]{"id"}
11                         ,new int[]{R.id.tv});
12                 gv.setAdapter(adapter_01);
13                 adapter_01.notifyDataSetChanged();
14                 pageup.setClickable(true);
15                 if(sublist.size()<line*column) 
16                 {
17                     pagedown.setClickable(false);
18                 }
19                 else 
20                 {
21                     pagedown.setClickable(true);
22                 }
23             }
24         });



  看到这不要笑我,我也知道每翻一页就新建一个adapter,效率之低下。。。只是为了不打断后面的工作,硬着头皮写上去的。这样写之后,也确实可以实现预期的功能了。

  然而出来混,总是要还的,终于问题到了非解决不可得时候。我将代码与之前成功的例子仔细比较,发现以前的更新,都是为列表添加/删除操作——即add,remove之类,而这次的关键语句是通过getlist方法直接获得下一页的子表。问题就出在这里。

  1)sublist这个名字,表示的是一个引用,存储在栈内存空间中,当它第一次调用getlist方法时,它就指向了堆内存的某个空间,这个空间存储的是getlist方法获得的第一个子表(第一页);

  2)创建adapter,将sublist作为其第二个参数存入,关键就是这里,原本以为adapter存入的是sublist这个引用,但这只是自己一厢情愿。先看SimpleAdapter源码:



1 public class SimpleAdapter extends BaseAdapter implements Filterable {
 2     private int[] mTo;
 3     private String[] mFrom;
 4     private ViewBinder mViewBinder;
 5 
 6     private List<? extends Map<String, ?>> mData;
 7 
 8     private int mResource;
 9     private int mDropDownResource;
10     private LayoutInflater mInflater;
11 
12     private SimpleFilter mFilter;
13     private ArrayList<Map<String, ?>> mUnfilteredData;
14 
15     /**
16      * Constructor
17      * 
18      * @param context The context where the View associated with this SimpleAdapter is running
19      * @param data A List of Maps. Each entry in the List corresponds to one row in the list. The
20      *        Maps contain the data for each row, and should include all the entries specified in
21      *        "from"
22      * @param resource Resource identifier of a view layout that defines the views for this list
23      *        item. The layout file should include at least those named views defined in "to"
24      * @param from A list of column names that will be added to the Map associated with each
25      *        item.
26      * @param to The views that should display column in the "from" parameter. These should all be
27      *        TextViews. The first N views in this list are given the values of the first N columns
28      *        in the from parameter.
29      */
30     public SimpleAdapter(Context context, List<? extends Map<String, ?>> data,
31             int resource, String[] from, int[] to) {
32         mData = data;
33         mResource = mDropDownResource = resource;
34         mFrom = from;
35         mTo = to;
36         mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
37     }
38 ......
39 }



  看到了吧,上面SimpleAdapter的构造器,把传入的第二个参数赋给了mData,也就此时mData指向了第一个子表(第一页)的堆内存空间,然而改变了sublist之后,sublist已经指向了第二个子表(第二页)的堆内存空间,可是mData仍然指向原来的对内存空间,adapter的notifydatasetchanged()方法仅仅是更新mData指向的数据,所以出现了上述现象。

  下面来验证这个说法。先吐槽一下,java中没有类似C语言的‘&’——地址操作符,个人感觉不是很方便啊。不过还好Object中使用equals方法,比较的就是地址,可以用这个方法判断sublist=getlist()前后是否改变了指向的地址。

  将程序改为



1 pageup.setOnClickListener(new OnClickListener() 
 2         {            
 3             public void onClick(View v) 
 4             {
 5                 page--;
 6                 ArrayList<Map<String,Object>> a = sublist;
 7                 sublist.clear();
 8                 Log.v("before:a.equals(sublist)",""+a.equals(sublist));
 9                 sublist = getlist(list, page, line, column);
10                 Log.v("before:a.equals(sublist)",""+a.equals(sublist));
11                 SimpleAdapter adapter_01 = new SimpleAdapter(MainActivity.this
12                         ,sublist
13                         ,R.layout.list
14                         ,new String[]{"id"}
15                         ,new int[]{R.id.tv});
16                 gv.setAdapter(adapter_01);
17                 adapter_01.notifyDataSetChanged();
18                 pagedown.setClickable(true);
19                 if(page==1)
20                 {
21                     pageup.setClickable(false);
22                 }
23                 else 
24                 {
25                     pageup.setClickable(true);
26                 }
27             }
28         });



  其日志打印为

java mognodb存储时间_移动开发_02

  果然前后两次不同了。在将程序进行修改:



1 pagedown.setOnClickListener(new OnClickListener() 
 2         {            
 3             public void onClick(View v) 
 4             {                            
 5                 page++;
 6                 ArrayList<Map<String,Object>> a = sublist;
 7                 sublist.clear();
 8                 Log.v("before:a.equals(sublist)",""+a.equals(sublist));                
 9                 for(int i = 0;i < getlist(list, page, line, column).size(); i++)
10                 {
11                     sublist.add(getlist(list, page, line, column).get(i));
12                 }
13                 Log.v("before:a.equals(sublist)",""+a.equals(sublist));
14                 adapter_01.notifyDataSetChanged();
15                 pageup.setClickable(true);
16                 if(sublist.size()<line*column) 
17                 {
18                     pagedown.setClickable(false);
19                 }
20                 else 
21                 {
22                     pagedown.setClickable(true);
23                 }
24             }
25         });



 

  这就实现了不改变sublist的指向,从程序的运行结果看果然

java mognodb存储时间_android_03

  java的基础才是对android的最可靠保证啊,对于java看了1个月就学android的我来说,尤其如此。。