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

Android:重启App后保留含Button与TextBox的ListView Item状态

问题描述

我在主Activity里有个ListView,每个Item默认显示Button、隐藏TextBox。点击Button后,Button消失,TextBox显示"Activated by currentUser",同时这条消息会存入数据库,而且这个逻辑和ListItem的点击事件是分开的。

现在遇到的问题是:重启App后,ListView Item的状态没法保留。比如有4个Item,其中2个已经点击Button切换了状态,但重启后Button又重新显示,TextBox不见了。另外,这个App是连接MEAN Stack Web应用的,更新/删除操作会同步到MEAN端。

附上我的自定义Adapter代码:

import com.elegantcab.getcabgo.utils.QueryUtils; 
public class CabDriverNotificationAdapter extends ArrayAdapter<CabDriverNotification> { 
    private SessionManager mSession; 
    private String mNotificationId; 
    private String mMemo; 
    private static final String DATE_FORMAT = "LLL dd, yyyy"; 
    private static final String TIME_FORMAT = "h:mm a"; 

    public CabDriverNotificationAdapter(Context context, List<CabDriverNotification> notifications) { 
        super(context, 0, notifications); 
    }

    /** The static holder class will act as a holder for Android.Widget items 
     * such as the activated by textview and the activate button **/ 
    public static class ViewHolder{ 
        LinearLayout _layout; 
        TextView _activatedBy; 
        Button acceptButton; 
    } 

    @Override 
    public View getView(int position, View convertView, ViewGroup parent) { 
        View listItemView = convertView; 
        final ViewHolder holder; 
        mSession = new SessionManager(getContext()); 
        final CabDriverNotification currentNotification = getItem(position); 
        // get the id of current notification 
        mNotificationId = String.valueOf(currentNotification.getObjectId()); 

        if (listItemView == null) { 
            listItemView = LayoutInflater.from(getContext()).inflate( 
                    R.layout.notification_list_item, parent, false); 
            holder = new ViewHolder(); 
            holder._layout = (LinearLayout) listItemView.findViewById(R.id.activate_layout); 
            holder._activatedBy = (TextView) listItemView.findViewById(R.id.activated_by_message); 
            holder.activateButton = (Button) listItemView.findViewById(R.id.activate_button); 
            listItemView.setTag(holder); 

            //onClickListener for activate button 
            holder.activateButton.setOnClickListener(new View.OnClickListener() { 
                @Override 
                public void onClick(View v) { 
                    mMemo = toggleActivaionStatus(holder, mNotificationId); 
                    QueryUtils.updateNotification(getContext(), new SessionManager(getContext()).getNotificationUrl(), mNotificationId, mMemo); 
                } 
            }); 
        } else { 
            holder = (ViewHolder) listItemView.getTag(); 
            holder._activatedBy = (TextView) listItemView.findViewById(R.id.activated_by_message); 
            holder.activateButton = (Button) listItemView.findViewById(R.id.activate_button); 

            if(currentNotification.getMemo().contains("Activated by")){ 
                holder._activatedBy.setText(currentNotification.getMemo()); 
                holder._activatedBy.setVisibility(View.VISIBLE); 
                holder.activateButton.setVisibility(View.GONE); 
            } else{ 
                holder._activatedBy.setVisibility(View.GONE); 
                holder.activateButton.setVisibility(View.VISIBLE); 
                holder.activateButton.setOnClickListener(new View.OnClickListener() { 
                    @Override 
                    public void onClick(View v) { 
                        mMemo = toggleActivateStatus(holder, mNotificationId); 
                        QueryUtils.updateNotification(getContext(), new SessionManager(getContext()).getNotificationUrl(), mNotificationId, mMemo); 
                    } 
                }); 
            } 
        } 

        // Create full name from first and last name 
        String fullName = currentNotification.getFirstname() + " " + currentNotification.getLastname(); 
        // Find the TextView with view ID name 
        TextView nameView = (TextView) listItemView.findViewById(R.id.name); 
        // Display the name in that TextView 
        nameView.setText(fullName); 

        // Create a new Date object from the time in milliseconds of the notification 
        Date dateObject = new Date(currentNotification.getTimeInMilliseconds()); 
        // Find the TextView with view ID date 
        TextView dateView = (TextView) listItemView.findViewById(R.id.date); 
        // Format the date string (i.e. "Mar 3, 1984") 
        final String formattedDate = formatDate(dateObject); 
        // Display the date of the current notification in that TextView 
        dateView.setText(formattedDate); 

        // Find the TextView with view ID time 
        TextView timeView = (TextView) listItemView.findViewById(R.id.time); 
        // Format the time string (i.e. "4:30PM") 
        final String formattedTime = formatTime(dateObject); 
        // Display the time of the current notification in that TextView 
        timeView.setText(formattedTime);
    }
}
解决方案

嘿,这个问题核心就是状态没有和数据绑定,重启后没有从服务器拉取最新状态,我给你拆解几个关键修复点:

  • 统一Adapter的状态渲染逻辑
    你现在的代码在convertView == null和else分支里分别处理状态,很容易出现逻辑不一致。应该把状态判断的代码抽出来,不管View是新创建还是复用的,都统一执行状态设置,避免复用View时状态出错。修改后的getView方法如下:

    @Override 
    public View getView(int position, View convertView, ViewGroup parent) { 
        View listItemView = convertView; 
        final ViewHolder holder; 
        mSession = new SessionManager(getContext()); 
        final CabDriverNotification currentNotification = getItem(position); 
        mNotificationId = String.valueOf(currentNotification.getObjectId()); 
    
        if (listItemView == null) { 
            listItemView = LayoutInflater.from(getContext()).inflate( 
                    R.layout.notification_list_item, parent, false); 
            holder = new ViewHolder(); 
            holder._layout = (LinearLayout) listItemView.findViewById(R.id.activate_layout); 
            holder._activatedBy = (TextView) listItemView.findViewById(R.id.activated_by_message); 
            holder.activateButton = (Button) listItemView.findViewById(R.id.activate_button); 
            listItemView.setTag(holder); 
        } else { 
            holder = (ViewHolder) listItemView.getTag(); 
        }
    
        // 核心:统一处理每个Item的显示状态
        if(currentNotification.getMemo() != null && currentNotification.getMemo().contains("Activated by")){
            holder._activatedBy.setText(currentNotification.getMemo());
            holder._activatedBy.setVisibility(View.VISIBLE);
            holder.activateButton.setVisibility(View.GONE);
        } else {
            holder._activatedBy.setVisibility(View.GONE);
            holder.activateButton.setVisibility(View.VISIBLE);
            // 只在Button显示时设置点击监听,避免重复绑定
            holder.activateButton.setOnClickListener(v -> {
                mMemo = toggleActivateStatus(holder, mNotificationId);
                // 关键:更新本地数据对象的状态
                currentNotification.setMemo(mMemo);
                // 通知Adapter刷新界面
                notifyDataSetChanged();
                // 同步到MEAN服务器
                QueryUtils.updateNotification(getContext(), mSession.getNotificationUrl(), mNotificationId, mMemo);
            });
        }
    
        // 下面的姓名、日期、时间渲染代码保持不变
        String fullName = currentNotification.getFirstname() + " " + currentNotification.getLastname();
        TextView nameView = listItemView.findViewById(R.id.name);
        nameView.setText(fullName);
    
        Date dateObject = new Date(currentNotification.getTimeInMilliseconds());
        TextView dateView = listItemView.findViewById(R.id.date);
        final String formattedDate = formatDate(dateObject);
        dateView.setText(formattedDate);
    
        TextView timeView = listItemView.findViewById(R.id.time);
        final String formattedTime = formatTime(dateObject);
        timeView.setText(formattedTime);
    
        return listItemView;
    }
    
  • 本地数据同步要及时
    点击Button调用接口更新服务器后,一定要立刻更新本地currentNotification的memo字段,然后调用notifyDataSetChanged()让Adapter刷新界面。这样不仅当前界面能马上显示正确状态,内存中的数据也会同步更新,避免后续复用View时出错。

  • 启动时拉取最新数据
    在主Activity的onCreate方法里,一定要确保从MEAN端拉取最新的通知列表,而不是使用旧的缓存数据。重启App后,Adapter拿到的是服务器返回的最新状态数据,自然就能正确显示每个Item的Button或TextBox了。

  • 注意空值判断
    加上currentNotification.getMemo() != null的判断,避免空指针异常,毕竟服务器返回的字段可能为空。

内容的提问来源于stack exchange,提问作者Choudhury Saadmaan Mahmid

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 08:25:43