adapter+线程
1.很多时候自定义adapter的数据都是来源于服务器的,所以在获取服务器的时候就需要异步获取,这里就需要开线程了(线程池)去获取服务器的数据了。但这样有的时候adapter的中没有数据。
如下面的代码:
这就是在initData中异步获取服务器的数据,然后实例化adatper,再将adapter赋给listView。
2.initData()中的代码是:
这里线程要睡眠5秒钟,是为了模仿网络的耗时操作
3.Handler:
在Handler中接收到数据后给list赋值后,告诉adapter数据改变了,要更改UI 了。
4.自定义中的Myadapter中的一段代码:
这段代码就是想在实例化Myadapter的时候根据数据的长度来new一个对应长度的数组。
5.上面的准备工作完成后运行程序:
报错说明list1.size是没有大小的;
经过验证后得到出错的原因是在这段代码上:
从代码的执行顺序来说,InitData方法在线程当中获取数据后通过handler进行处理后list列表就应该有数据了,但实际上是不会有数据的,因为开辟了线程进行耗时操作,它会继续在线程但中执行,而程序会自己执行下去,在初始化adapter的时候list就为空。所以要将必须是要将initData()异步后去值后在去adapter的初始化和给listView的赋值。就该将adapter和listView.setAdapter(adapter)这段代码放到:
这样就能获取到数据并付给listView 了。
显示的结果就是:
ListView中按钮滑动后状态丢失
上面的效果是出来了,现在又遇到另外一个问题就是checkbox的状态在滑动listview后会丢失
如:
在选中前面三个checkbox后,如果上拉的滑动listview后(至前三个checkbox都看不见了),在下拉去观察前三个checkbox的状态是没有被选中的状态,为什么我选择了状态,现在却没有选中呢?
这里在对listview的一个循环机制做个解释(引用自网络):
我们有大量的数据需要显示的时候,每个Item都去重复执行getView中的创建新的View的动作吗?这样做会耗费大量的资源去执行重复的事情,实际上Android为我们提供了一套重复利用的机制叫做“Recycler”:
原理简单描述下就是这样:
在 一个完整的ListView第一次出现时,每个Item都是Null的,getView的时候会跑到需要inflate一个Item的代码段,假设整个 view只能最多显示10个item,那么当滑动到第11个Item的时候,第一个item会放入“recycler”,如果第11个Item和放入 “Recycler”的item的view一致,那么就会使用"Recycler"里面的Item来显示,从而不用再重复inflate一次,这样大大节 省了创建View的工作,在需要显示大量数据时显得尤为重要
所以在listview重新引入item之前,就必须要将item中每个checkd 状态就要被记录下来:
对adapter中getView()的:
对ViewHolder进行一个解释:
就是一个持有者的类,他里面一般没有方法,只有属性,作用就是一个临时存储器,把你getView方法中每次翻的View存起来,可以下次再用。这样做的好处就是不必每次都到布局文件中去拿你的View,提高了效率
这里先对checks状态数组的长度初始化为list的长度,然后再getView()绘制listView的item的时候按顺序执行下来,如果checkBox的状态被改变了就记录到数组当中,而数组的下标就是item的位置。
在设置checkbox状态时,就直接根据对应数组中下标为Position的值。就OK了
这样就改变了滑动按钮状态丢失的情况。
这里发一个完整的代码:
1 public class MainActivity extends Activity { 2 3 private ListView listView; 4 5 Madapter adapter; 6 private List<HashMap<String, Object>> list; 7 8 private static final int LDADDATA = 0; 9 10 @Override 11 protected void onCreate(Bundle savedInstanceState) { 12 super.onCreate(savedInstanceState); 13 setContentView(R.layout.activity_main); 14 listView = (ListView) findViewById(R.id.listView); 15 initData(); 16 //从代码的执行顺序来说,InitData方法在线程当中获取数据后通过handler进行处理后list列表就应该有数据了,但实际上是不会有数据的, 17 //因为开辟了线程进行耗时操作,它会继续在线程但中执行,而程序会自己执行下去,在初始化adapter的时候list就为空 18 // adapter = new Madapter(MainActivity.this, R.layout.item, list); 19 // listView.setAdapter(adapter); 20 } 21 22 static class ViewHolder { 23 TextView title; 24 CheckBox checkBox; 25 } 26 27 private void initData() { 28 list = new ArrayList<HashMap<String, Object>>(); 29 final List<HashMap<String, Object>> list1 = new ArrayList<HashMap<String, Object>>(); 30 new Thread(new Runnable() { 31 32 @Override 33 public void run() { 34 try { 35 Thread.sleep(5000); 36 37 } catch (InterruptedException e) { 38 // TODO Auto-generated catch block 39 } 40 for (int i = 0; i < 20; i++) { 41 HashMap<String, Object> map = new HashMap<String, Object>(); 42 map.put("title", "title" + i); 43 list1.add(map); 44 } 45 Message message = myHandler.obtainMessage(LDADDATA); 46 message.obj = list1; 47 message.sendToTarget(); 48 } 49 }).start(); 50 51 } 52 53 public Handler myHandler = new Handler() { 54 public void handleMessage(Message msg) { 55 switch (msg.arg1) { 56 case LDADDATA: 57 list = (List<HashMap<String, Object>>) msg.obj; 58 adapter = new Madapter(MainActivity.this, R.layout.item, list); 59 listView.setAdapter(adapter); 60 break; 61 default: 62 break; 63 64 } 65 66 }; 67 68 }; 69 public class Madapter extends BaseAdapter { 70 private int resource; 71 private LayoutInflater inflater; 72 private boolean[] checks; 73 74 public Madapter(Context context, int resource, 75 List<HashMap<String, Object>> list1) { 76 checks = new boolean[list1.size()]; 77 this.resource = resource; 78 inflater = (LayoutInflater) context 79 .getSystemService(Context.LAYOUT_INFLATER_SERVICE); 80 System.out.println("LIST的长度---->>" + list.size()); 81 } 82 83 @Override 84 public int getCount() { 85 return list.size(); 86 } 87 88 @Override 89 public Object getItem(int position) { 90 return list.get(position); 91 } 92 93 @Override 94 public long getItemId(int position) { 95 return position; 96 } 97 98 @Override 99 public View getView(int position, View convertView, ViewGroup parent) { 100 System.out.println("这句话执行了的"); 101 ViewHolder holder = null; 102 if (convertView == null) { 103 convertView = inflater.inflate(resource, null); 104 holder = new ViewHolder(); 105 holder.title = (TextView) convertView.findViewById(R.id.title); 106 holder.checkBox = (CheckBox) convertView 107 .findViewById(R.id.checkBox); 108 convertView.setTag(holder); 109 110 } else { 111 holder = (ViewHolder) convertView.getTag(); 112 } 113 holder.title.setText(list.get(position).get("title").toString()); 114 final int pos = position; 115 holder.checkBox 116 .setOnCheckedChangeListener(new CheckBox.OnCheckedChangeListener() { 117 118 @Override 119 public void onCheckedChanged(CompoundButton buttonView, 120 boolean isChecked) { 121 checks[pos] = isChecked; 122 System.out.println(isChecked); 123 } 124 }); 125 holder.checkBox.setChecked(checks[pos]); 126 127 return convertView; 128 } 129 130 } 131 132 @Override 133 public boolean onCreateOptionsMenu(Menu menu) { 134 getMenuInflater().inflate(R.menu.main, menu); 135 return true; 136 } 137 138 }
ListView状态丢失的扩展情况分析:
这时你就必须先将获得的按钮初始状态保存到对应的数组当中去,这里自己做个笔记:
1 public View getView(int position, View convertView, ViewGroup parent) { 2 final HashMap<String, Object> map = items.get(position); 3 ViewHolder holder = null; 4 if (convertView == null) { 5 convertView = inflater.inflate(R.layout.moniter_item, null); 6 holder = new ViewHolder(); 7 holder.temperture = (TextView) convertView 8 .findViewById(R.id.tempure_now); 9 holder.moist = (TextView) convertView 10 .findViewById(R.id.moist_now); 11 holder.soilTemperature = (TextView) convertView 12 .findViewById(R.id.soilTemperature_now); 13 holder.photosynthetic = (TextView) convertView 14 .findViewById(R.id.photosynthetic_now); 15 holder.soilhumidity = (TextView) convertView 16 .findViewById(R.id.soilumidity_now); 17 holder.radiation = (TextView) convertView 18 .findViewById(R.id.radiation_now); 19 holder.carbondioxide = (TextView) convertView 20 .findViewById(R.id.carbondioxide_now); 21 holder.lanName = (TextView) convertView 22 .findViewById(R.id.lan_num); 23 holder.sluiceToggButton = (ToggleButton) convertView 24 .findViewById(R.id.sluice); 25 holder.rollerToggButton = (ToggleButton) convertView 26 .findViewById(R.id.roller); 27 convertView.setTag(holder); 28 } else { 29 holder = (ViewHolder) convertView.getTag(); 30 } 31 32 final int pos = position; 33 34 // View view1 = RealtimeMoniterActivity.this.getLayoutInflater() 35 // .inflate(R.layout.moniter_item, null);// 消息 36 37 holder.temperture.setText(map.get("tempture").toString()); 38 holder.moist.setText(map.get("moist").toString()); 39 holder.soilTemperature.setText(map.get("soilTemperature") 40 .toString()); 41 holder.photosynthetic.setText(map.get("photosynthetic").toString()); 42 holder.soilhumidity.setText(map.get("soilhumidity").toString()); 43 holder.radiation.setText(map.get("radiation").toString()); 44 holder.carbondioxide.setText(map.get("carbondioxide").toString()); 45 holder.lanName.setText(map.get("realDataAreaName").toString()); 46 47 if (map.get("sluice").toString().equals("0")) { 48 sluiceCheck[pos] = false; 49 } else { 50 sluiceCheck[pos] = true; 51 } 52 53 if (map.get("roller").toString().equals("0")) { 54 rollerCheck[pos] = false; 55 } else { 56 rollerCheck[pos] = true; 57 } 58 59 holder.sluiceToggButton 60 .setOnCheckedChangeListener(new ToggleButton.OnCheckedChangeListener() { 61 62 @Override 63 public void onCheckedChanged(CompoundButton buttonView, 64 boolean isChecked) { 65 66 sluiceCheck[pos] = isChecked; //记录那个位置的toggbutton的状态改变成什么了; 67 if (isChecked) { 68 commandBase.request(new TaskListener() { 69 70 @Override 71 public void updateCacheDate( 72 List<HashMap<String, Object>> cacheData) { 73 74 } 75 76 @Override 77 public void start() { 78 } 79 80 @Override 81 public String requestUrl() { 82 return "updateStatus"; 83 } 84 85 @Override 86 public JSONObject requestData() { 87 88 JSONObject object1 = new JSONObject(); 89 try { 90 object1.put("id", map.get("id")); 91 object1.put("sluice", 1); 92 object1.put("roller", 93 (Integer) map.get("roller")); 94 } catch (JSONException e) { 95 e.printStackTrace(); 96 } 97 98 return object1; 99 } 100 101 @Override 102 public String readCache() { 103 return null; 104 } 105 106 @Override 107 public boolean needCacheTask() { 108 return false; 109 } 110 111 @Override 112 public void messageUpdated(JSONObject msg) { 113 } 114 115 @Override 116 public void finish() { 117 } 118 119 @Override 120 public String filepath() { 121 return null; 122 } 123 124 @Override 125 public void failure(String str) { 126 127 } 128 129 @Override 130 public String contentype() { 131 return null; 132 } 133 }); 134 135 map.put("sluice", 1); //因为不会自动去刷新map中的数据,所以在下拉, 136 //上拉滑动是从原来List<HashMap<.,.>>获取数据,这样就造成了状态药恢复到没改变前的状态,所以就必须去修改map中的对应的状态, 137 //这样在滑动的时候就获取的List<HashMap<.,.>>的数据就是已经改变过了,如果有自动刷新的按钮,这些问题就不会存在了 138 139 } else { 140 141 commandBase.request(new TaskListener() { 142 143 @Override 144 public void updateCacheDate( 145 List<HashMap<String, Object>> cacheData) { 146 147 } 148 149 @Override 150 public void start() { 151 152 } 153 154 @Override 155 public String requestUrl() { 156 return "updateStatus"; 157 } 158 159 @Override 160 public JSONObject requestData() { 161 162 JSONObject object1 = new JSONObject(); 163 try { 164 object1.put("id", map.get("id")); 165 object1.put("sluice", 0); 166 object1.put("roller", 167 (Integer) map.get("roller")); 168 } catch (JSONException e) { 169 e.printStackTrace(); 170 } 171 172 return object1; 173 } 174 175 @Override 176 public String readCache() { 177 return null; 178 } 179 180 @Override 181 public boolean needCacheTask() { 182 return false; 183 } 184 185 @Override 186 public void messageUpdated(JSONObject msg) { 187 } 188 189 @Override 190 public void finish() { 191 192 } 193 194 @Override 195 public String filepath() { 196 return null; 197 } 198 199 @Override 200 public void failure(String str) { 201 202 } 203 204 @Override 205 public String contentype() { 206 return null; 207 } 208 }); 209 map.put("sluice", 0);//因为不会自动去刷新map中的数据,所以在下拉, 210 //上拉滑动是从原来List<HashMap<.,.>>获取数据,这样就造成了状态药恢复到没改变前的状态,所以就必须去修改map中的对应的状态, 211 //这样在滑动的时候就获取的List<HashMap<.,.>>的数据就是已经改变过了,如果有自动刷新的按钮,这些问题就不会存在了 212 } 213 } 214 }); 215 216 holder.rollerToggButton 217 .setOnCheckedChangeListener(new ToggleButton.OnCheckedChangeListener() { 218 219 @Override 220 public void onCheckedChanged(CompoundButton buttonView, 221 boolean isChecked) { 222 rollerCheck[pos] = isChecked; 223 224 if (isChecked) { 225 commandBase.request(new TaskListener() { 226 227 @Override 228 public void updateCacheDate( 229 List<HashMap<String, Object>> cacheData) { 230 231 } 232 233 @Override 234 public void start() { 235 236 } 237 238 @Override 239 public String requestUrl() { 240 return "updateStatus"; 241 } 242 243 @Override 244 public JSONObject requestData() { 245 JSONObject object1 = new JSONObject(); 246 try { 247 object1.put("id", map.get("id")); 248 object1.put("sluice", 249 (Integer) map.get("sluice")); 250 object1.put("roller", 1); 251 } catch (JSONException e) { 252 e.printStackTrace(); 253 } 254 255 return object1; 256 } 257 258 @Override 259 public String readCache() { 260 return null; 261 } 262 263 @Override 264 public boolean needCacheTask() { 265 return false; 266 } 267 268 @Override 269 public void messageUpdated(JSONObject msg) { 270 System.out.println("返回的数据--->>" 271 + msg.toString()); 272 273 } 274 275 @Override 276 public void finish() { 277 278 } 279 280 @Override 281 public String filepath() { 282 return null; 283 } 284 285 @Override 286 public void failure(String str) { 287 288 } 289 290 @Override 291 public String contentype() { 292 return null; 293 } 294 }); 295 map.put("roller", 1);//因为不会自动去刷新map中的数据,所以在下拉, 296 //上拉滑动是从原来List<HashMap<.,.>>获取数据,这样就造成了状态药恢复到没改变前的状态,所以就必须去修改map中的对应的状态, 297 //这样在滑动的时候就获取的List<HashMap<.,.>>的数据就是已经改变过了,如果有自动刷新的按钮,这些问题就不会存在了 298 } else { 299 commandBase.request(new TaskListener() { 300 301 @Override 302 public void updateCacheDate( 303 List<HashMap<String, Object>> cacheData) { 304 305 } 306 307 @Override 308 public void start() { 309 310 } 311 312 @Override 313 public String requestUrl() { 314 return "updateStatus"; 315 } 316 317 @Override 318 public JSONObject requestData() { 319 JSONObject object1 = new JSONObject(); 320 try { 321 object1.put("id", map.get("id")); 322 object1.put("sluice", 323 (Integer) map.get("sluice")); 324 object1.put("roller", 0); 325 } catch (JSONException e) { 326 e.printStackTrace(); 327 } 328 329 return object1; 330 } 331 332 @Override 333 public String readCache() { 334 return null; 335 } 336 337 @Override 338 public boolean needCacheTask() { 339 return false; 340 } 341 342 @Override 343 public void messageUpdated(JSONObject msg) { 344 System.out.println("返回的数据--->>" 345 + msg.toString()); 346 } 347 348 @Override 349 public void finish() { 350 351 } 352 353 @Override 354 public String filepath() { 355 return null; 356 } 357 358 @Override 359 public void failure(String str) { 360 361 } 362 363 @Override 364 public String contentype() { 365 return null; 366 } 367 }); 368 map.put("roller", 0);//因为不会自动去刷新map中的数据,所以在下拉, 369 //上拉滑动是从原来List<HashMap<.,.>>获取数据,这样就造成了状态药恢复到没改变前的状态,所以就必须去修改map中的对应的状态, 370 //这样在滑动的时候就获取的List<HashMap<.,.>>的数据就是已经改变过了,如果有自动刷新的按钮,这些问题就不会存在了 371 372 } 373 374 } 375 }); 376 377 holder.sluiceToggButton.setChecked(sluiceCheck[pos]); 378 holder.rollerToggButton.setChecked(rollerCheck[pos]); 379 380 return convertView; 381 } 382 }
android 自定义adapter和线程结合 + ListView中按钮滑动后状态丢失解决办法,布布扣,bubuko.com
android 自定义adapter和线程结合 + ListView中按钮滑动后状态丢失解决办法
原文:http://www.cnblogs.com/liangstudyhome/p/3760078.html