You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android:LayoutInflater加载多视图后更新指定TextView及滚动保余额问题

嘿,我来帮你搞定这个需求!你要的效果核心就是数据和视图分离——确保滚动时余额数据不会因为视图回收/重建丢失,同时能精准更新对应项的UI。下面是一步步的实现方案,完全贴合PhonePe那种流畅的体验:

核心思路

为什么滚动后更新的余额会消失?本质是因为你如果只临时修改TextView的文本,没有把数据存在独立的模型里,当视图被回收(比如列表复用)或重新绘制时,TextView会回到初始状态。所以关键是:用数据模型保存每个项的状态,视图只负责展示模型的数据。

具体实现步骤

1. 创建数据模型类

先定义一个WalletItem类,用来存储每个钱包项的所有信息(包括余额),这样不管视图怎么变化,数据都能稳定保存:

public class WalletItem {
    private String walletId; // 唯一标识,区分不同钱包项
    private String walletName;
    private String balance; // 初始可设为"点击查询余额"或占位符

    // 构造方法、getter、setter
    public WalletItem(String walletId, String walletName, String balance) {
        this.walletId = walletId;
        this.walletName = walletName;
        this.balance = balance;
    }

    public String getWalletId() { return walletId; }
    public String getWalletName() { return walletName; }
    public String getBalance() { return balance; }
    public void setBalance(String balance) { this.balance = balance; }
}

2. 设计列表项布局(item_wallet.xml)

这是你要通过LayoutInflater加载的独立布局,包含余额查询按钮和显示余额的TextView:

<?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="wrap_content"
    android:padding="16dp"
    android:orientation="horizontal"
    android:gravity="center_vertical">

    <TextView
        android:id="@+id/tv_wallet_name"
        android:layout_width="0dp"
        android:layout_weight="1"
        android:layout_height="wrap_content"
        android:textSize="16sp"
        android:text="钱包名称"/>

    <Button
        android:id="@+id/btn_check_balance"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="查余额"/>

    <TextView
        android:id="@+id/tv_balance"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:textSize="16sp"
        android:text="——"/>
</LinearLayout>

3. 推荐方案:用RecyclerView实现(贴合PhonePe的高效滚动)

手动for循环添加View到LinearLayout+ScrollView的方式虽然简单,但滚动性能差,大量项会占用过多内存。PhonePe这类应用肯定用RecyclerView,它自带视图复用,完美解决滚动数据不丢失的问题,优先推荐这个方案:

3.1 创建RecyclerView的Adapter和ViewHolder

ViewHolder负责持有项内控件,Adapter负责绑定数据、处理点击事件:

public class WalletAdapter extends RecyclerView.Adapter<WalletAdapter.WalletViewHolder> {

    private List<WalletItem> walletList;
    private Context context;

    public WalletAdapter(Context context, List<WalletItem> walletList) {
        this.context = context;
        this.walletList = walletList;
    }

    @NonNull
    @Override
    public WalletViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        // 加载item布局
        View itemView = LayoutInflater.from(context).inflate(R.layout.item_wallet, parent, false);
        return new WalletViewHolder(itemView);
    }

    @Override
    public void onBindViewHolder(@NonNull WalletViewHolder holder, int position) {
        WalletItem currentItem = walletList.get(position);
        holder.tvWalletName.setText(currentItem.getWalletName());
        holder.tvBalance.setText(currentItem.getBalance());

        // 设置余额查询按钮点击事件
        holder.btnCheckBalance.setOnClickListener(v -> {
            // 防止重复请求,先禁用按钮
            holder.btnCheckBalance.setEnabled(false);
            holder.btnCheckBalance.setText("查询中...");

            // 发起余额查询请求(这里用模拟请求代替真实网络请求)
            simulateBalanceQuery(currentItem.getWalletId(), position, holder);
        });
    }

    @Override
    public int getItemCount() {
        return walletList.size();
    }

    // 模拟网络请求,实际项目替换为Retrofit/OkHttp的真实请求
    private void simulateBalanceQuery(String walletId, int position, WalletViewHolder holder) {
        new Handler(Looper.getMainLooper()).postDelayed(() -> {
            // 模拟服务器返回的余额
            String balance = "₹" + new Random().nextInt(10000);
            // 更新数据模型
            walletList.get(position).setBalance(balance);
            // 更新对应项UI(也可以调用notifyItemChanged(position))
            holder.tvBalance.setText(balance);
            // 恢复按钮状态
            holder.btnCheckBalance.setEnabled(true);
            holder.btnCheckBalance.setText("查余额");
        }, 1500);
    }

    public static class WalletViewHolder extends RecyclerView.ViewHolder {
        TextView tvWalletName, tvBalance;
        Button btnCheckBalance;

        public WalletViewHolder(@NonNull View itemView) {
            super(itemView);
            tvWalletName = itemView.findViewById(R.id.tv_wallet_name);
            tvBalance = itemView.findViewById(R.id.tv_balance);
            btnCheckBalance = itemView.findViewById(R.id.btn_check_balance);
        }
    }
}

3.2 在Activity/Fragment中初始化RecyclerView

public class WalletActivity extends AppCompatActivity {

    private RecyclerView recyclerView;
    private WalletAdapter adapter;
    private List<WalletItem> walletList;

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

        // 初始化数据集,生成8个钱包项
        walletList = new ArrayList<>();
        for (int i = 1; i <= 8; i++) {
            walletList.add(new WalletItem("wallet_" + i, "钱包 " + i, "点击查询余额"));
        }

        // 设置RecyclerView
        recyclerView = findViewById(R.id.recycler_view);
        recyclerView.setLayoutManager(new LinearLayoutManager(this));
        adapter = new WalletAdapter(this, walletList);
        recyclerView.setAdapter(adapter);
    }
}

对应的activity_wallet.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">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recycler_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
</LinearLayout>

4. 备选方案:手动for循环添加View到LinearLayout

如果你坚持要用for循环手动生成视图,核心还是把数据和View绑定:

public class WalletActivity extends AppCompatActivity {

    private LinearLayout container;
    private List<WalletItem> walletList;

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

        container = findViewById(R.id.container);
        walletList = new ArrayList<>();

        // 生成8个钱包项
        for (int i = 1; i <= 8; i++) {
            WalletItem item = new WalletItem("wallet_" + i, "钱包 " + i, "点击查询余额");
            walletList.add(item);
            // 加载item布局并添加到容器
            addWalletItemView(item);
        }
    }

    private void addWalletItemView(WalletItem item) {
        View itemView = LayoutInflater.from(this).inflate(R.layout.item_wallet, container, false);
        TextView tvWalletName = itemView.findViewById(R.id.tv_wallet_name);
        TextView tvBalance = itemView.findViewById(R.id.tv_balance);
        Button btnCheckBalance = itemView.findViewById(R.id.btn_check_balance);

        tvWalletName.setText(item.getWalletName());
        tvBalance.setText(item.getBalance());

        // 将WalletItem设置为View的Tag,方便点击时获取
        itemView.setTag(item);

        btnCheckBalance.setOnClickListener(v -> {
            btnCheckBalance.setEnabled(false);
            btnCheckBalance.setText("查询中...");

            // 获取当前项的数据模型
            WalletItem currentItem = (WalletItem) itemView.getTag();
            // 模拟请求
            simulateBalanceQuery(currentItem, tvBalance, btnCheckBalance);
        });

        container.addView(itemView);
    }

    private void simulateBalanceQuery(WalletItem item, TextView tvBalance, Button btn) {
        new Handler(Looper.getMainLooper()).postDelayed(() -> {
            String balance = "₹" + new Random().nextInt(10000);
            // 更新数据模型
            item.setBalance(balance);
            // 更新TextView
            tvBalance.setText(balance);
            btn.setEnabled(true);
            btn.setText("查余额");
        }, 1500);
    }
}

对应的activity_wallet.xml(需嵌套ScrollView):

<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <LinearLayout
        android:id="@+id/container"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"/>
</ScrollView>
关键注意点
  • 数据驱动UI:不管用哪种方案,余额数据一定要存在WalletItem模型里,而不是只存在TextView中。这样滚动时,视图重建/复用都会从模型读取最新数据,不会丢失。
  • 主线程更新UI:网络请求是异步的,请求成功后必须切回主线程更新UI,上面用Handler(Looper.getMainLooper())实现,实际项目可使用Retrofit回调、Coroutines或RxJava处理。
  • 防止重复请求:点击按钮后禁用按钮,请求完成后再恢复,避免用户多次点击发起重复请求。

这样实现后,不管怎么滚动,已查询的余额都会保存在数据模型里,视图始终展示最新状态,完全符合你要的PhonePe页面效果!

内容的提问来源于stack exchange,提问作者harikrishnan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 07:39:14