Android App开发学习第十四天:BaseAdapter的一些优化

重用ConvertView

一般我们在重写BaseAdapter里的getView()中,有多少条数据就要inflate多少次布局文件,比较浪费资源。未优化前的代码

 @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        convertView = LayoutInflater.from(mContext).inflate(R.layout.item_demo,parent,false);
       
        TextView textView = convertView.findViewById(R.id.tv_item);
        textView.setText(list.get(position));
        return convertView;
    }

实际上,convertView是系统提供给我们的可复用的View的缓存对象,只需加一个判断即可实现复用。

   @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        if (convertView ==null){
            convertView = LayoutInflater.from(mContext).inflate(R.layout.item_demo,parent,false);
        }
        TextView textView = convertView.findViewById(R.id.tv_item);
        textView.setText(list.get(position));
        return convertView;
    }

ViewHolder重用组件
getView()会被调用多次,则findViewById也一样会被调用多次。未修改前

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        if (convertView ==null){
            convertView = LayoutInflater.from(mContext).inflate(R.layout.item_demo,parent,false);
        }
       TextView textView = convertView.findViewById(R.id.tv_item);
        textView.setText(list.get(position));
        return convertView;
    }

可以自定义ViewHolder来绑定控件

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        if (convertView ==null){
            convertView = LayoutInflater.from(mContext).inflate(R.layout.item_demo,parent,false);
            viewHolder = new ViewHolder();
            viewHolder.textView = convertView.findViewById(R.id.tv_item);
            convertView.setTag(viewHolder); //将viewHolder存储到convertView中
        }else {
            viewHolder = (ViewHolder) convertView.getTag();
        }
        viewHolder.textView.setText(list.get(position));
        return convertView;
    }

    static class ViewHolder{
        TextView textView;
    }
    }
<think>我们使用Android开发,需要实现一个任务中心功能。根据要求,我们需要: 1. 在导航栏中添加“任务中心”菜单项,并设置为默认打开的页面。 2. 任务中心页面使用TabHost来展示三个标签:未领取、已领取、已完成,默认显示未领取。 3. 当页面滚动时,标签需要固定在顶部。 4. 列表使用SwipeMenuListView,每条数据右侧有一个领取按钮(对于未领取标签页),点击进入领取页面。 注意:由于要求使用TabHost,虽然现在更推荐TabLayout+ViewPager,但这里按照需求使用TabHost。 实现步骤: 步骤1:在导航菜单中添加“任务中心”项,并设置默认选中。 步骤2:创建任务中心的Fragment,使用TabHost来管理三个标签页。 步骤3:实现每个标签页的内容,其中未领取标签页使用SwipeMenuListView展示订单列表,并添加领取按钮。 步骤4:确保标签在滚动时固定在顶部。我们可以通过布局设计,将TabHost的标签栏放在顶部,下面放一个可滚动的列表,当滚动时,整个标签栏会固定在顶部(因为TabHost的标签栏是独立于内容的,我们只需要将内容区域设置为可滚动即可)。 但是,注意TabHost本身并不支持内容区域滚动时标签栏固定(除非将标签栏放在外部)。因此,我们可以将任务中心Fragment的布局设计为垂直的LinearLayout,顶部是TabWidget(标签栏),下面是一个FrameLayout(作为标签内容容器),然后每个标签页的内容是一个可滚动的ListView(SwipeMenuListView)。这样,当列表滚动时,标签栏会保持在顶部不动(因为它们是两个独立的部分)。 然而,按照要求,我们需要整个页面滚动时标签固定,但这里每个标签页的内容是独立的,所以每个标签页内部滚动并不会影响其他标签页的标签栏。因此,我们只需要在每个标签页的内容中放置可滚动的列表即可,标签栏会一直固定在顶部。 具体实现: 1. 添加依赖:在build.gradle中添加SwipeMenuListView的依赖(如果尚未添加): implementation 'com.baoyz.swipemenulistview:library:1.3.0' 2. 修改导航菜单:在res/menu/activity_main_drawer.xml中添加“任务中心”项。 3. 创建任务中心Fragment:TaskCenterFragment.java 和对应的布局文件 fragment_task_center.xml。 4. 创建三个标签页的Fragment(或者使用同一个Fragment通过参数区分状态),这里为了简单,我们创建三个Fragment,分别对应未领取、已领取、已完成。 5. 在TaskCenterFragment中初始化TabHost,并添加三个标签。 6. 在未领取标签页的Fragment中,使用SwipeMenuListView,并为其添加一个“领取”的侧滑菜单项。 7. 处理领取按钮的点击事件,跳转到领取页面。 由于代码量较大,下面给出关键代码: 首先,修改导航菜单(res/menu/navigation.xml): ```xml <item android:id="@+id/nav_task_center" android:icon="@drawable/ic_task_center" android:title="任务中心" /> ``` 在MainActivity中,设置默认选中任务中心: ```java // 在onCreate中,设置默认选中的菜单项 navigationView.setCheckedItem(R.id.nav_task_center); // 并加载任务中心Fragment loadFragment(new TaskCenterFragment()); ``` 创建TaskCenterFragment: ```java public class TaskCenterFragment extends Fragment { private TabHost tabHost; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_task_center, container, false); tabHost = (TabHost) view.findViewById(android.R.id.tabhost); tabHost.setup(); // 添加标签页 TabHost.TabSpec unclaimedSpec = tabHost.newTabSpec("unclaimed"); unclaimedSpec.setIndicator("未领取"); unclaimedSpec.setContent(R.id.tab_unclaimed); tabHost.addTab(unclaimedSpec); TabHost.TabSpec claimedSpec = tabHost.newTabSpec("claimed"); claimedSpec.setIndicator("已领取"); claimedSpec.setContent(R.id.tab_claimed); tabHost.addTab(claimedSpec); TabHost.TabSpec completedSpec = tabHost.newTabSpec("completed"); completedSpec.setIndicator("已完成"); completedSpec.setContent(R.id.tab_completed); tabHost.addTab(completedSpec); // 设置默认标签 tabHost.setCurrentTab(0); return view; } } ``` 布局文件:fragment_task_center.xml ```xml <?xml version="1.0" encoding="utf-8"?> <TabHost xmlns:android="http://schemas.android.com/apk/res/android" android:id="@android:id/tabhost" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <!-- 标签栏,会固定在顶部 --> <TabWidget android:id="@android:id/tabs" android:layout_width="match_parent" android:layout_height="wrap_content" /> <!-- 标签内容区域 --> <FrameLayout android:id="@android:id/tabcontent" android:layout_width="match_parent" android:layout_height="match_parent"> <!-- 未领取标签页的内容 --> <FrameLayout android:id="@+id/tab_unclaimed" android:layout_width="match_parent" android:layout_height="match_parent" /> <!-- 已领取标签页的内容 --> <FrameLayout android:id="@+id/tab_claimed" android:layout_width="match_parent" android:layout_height="match_parent" /> <!-- 已完成标签页的内容 --> <FrameLayout android:id="@+id/tab_completed" android:layout_width="match_parent" android:layout_height="match_parent" /> </FrameLayout> </LinearLayout> </TabHost> ``` 注意:在TaskCenterFragment中,我们为每个标签页指定了内容区域(FrameLayout),然后我们可以在Fragment中动态添加对应的Fragment到这些FrameLayout中。但是,这里我们也可以直接在TabHost中设置内容,不过为了模块化,我们使用Fragment来管理每个标签页的内容。 我们可以修改TaskCenterFragment,在添加标签页的同时,将对应的Fragment添加到FrameLayout中。但是,为了简单,我们可以在onCreateView中初始化TabHost后,为每个标签页添加对应的Fragment。 修改TaskCenterFragment的onCreateView方法,在添加标签后,初始化每个标签页的Fragment: ```java // 在onCreateView中,添加标签后: FragmentManager fm = getChildFragmentManager(); FragmentTransaction ft = fm.beginTransaction(); ft.replace(R.id.tab_unclaimed, new UnclaimedFragment()); ft.replace(R.id.tab_claimed, new ClaimedFragment()); ft.replace(R.id.tab_completed, new CompletedFragment()); ft.commit(); ``` 然后,我们实现未领取标签页的Fragment:UnclaimedFragment.java ```java public class UnclaimedFragment extends Fragment { private SwipeMenuListView listView; private List<Order> orderList = new ArrayList<>(); @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_unclaimed, container, false); listView = (SwipeMenuListView) view.findViewById(R.id.listView); // 模拟数据 loadData(); // 创建适配器 OrderAdapter adapter = new OrderAdapter(getContext(), orderList); listView.setAdapter(adapter); // 创建侧滑菜单 SwipeMenuCreator creator = new SwipeMenuCreator() { @Override public void create(SwipeMenu menu) { // 创建“领取”按钮 SwipeMenuItem claimItem = new SwipeMenuItem(getContext()); claimItem.setBackground(new ColorDrawable(Color.GREEN)); claimItem.setWidth(180); claimItem.setTitle("领取"); claimItem.setTitleSize(16); claimItem.setTitleColor(Color.WHITE); menu.addMenuItem(claimItem); } }; listView.setMenuCreator(creator); // 菜单点击事件 listView.setOnMenuItemClickListener(new SwipeMenuListView.OnMenuItemClickListener() { @Override public boolean onMenuItemClick(int position, SwipeMenu menu, int index) { if (index == 0) { // 第一个菜单项(领取) Order order = orderList.get(position); // 跳转到领取页面 Intent intent = new Intent(getActivity(), ClaimActivity.class); intent.putExtra("order_id", order.getId()); startActivity(intent); return true; } return false; } }); return view; } private void loadData() { // 这里模拟从仓储系统获取入库订单数据 for (int i = 0; i < 20; i++) { Order order = new Order(); order.setId("ORD" + i); order.setCreateTime("2023-06-01 10:00"); order.setGoodsName("商品" + i); orderList.add(order); } } private static class OrderAdapter extends BaseAdapter { // 实现BaseAdapter,这里省略具体实现 } } ``` 布局文件 fragment_unclaimed.xml: ```xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <com.baoyz.swipemenulistview.SwipeMenuListView android:id="@+id/listView" android:layout_width="match_parent" android:layout_height="match_parent" /> </LinearLayout> ``` 注意:已领取和已完成标签页的Fragment可以类似实现,只是数据不同,且可能不需要领取按钮。 这样,当用户向下滚动列表时,标签栏会固定在顶部(因为标签栏是独立于列表的,位于列表上方)。 但是,请注意:TabHost的标签栏(TabWidget)会一直显示在顶部,而每个标签页的内容是独立的,因此滚动时不会影响标签栏的位置。 另外,关于SwipeMenuListView的使用,我们添加了一个绿色的领取按钮,点击后跳转到领取页面。 注意:Order类是一个简单的POJO,包含订单信息。 最后,确保在AndroidManifest.xml中注册ClaimActivity。 以上代码基于JDK1.8,使用了Android的兼容库(AppCompatActivity和Fragment)。 注意:由于TabHost是传统的控件,可能在某些新特性上支持不够,但按照需求使用。 另外,如果标签页内容较多,可以考虑使用ViewPager和TabLayout,但这里按照要求使用TabHost。 相关问题: 1. 如何动态更新任务中心各标签页的数据? 2. 如何实现当在领取页面操作后,返回任务中心时刷新列表? 3. SwipeMenuListView如何自定义菜单项的样式(比如图标)? 4. 如果订单数据量很大,如何做分页加载?</think>### Android任务中心功能实现方案 我将为您提供完整的任务中心功能实现方案,包含所有要求的特性。以下是详细实现步骤: #### 1. 添加导航菜单项并设置默认页面 **修改导航菜单文件 (res/menu/navigation.xml)**: ```xml <item android:id="@+id/nav_task_center" android:icon="@drawable/ic_task" android:title="任务中心" android:checked="true"/> <!-- 设置默认选中 --> ``` **修改 MainActivity.java**: ```java public class MainActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); NavigationView navigationView = findViewById(R.id.nav_view); navigationView.setNavigationItemSelectedListener(this); // 设置默认选中任务中心 navigationView.setCheckedItem(R.id.nav_task_center); // 加载默认Fragment if (savedInstanceState == null) { loadFragment(new TaskCenterFragment()); } } private void loadFragment(Fragment fragment) { getSupportFragmentManager().beginTransaction() .replace(R.id.fragment_container, fragment) .commit(); } @Override public boolean onNavigationItemSelected(@NonNull MenuItem item) { int id = item.getItemId(); if (id == R.id.nav_task_center) { loadFragment(new TaskCenterFragment()); } // 其他菜单项处理... DrawerLayout drawer = findViewById(R.id.drawer_layout); drawer.closeDrawer(GravityCompat.START); return true; } } ``` #### 2. 任务中心主Fragment (使用TabHost) **TaskCenterFragment.java**: ```java public class TaskCenterFragment extends Fragment { private TabHost tabHost; private String[] tabTitles = {"未领取", "已领取", "已完成"}; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_task_center, container, false); // 初始化TabHost tabHost = view.findViewById(android.R.id.tabhost); tabHost.setup(); // 添加标签页 for (int i = 0; i < tabTitles.length; i++) { TabHost.TabSpec spec = tabHost.newTabSpec("tab" + i); spec.setIndicator(tabTitles[i]); spec.setContent(new TabHost.TabContentFactory() { @Override public View createTabContent(String tag) { // 返回空视图,实际内容在Fragment中 return new View(getContext()); } }); tabHost.addTab(spec); } // 设置默认标签 tabHost.setCurrentTab(0); // 标签切换监听 tabHost.setOnTabChangedListener(new TabHost.OnTabChangeListener() { @Override public void onTabChanged(String tabId) { int position = tabHost.getCurrentTab(); loadTabFragment(position); } }); // 加载初始标签页 loadTabFragment(0); return view; } private void loadTabFragment(int position) { Fragment fragment = null; switch (position) { case 0: fragment = new UnclaimedFragment(); break; case 1: fragment = new ClaimedFragment(); break; case 2: fragment = new CompletedFragment(); break; } if (fragment != null) { getChildFragmentManager().beginTransaction() .replace(R.id.tab_content_container, fragment) .commit(); } } } ``` **布局文件 (fragment_task_center.xml)**: ```xml <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <!-- 固定在顶部的TabHost --> <TabHost android:id="@android:id/tabhost" android:layout_width="match_parent" android:layout_height="wrap_content"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <!-- 标签栏 --> <TabWidget android:id="@android:id/tabs" android:layout_width="match_parent" android:layout_height="48dp" android:background="@color/colorPrimary" android:divider="@null"/> </LinearLayout> </TabHost> <!-- 标签内容区域 --> <FrameLayout android:id="@+id/tab_content_container" android:layout_width="match_parent" android:layout_height="match_parent"/> </LinearLayout> ``` #### 3. 未领取任务Fragment (使用SwipeMenuListView) **UnclaimedFragment.java**: ```java public class UnclaimedFragment extends Fragment { private SwipeMenuListView listView; private List<WarehouseOrder> orderList = new ArrayList<>(); private OrderAdapter adapter; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_unclaimed, container, false); listView = view.findViewById(R.id.swipe_list_view); // 加载订单数据 loadOrderData(); // 设置适配器 adapter = new OrderAdapter(getActivity(), orderList); listView.setAdapter(adapter); // 创建侧滑菜单 createSwipeMenu(); return view; } private void createSwipeMenu() { SwipeMenuCreator creator = new SwipeMenuCreator() { @Override public void create(SwipeMenu menu) { // 创建"领取"按钮 SwipeMenuItem claimItem = new SwipeMenuItem(getActivity()); claimItem.setBackground(R.color.colorPrimary); claimItem.setWidth(dpToPx(80)); claimItem.setTitle("领取"); claimItem.setTitleSize(16); claimItem.setTitleColor(Color.WHITE); menu.addMenuItem(claimItem); } }; listView.setMenuCreator(creator); // 菜单点击事件 listView.setOnMenuItemClickListener(new SwipeMenuListView.OnMenuItemClickListener() { @Override public boolean onMenuItemClick(int position, SwipeMenu menu, int index) { if (index == 0) { // 领取按钮 WarehouseOrder order = orderList.get(position); openClaimActivity(order); return true; } return false; } }); } private void openClaimActivity(WarehouseOrder order) { Intent intent = new Intent(getActivity(), ClaimActivity.class); intent.putExtra("order_id", order.getId()); startActivity(intent); } private void loadOrderData() { // 模拟从仓储系统API获取数据 orderList.clear(); orderList.add(new WarehouseOrder("ORD001", "2023-06-15", "电子产品", "待入库")); orderList.add(new WarehouseOrder("ORD002", "2023-06-16", "日用品", "待验收")); orderList.add(new WarehouseOrder("ORD003", "2023-06-17", "办公用品", "待分配")); // 添加更多订单... if (adapter != null) { adapter.notifyDataSetChanged(); } } private int dpToPx(int dp) { return (int) (dp * getResources().getDisplayMetrics().density); } // 订单数据模型 public static class WarehouseOrder { private String id; private String date; private String goodsType; private String status; // 构造方法、getter/setter省略... } // 订单适配器 class OrderAdapter extends BaseAdapter { private Context context; private List<WarehouseOrder> orders; public OrderAdapter(Context context, List<WarehouseOrder> orders) { this.context = context; this.orders = orders; } @Override public int getCount() { return orders.size(); } @Override public WarehouseOrder getItem(int position) { return orders.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder; if (convertView == null) { convertView = LayoutInflater.from(context) .inflate(R.layout.item_order, parent, false); holder = new ViewHolder(); holder.orderId = convertView.findViewById(R.id.tv_order_id); holder.date = convertView.findViewById(R.id.tv_date); holder.goodsType = convertView.findViewById(R.id.tv_goods_type); holder.status = convertView.findViewById(R.id.tv_status); convertView.setTag(holder); } else { holder = (ViewHolder) convertView.getTag(); } WarehouseOrder order = getItem(position); holder.orderId.setText("订单号: " + order.getId()); holder.date.setText("日期: " + order.getDate()); holder.goodsType.setText("商品类型: " + order.getGoodsType()); holder.status.setText("状态: " + order.getStatus()); return convertView; } class ViewHolder { TextView orderId; TextView date; TextView goodsType; TextView status; } } } ``` **列表项布局 (item_order.xml)**: ```xml <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:padding="16dp"> <TextView android:id="@+id/tv_order_id" android:layout_width="match_parent" android:layout_height="wrap_content" android:textSize="16sp" android:textStyle="bold"/> <TextView android:id="@+id/tv_date" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="4dp"/> <TextView android:id="@+id/tv_goods_type" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="4dp"/> <TextView android:id="@+id/tv_status" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="4dp" android:textColor="@color/colorAccent"/> </LinearLayout> ``` #### 4. 依赖配置 (app/build.gradle) ```gradle dependencies { implementation 'com.android.support:appcompat-v7:28.0.0' implementation 'com.android.support:design:28.0.0' // SwipeMenuListView implementation 'com.baoyz.swipemenulistview:library:1.3.0' // 网络请求库(示例) implementation 'com.squareup.retrofit2:retrofit:2.9.0' implementation 'com.squareup.retrofit2:converter-gson:2.9.0' // 图片加载库(可选) implementation 'com.github.bumptech.glide:glide:4.12.0' annotationProcessor 'com.github.bumptech.glide:compiler:4.12.0' } ``` ### 关键实现说明 1. **导航与默认页面**: - 在导航菜单添加"任务中心"项并设置默认选中 - MainActivity初始化时加载TaskCenterFragment - 使用FragmentManager管理页面切换 2. **TabHost固定顶部**: - 使用垂直LinearLayout确保TabWidget在顶部 - 内容区域使用FrameLayout作为Fragment容器 - 切换标签时动态加载对应Fragment 3. **SwipeMenuListView使用**: - 添加依赖并配置SwipeMenuCreator - 创建"领取"按钮并设置点击事件 - 点击按钮启动ClaimActivity并传递订单ID 4. **数据加载与展示**: - 创建WarehouseOrder数据模型 - 使用BaseAdapter实现订单列表适配器 - 列表项布局展示订单详细信息 5. **性能优化**: - 使用ViewHolder模式优化列表性能 - 动态加载标签页内容(懒加载) - 使用异步任务加载网络数据 ### 注意事项 1. **实际数据获取**: ```java // 实际应从仓储系统API获取数据 private void loadRealOrderData() { ApiService apiService = RetrofitClient.getRetrofitInstance().create(ApiService.class); Call<List<WarehouseOrder>> call = apiService.getUnclaimedOrders(); call.enqueue(new Callback<List<WarehouseOrder>>() { @Override public void onResponse(Call<List<WarehouseOrder>> call, Response<List<WarehouseOrder>> response) { if (response.isSuccessful()) { orderList.clear(); orderList.addAll(response.body()); adapter.notifyDataSetChanged(); } } @Override public void onFailure(Call<List<WarehouseOrder>> call, Throwable t) { // 处理错误 } }); } ``` 2. **状态同步**: - 在ClaimActivity完成任务后发送广播 - 在Fragment中注册广播接收器更新列表 3. **标签样式优化**: ```java // 自定义标签样式 private void customizeTabs() { for (int i = 0; i < tabHost.getTabWidget().getChildCount(); i++) { View tabView = tabHost.getTabWidget().getChildAt(i); TextView tabText = tabView.findViewById(android.R.id.title); tabText.setTextSize(TypedValue.COMPLEX_UNIT_SP, 14); tabText.setTextColor(Color.WHITE); // 设置选中状态样式 if (i == tabHost.getCurrentTab()) { tabView.setBackgroundColor(ContextCompat.getColor(getContext(), R.color.colorPrimaryDark)); } else { tabView.setBackgroundColor(ContextCompat.getColor(getContext(), R.color.colorPrimary)); } } } ``` 4. **空状态处理**: ```java private void checkEmptyState() { if (orderList.isEmpty()) { View emptyView = getLayoutInflater().inflate(R.layout.empty_view, null); ((ViewGroup) listView.getParent()).addView(emptyView); listView.setEmptyView(emptyView); } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值