- 浏览: 348593 次
- 性别:
- 来自: 上海
文章分类
- 全部博客 (139)
- Java (49)
- C# (23)
- 软件实施 (1)
- Mysql (8)
- Struts2&1.x (15)
- DWR (0)
- Javascript (7)
- Effective Java (8)
- Oracle (0)
- SqlServer (1)
- Spring (6)
- 数据结构 (2)
- 设计模式 (0)
- Hibernate (6)
- c++ (2)
- Qt (1)
- 瞎侃几句 (5)
- Openbravo2.5实施记录 (3)
- 工作总结 (6)
- 软件测试 (3)
- css (1)
- Android (13)
- Object-c (0)
- Html5 (1)
- jshoper开源项目 (34)
- Windows Phone (1)
- activiti (2)
最新评论
-
yzlseu:
没有思考,就是抄的,垃圾文章
Activiti5用户手册---Message Event Definitions -
yy756127197:
<timeDuration>P10D</ti ...
Activiti5用户手册---Events---Timer Event Definitions -
云端帕帕:
Activiti5用户手册---Events---Timer Event Definitions -
raychiong:
lz现在哪里高就呢?
记录一次高德软件面试经历 -
sdywcd:
water_quite 写道sdywcd 写道water_qu ...
jshoper3x在线商城系统更新说明及未来开发计划
情况:最近ostocy-jshop这个开源项目,一直在进行pad版本的更新工作。今天把遇到的一些问题说说。
1,我们要实现的功能是,动态获取商品分类,加载到tabhost中,并切换tabhost读取商品分类下的商品。且能够单独绑定listview中的imageview和其他控件。
这个功能在网上搜索后的问题有如下几点:
1,listview的onclick事件覆盖了imageview的事件。
2,tabhost在extends 和 implements TabContentFactory的时候只会在第一次进入新tabhost的title才会读取。这不能符合我们的要求,我们希望每次切换tabhost都可以进行数据的读取。
3,图片的压缩避免内存溢出。
我们的代码解决了如上2个问题。
主要的思路是:
1,重写BaseAdapter对listview的空间进行单独绑定。
2,在继承 extends TabActivity implements TabContentFactory 并实现public View createTabContent(String tag) 方法后,同时给tabhost绑定onclick事件。但是这样可能会带来重复2次读取的操作,但是也就仅限在第一次,反复读取后并不会有重复的问题。
3,对读取的图片进行压缩动作,并把原始图片进行调整大小处理。
接下来贴出所有的代码
主体
package com.jshop.android.shop; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import android.app.AlertDialog; import android.app.TabActivity; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.pm.ActivityInfo; import android.database.Cursor; import android.graphics.Bitmap; import android.graphics.Color; import android.os.Bundle; import android.support.v4.view.ViewPager; import android.support.v4.view.ViewPager.OnPageChangeListener; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.view.Window; import android.view.WindowManager; import android.widget.BaseAdapter; import android.widget.GridView; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.ListView; import android.widget.SimpleAdapter; import android.widget.TabHost; import android.widget.TabHost.OnTabChangeListener; import android.widget.TabHost.TabContentFactory; import android.widget.TextView; import com.jshop.android.action.JshopMGoodsListAction; import com.jshop.android.action.JshopMelectrocartAction; import com.jshop.android.action.JshopMgoodscategoryListAction; import com.jshop.android.holder.ElecartListViewHolder; import com.jshop.android.holder.GoodsListViewHolder; import com.jshop.android.index.R; import com.jshop.android.shop.JshopActivityGoodsList.JshopActivityGoodsListPageChangeListener; import com.jshop.android.sqlite.DBHelper; import com.jshop.android.util.Arith; import com.jshop.android.util.BaseTools; import com.jshop.android.widget.JshopListViewAdapter; import com.jshop.android.widget.JshopViewpagerAdapter; import com.jshop.android.widget.JshopViewpagerAdapter.JshopActivityGoodsListPageAdapter; public class JshopActivityNGoodsList extends TabActivity implements TabContentFactory{ private final DBHelper dbhelper=new DBHelper(this); private String[]tabTitle=null; private GridView gv; private ListView listViews;//used by goodslist private ListView listViewForCart;//used by cartlist private TextView totalmemberprice;//显示我的菜单总价 private Double total=0.0; private List<Map<String,Object>>goodscategoryList=new ArrayList<Map<String,Object>>();//商品分类 private ArrayList<HashMap<String, Object>> electrocartgoodslists = new ArrayList<HashMap<String, Object>>();//elecart private ArrayList<HashMap<String, Object>> goodslists = new ArrayList<HashMap<String, Object>>();//商品列表 private JshopMgoodscategoryListAction jmgclAction=new JshopMgoodscategoryListAction(); private JshopMGoodsListAction jmGoodslistAction=new JshopMGoodsListAction(); private JshopMelectrocartAction jmelecart=new JshopMelectrocartAction(); @SuppressWarnings("unchecked") @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); super.requestWindowFeature(Window.FEATURE_NO_TITLE);//设置无标题窗口 super.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);//全屏模式 super.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);//强制为横屏 this.setContentView(R.layout.jshop_m_newgoodslist); listViews=(ListView)this.findViewById(R.id.listViewfornewgoods);//商品列表的listview listViewForCart=(ListView)this.findViewById(R.id.listViewforelecart);//我的菜单listview setElecartListView();//调用读取我的菜单数据 //读取商品分类缓存 Cursor c=dbhelper.query(DBHelper.GOODS_CATEGORY_TM_NAME); goodscategoryList=jmgclAction.getGoodsCategoryListtoSQLite(c); c.close(); if(goodscategoryList.isEmpty()){ goodscategoryList=jmgclAction.getGoodsCategoryList(); //缓存goodscategorylist jmgclAction.setGoodsCategoryListtoSQLite(goodscategoryList, this.getApplicationContext()); } setTabTitle(goodscategoryList); if(tabTitle!=null){ final TabHost th = getTabHost(); for(int i = 0; i < tabTitle.length;i++){ LinearLayout view = (LinearLayout) getLayoutInflater().inflate(R.layout.jshop_m_textfortabtitle,null); ((TextView) view.findViewById(R.id.tv_title)).setText(tabTitle[i]); th.addTab(th.newTabSpec(tabTitle[i]).setIndicator(view).setContent(this)); } th.getTabWidget().getChildAt(th.getCurrentTab()).setBackgroundColor(Color.parseColor("#ff58a300")); th.setOnTabChangedListener(new OnTabChangeListener(){ @Override public void onTabChanged(String tabId) { // TODO Auto-generated method stub SimpleListView(tabId); // change tab background color to red for (int i = 0; i < th.getTabWidget().getChildCount(); i++) { th.getTabWidget().getChildAt(i).setBackgroundColor(Color.parseColor("#ff003464")); /** * set height and width under TabActivity setting width has no * effect due to fill_parent layout parameter */ //NOTE i cannot get this part work properly. //tabHost.getTabWidget().getChildAt(i).getLayoutParams().height = 30; //tabHost.getTabWidget().getChildAt(i).getLayoutParams().width = 30; View tempView= th.getTabWidget().getChildAt(i); /** * I kept all drawables in selector so that the we could get correct * drawablea applied to tabs as the selector pointed to has both the * tabs and the bottom tab-bar drawables referenced */ //tempView.setBackgroundDrawable(res.getDrawable(R.drawable.somedrawable)); } // o set different color for current selected tab to blue th.getTabWidget().getChildAt(th.getCurrentTab()).setBackgroundColor(Color.parseColor("#ff58a300")); } }); } } /** * 读取我的菜单数据 */ public void setElecartListView(){ electrocartgoodslists.clear(); //读取ele_cart缓存 Cursor ec=dbhelper.query(DBHelper.ELE_CART_TM_NAME); electrocartgoodslists=jmelecart.getElecarttoSQLite(ec); ec.close(); listViewForCart.setAdapter(new JshopMyElecartListViewAdapter(electrocartgoodslists,this.getApplicationContext())); setTotalMemberprice(); } /** * 设置计算我的菜单总价 */ public void setTotalMemberprice(){ total=0.0; if(!electrocartgoodslists.isEmpty()){ for(int i=0;i<electrocartgoodslists.size();i++){ total=Arith.add(total, Arith.mul(Double.parseDouble(electrocartgoodslists.get(i).get("memberprice").toString()), Double.parseDouble(electrocartgoodslists.get(i).get("needquantity").toString()))); } totalmemberprice=(TextView) this.findViewById(R.id.totalmemberprice); totalmemberprice.setText("¥"+total); }else{ totalmemberprice=(TextView) this.findViewById(R.id.totalmemberprice); totalmemberprice.setText("¥"+total); } } /** * 刷新我的菜单数据 */ // public void rfreshElecartListView(){ // electrocartgoodslists.clear(); // //读取ele_cart缓存 // Cursor ec=dbhelper.query(DBHelper.ELE_CART_TM_NAME); // electrocartgoodslists=jmelecart.getElecarttoSQLite(ec); // ec.close(); // // } /** * 动态获取tabhost需要的title * @param goodscategoryList * @return */ @SuppressWarnings("unused") private void setTabTitle(List<Map<String,Object>>goodscategoryList){ String [] t=new String[goodscategoryList.size()]; for(int i=0;i<goodscategoryList.size();i++){ t[i]=goodscategoryList.get(i).get("name").toString(); } this.tabTitle=t; } /** * 切换tabhost时调用的方法 * @param tag * @return */ public View SimpleListView(String tag){ collectSqliteGoodsList(tag); listViews.setAdapter(new JshopMyGoodsListViewAdapter(goodslists,this.getApplicationContext())); return listViews; } @Override public View createTabContent(String tag) { View view = new View(this); if(tabTitle!=null){ if(tabTitle[0].equals(tag)){ collectSqliteGoodsList(tag); }else if (tabTitle[1].equals(tag)){ collectSqliteGoodsList(tag); }else if (tabTitle[2].equals(tag)){ collectSqliteGoodsList(tag); }else{ collectSqliteGoodsList(tag); } listViews.setAdapter(new JshopMyGoodsListViewAdapter(goodslists,this.getApplicationContext())); } return view; } @SuppressWarnings("unused") private void collectSqliteGoodsList(String tag){ Cursor c=dbhelper.queryByParamGoodsCategoryTName(DBHelper.GOODS_TM_NAME,tag); try { goodslists=jmGoodslistAction.getGoodsListSQLite(c); } catch (IOException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } c.close(); } /** * 点击加入我的菜单 * @param goodslists * @param arg2 */ public void showConfirmAddtoCart(final ArrayList<HashMap<String, Object>> goodslists,final int arg2){ AlertDialog.Builder bulider=new AlertDialog.Builder(this); bulider.setMessage("确定加入我的菜单吗?").setCancelable(false).setPositiveButton("确定", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { String goodsid=goodslists.get(arg2).get("goodsid").toString(); String goodsname=goodslists.get(arg2).get("goodsname").toString(); String memberprice=goodslists.get(arg2).get("memberprice").toString(); String pictureurl=goodslists.get(arg2).get("pictureurl").toString(); String needquantity="1"; jmelecart.setGoodsToElecartSQLite(goodsid,goodsname,memberprice,pictureurl,needquantity, getApplicationContext()); setElecartListView(); } }).setNegativeButton("取消", null); AlertDialog alert=bulider.create(); alert.show(); } /** * 商品listview的适配器 * @author "chenda" * */ public class JshopMyGoodsListViewAdapter extends BaseAdapter { private ArrayList<HashMap<String, Object>> list; private LayoutInflater myInflater; public JshopMyGoodsListViewAdapter( ArrayList<HashMap<String, Object>> list, Context context) { this.list = list; this.myInflater = LayoutInflater.from(context); } @Override public int getCount() { // TODO Auto-generated method stub return list.size(); } @Override public Object getItem(int position) { // TODO Auto-generated method stub return list.get(position); } @Override public long getItemId(int position) { // TODO Auto-generated method stub return position; } @Override public View getView(final int position, View convertView, ViewGroup parent) { GoodsListViewHolder holder = null; if (convertView == null) { holder = new GoodsListViewHolder(); convertView = myInflater.inflate( R.layout.jshop_m_listforcategory, null); holder.setPictureurl((ImageView) convertView .findViewById(R.id.pictureurl)); holder.setGoodsname((TextView) convertView .findViewById(R.id.goodsname)); holder.setMemberprice((TextView) convertView .findViewById(R.id.memberprice)); holder.setWeight((TextView) convertView .findViewById(R.id.weight)); holder.setUnitname((TextView) convertView .findViewById(R.id.unitname)); holder.setAddtomyelecartmenu((ImageView) convertView .findViewById(R.id.addtomyelecartmenu)); holder.setDetail((TextView) convertView .findViewById(R.id.detail)); convertView.setTag(holder); } else { holder = (GoodsListViewHolder) convertView.getTag(); } holder.getPictureurl().setImageBitmap( (Bitmap) list.get(position).get("pictureurl")); holder.getGoodsname().setText( list.get(position).get("goodsname").toString()); holder.getMemberprice().setText( list.get(position).get("memberprice").toString()); holder.getWeight().setText( list.get(position).get("weight").toString()); holder.getUnitname().setText( list.get(position).get("unitname").toString()); holder.getDetail().setText( list.get(position).get("detail").toString()); holder.getAddtomyelecartmenu().setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { showConfirmAddtoCart(list, position); } }); holder.getPictureurl().setOnClickListener(new OnClickListener(){ @Override public void onClick(View v) { } }); return convertView; } @Override public void notifyDataSetChanged() { // TODO Auto-generated method stub super.notifyDataSetChanged(); } } /** /** * 我的elecart的适配器 * @author "chenda" * */ public class JshopMyElecartListViewAdapter extends BaseAdapter { private final ArrayList<HashMap<String, Object>> list; private LayoutInflater myInflater; public JshopMyElecartListViewAdapter( ArrayList<HashMap<String, Object>> list, Context context) { this.list = list; this.myInflater = LayoutInflater.from(context); } @Override public int getCount() { // TODO Auto-generated method stub return list.size(); } @Override public Object getItem(int position) { // TODO Auto-generated method stub return list.get(position); } @Override public long getItemId(int position) { // TODO Auto-generated method stub return position; } @Override public View getView(final int position, View convertView, final ViewGroup parent) { ElecartListViewHolder holder = null; if (convertView == null) { holder = new ElecartListViewHolder(); convertView = myInflater.inflate( R.layout.jshop_m_detaillistview, null); holder.setGoodsname((TextView) convertView .findViewById(R.id.goodsname)); holder.setMemberprice((TextView) convertView .findViewById(R.id.memberprice)); holder.setNeedquantity((TextView) convertView.findViewById(R.id.needquantity)); holder.setPlus((ImageView) convertView.findViewById(R.id.plus)); holder.setMinus((ImageView) convertView.findViewById(R.id.minus)); convertView.setTag(holder); } else { holder = (ElecartListViewHolder) convertView.getTag(); } holder.getGoodsname().setText( list.get(position).get("goodsname").toString()); holder.getMemberprice().setText( list.get(position).get("memberprice").toString()); holder.getNeedquantity().setText( list.get(position).get("needquantity").toString()); holder.getPlus().setOnClickListener( new OnClickListener() { @Override public void onClick(View v) { jmelecart.plusorMinusElecart(list, position, "plus", v.getContext()); setElecartListView(); setTotalMemberprice(); } }); holder.getMinus().setOnClickListener( new OnClickListener() { @Override public void onClick(View v) { jmelecart.plusorMinusElecart(list, position, "minus", v.getContext()); setElecartListView(); setTotalMemberprice(); } }); return convertView; } @Override public void notifyDataSetChanged() { // TODO Auto-generated method stub super.notifyDataSetChanged(); } } }
/** * 压缩图片 * to change sd card pc to bmp type * @param pictureurl * @return * @throws IOException */ public static Bitmap GetLocalOrNetBitmap(String url) throws IOException { String sdcard=Environment.getExternalStorageDirectory().getPath(); BitmapFactory.Options options=new BitmapFactory.Options(); options.inSampleSize=6; options.inTempStorage=new byte[5*1024]; Bitmap bitmap=BitmapFactory.decodeFile(sdcard+url,options); return bitmap; } /** * 不压缩图片 * to change sd card pc to bmp type * @param pictureurl * @return * @throws IOException */ public static Bitmap GetLocalOrNetBitmapNoZip(String url) throws IOException { String sdcard=Environment.getExternalStorageDirectory().getPath(); BitmapFactory.Options options=new BitmapFactory.Options(); options.inTempStorage=new byte[5*1024]; Bitmap bitmap=BitmapFactory.decodeFile(sdcard+url,options); return bitmap; }
更多代码请关注 https://github.com/sdywcd/ostocy-jshop 中的jshop-android (项目会需要服务器端做支持,可能比较复杂。如果有问题欢迎通过站内信或者邮箱联系。)
发表评论
-
android按需加载你的界面
2014-05-08 09:18 1274按需加载你的界面 有时候你的布局中可能存在一些不常 ... -
如何判断android activity是否运行
2014-05-05 17:19 7988如何判断android activity是否运行 ... -
看了一些git教程后自己的总结
2014-04-24 12:45 1350平时在维护开源程序 ... -
android在布局中动态增加view时的层级控制
2014-03-24 14:40 34013问题:我们有时候希望动态的在android的布局中增加vi ... -
android 在配置文件中指定上级activity
2013-12-07 23:47 1455今天在看sdk doc时发现可以在配置文件中定义一个acti ... -
android button 点击事件
2013-12-06 11:49 1161<Button android:layou ... -
Activiti5用户手册---Message Event Definitions
2013-09-04 14:05 6568Message Event Definitions(消息事件 ... -
mysql 计算工作日
2013-08-16 16:25 2261DELIMITER $$ drop procedure ... -
mysql 跨年按周分组
2013-08-16 15:36 2538use employees; create table s ... -
Activiti5用户手册---Events---Timer Event Definitions
2013-07-30 11:45 10455好久以前翻译的了, ... -
我的android记录
2013-06-11 23:54 01,listview获取选择的items选中状态(例如lis ... -
android 中checkbox radiobutton文字间间距处理
2013-06-09 13:05 4888情况:ui设计要求必须让checkbox或者radiobut ... -
如何在eclipse adt中查看手机中应用的ui布局
2013-06-04 20:56 5876情况:忽然想查下怎么看那些漂亮的android ui布局 ... -
在eclipse 4.2中配置tomcat插件并修改jvm启动参数
2013-06-04 12:31 4752情况:今天在运行项目的时候发现需要一个比较大的内存才能够完成 ... -
css和html中的dom节点都是怎么被处理的
2013-05-26 19:11 1189今天看到一篇文章浏览器渲染原理 很不错 为什么我会去注意 ... -
搜寻了关于android推送资料后的一些思考
2013-04-11 22:23 1677其实我们要用推送服务的情况还挺多: 1,站内性 其实是可以 ... -
java中集合的父类collection的那些事
2013-04-10 18:02 01,collection是所有集合的父类 2,Li ... -
有那些设计模式,观察者模式是什么
2013-04-09 15:41 0设计模式还挺多的。可以分成如下几类 创建模式: ... -
写一个线程安全的单例模式
2013-04-08 23:30 1715谢谢 http://blog.sina.com.cn/s/b ... -
ThreadLocale是什么
2013-04-07 21:53 1107维持线程封闭性的一种更规范的方法是用ThreadLocal, ...
相关推荐
在Android开发中,`TabHost`、`Spinner`和`ListView`是三个非常重要的组件,它们各自承担着不同的功能,并且可以协同工作以提供丰富的用户界面。`TabHost`用于创建多标签界面,`Spinner`则是一种下拉选择菜单,而`...
我们可以通过Adapter将数据绑定到ListView,常见的Adapter有ArrayAdapter、SimpleAdapter和CursorAdapter。Adapter负责将数据转化为ListView项的视图。为了使ListView更具交互性,我们可以添加OnItemClickListener...
在Android开发中,ListView和GridView是两种常用的列表控件,它们允许开发者以列表或网格的形式展示大量数据。适配器(Adapter)则是连接数据源与这些视图的关键组件。此外,基本的Tab和Fragment的使用也是构建用户...
ListView是Android系统提供的一种列表视图控件,常用于显示大量可滚动的数据。它能高效地处理大量的条目,只加载屏幕可见的部分,降低内存消耗。开发者可以通过Adapter将数据源(如ArrayList)与ListView关联,...
“和一个listview的适配器样本”说明在应用中还使用了ListView,这是一种常见的列表控件,通过适配器(Adapter)将数据绑定到ListView上,以展示列表形式的内容。 关于TabHost的使用,有以下几点关键知识点: 1. *...
Android应用开发中,控件是构建用户界面的基本元素,决定了应用的外观和功能。本文档旨在详细介绍Android中一些常见控件的使用方法,帮助开发者更好地理解和运用它们。 1. **TextView文本框**: - TextView是用于...
开发者可以通过Adapter将数据绑定到ListView中,Adapter可以是ArrayAdapter、SimpleAdapter或者自定义的Adapter。此外,ListView还支持头视图和脚视图,以及点击事件、长按事件等交互功能。 3. Toast:Toast用于...
4. **Adapter与ListView/RecyclerView**:新闻内容通常以列表形式呈现,因此可能会使用Adapter将数据绑定到ListView或RecyclerView,以便动态加载和滚动。 5. **碎片(Fragment)**:在大型应用中,为了更好地管理...
11. ArrayAdapter和RecyclerView:AdapterView家族的成员,如ListView和GridView,用于将数据绑定到视图上,RecyclerView是更现代且高效的替代品,支持更复杂的布局和动画效果。 12. DatePicker和TimePicker:用于...
`ListView`是Android中的一个重要控件,它用于显示一系列可滚动的项目。`ListView`可以高效地处理大量数据,因为它只渲染屏幕可见的部分,其余部分会在需要时动态加载。通过设置适配器,`ListView`可以展示各种复杂...
### Android中常见控件参考手册知识点详述...以上概述了Android中常见控件的基本知识,涵盖了从文本显示到复杂布局和交互的各种场景,对于开发者来说,熟练掌握这些控件的特性和使用方法,是构建高质量应用程序的基础。
27. ArrayAdapter(适配器):连接数据源和UI控件,如ListView或Spinner,用于数据绑定。 28. CursorAdapter(游标适配器):专门用于数据库数据的适配,配合SQLite使用。 29. Fragment(片段):Android 3.0引入,...
本项目通过使用Tab分栏和ListView控件,为用户提供了一种新颖的方式来浏览和管理联系人信息。下面我们将深入探讨这个项目中的关键技术和知识点。 首先,Tab分栏是Android UI设计中常用的一种组织信息的方式,它允许...
4. **自定义ListView**:ListView是Android中常用的列表控件,它可以展示大量数据并支持滚动。通过自定义ListView,开发者可以实现特定的视图效果,比如在这个项目中,滑动显示删除按钮,增加了用户体验的交互性和...
例如,TextView的`setText()`方法用于设置文本,Button的`setOnClickListener()`用于添加点击事件,ListView的`Adapter`用于绑定数据,RecyclerView则通过`LayoutManager`实现不同的布局方式。 通过"一个Demo搞定30...
我们可以使用XML布局文件来设计界面,然后在代码中通过FindViewById方法获取这些组件的实例,进行事件绑定和属性设置。 在C#中处理Android UI还有一个关键点是线程模型。由于Android的UI操作必须在主线程进行,因此...
5. **P133ListViewPro**:`ListView`是Android中常用的数据展示控件,`ListViewPro`可能是在原生`ListView`基础上进行了优化或功能扩展,例如添加了动态加载、分组、多选等特性。 6. **P144AlertDialogDemo**:`...
SampleAdapter是一个基础示例,帮助开发者理解如何绑定数据到ListView。 6. **DatePicker, TimePicker(日期和时间选择器)**: 这两个组件用于让用户选择日期和时间。DatePicker显示日历视图,而TimePicker则提供...
`ListView`是一个可滚动的视图,用于显示多行数据,而`RecyclerView`作为其替代品,提供了更高效的性能和更灵活的布局管理器。开发者通常会创建自定义的`Adapter`来绑定数据源,并为每个列表项提供对应的`CheckBox`...