制作 ListView 时遇到问题,其中每个项目都显示模型的 ArrayList

Posted

技术标签:

【中文标题】制作 ListView 时遇到问题,其中每个项目都显示模型的 ArrayList【英文标题】:Trouble making a ListView where each item displays an ArrayList of a model 【发布时间】:2015-08-01 15:23:04 【问题描述】:

我正在处理警报我已经设置了整个警报系统(模型、数据库、服务、接收器等),但这不是重点。

我将每个警报分组到一个名为“matchingAlarms”的数组列表中,该数组列表基于用户输入的重复天数(周日至周六)。 我把这部分记下来了,没问题

现在使用 matchAlarms Arraylist,我正在尝试创建一个 ListView,其中 ListView 中的每个项目都显示该 arraylist 的每个索引的警报名称和警报时间(我希望它们在 ListView 中使用计时器进行更改)。

例子:

我有 1 个闹钟:上午 8 点 - 晚上 11 点,重复天数:周日至周四 AND 1 个闹钟,上午 9 点至下午 12 点,重复天数:周五至周六

这些警报中的每一个都在matchingAlarms Arraylist的索引中, 所以matchingAlarms的大小是2。

我想我提到了所有内容,现在是代码。

AlarmListAdapter:

public class AlarmListAdapter extends BaseAdapter 

public static Context mContext;
private List<AlarmModel> mAlarms;
private ArrayList<ArrayList<AlarmModel>> mMatchingAlarms = new ArrayList<ArrayList<AlarmModel>>();
private ArrayList<AlarmModel> grouped = new ArrayList<AlarmModel>();

private Animation anim;

AlarmModel model;
TextView txtTime,txtName,sun,mon,tue,wed,thur,fri,sat;
ToggleButton btnToggle;
int matchingAlarmsIndex = 0;
int groupIndex = 0;
int itemIndex;

public AlarmListAdapter(Context context, List<AlarmModel> alarms, ArrayList<ArrayList<AlarmModel>> matchingAlarms) 
    mContext = context;
    mAlarms = alarms;
    mMatchingAlarms = matchingAlarms;
    anim = AnimationUtils.loadAnimation(mContext, R.anim.right_left);


public AlarmListAdapter(Context context) 
    mContext = context;


public void setAlarms(List<AlarmModel> alarms) 
    mAlarms = alarms;


@Override
public int getCount() 
    if (mMatchingAlarms != null) 
        return mMatchingAlarms.size();
    
    return 0;


@Override
public ArrayList<AlarmModel> getItem(int position) 
    if (mMatchingAlarms != null) 
        return mMatchingAlarms.get(position);
    
    return null;


@Override
public long getItemId(int position) 
    if (mAlarms != null) 
        return mAlarms.get(position).id;
    
    return 0;




@Override
public View getView(int position, View view, ViewGroup parent) 

    if (view == null) 
        LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        view = inflater.inflate(R.layout.alarm_list_item, parent, false);
    

    txtName = (TextView) view.findViewById(R.id.alarm_item_name);
    txtTime = (TextView) view.findViewById(R.id.alarm_item_time);
    sun = (TextView) view.findViewById(R.id.alarm_item_sunday);
    mon = (TextView) view.findViewById(R.id.alarm_item_monday);
    tue = (TextView) view.findViewById(R.id.alarm_item_tuesday);
    wed = (TextView) view.findViewById(R.id.alarm_item_wednesday);
    thur = (TextView) view.findViewById(R.id.alarm_item_thursday);
    fri = (TextView) view.findViewById(R.id.alarm_item_friday);
    sat = (TextView) view.findViewById(R.id.alarm_item_saturday);
    btnToggle = (ToggleButton) view.findViewById(R.id.alarm_item_toggle);

    grouped = getItem(position);


    Timer timer = new Timer();
    timer.scheduleAtFixedRate(new TimerTask() 
        public void run() 
            ((AlarmListActivity) mContext).runOnUiThread(new Runnable() 
                @Override
                public void run() 
                    if ((groupIndex + 1) <= grouped.size()) 
                        model = grouped.get(groupIndex);
                        updateTimeAndDates(model);
                        groupIndex++;
                    
                    if ((groupIndex + 1) > grouped.size()) 
                        groupIndex = 0;
                    
                    Log.i("", String.valueOf(groupIndex));
                
            );

        
    , 0, 2500);



    return view;


private void updateTextColor(TextView view, boolean isOn) 
    if (isOn) 
        view.setTextColor(Colors.IndianRed);
     else 
        view.setTextColor(Color.LTGRAY);
    


private void updateTimeAndDates(AlarmModel model) 
    txtName.setText(model.name);
    txtName.startAnimation(anim);
    txtTime.setText(DietDoctor.to12Hours(model.timeHour, model.timeMinute));
    txtTime.startAnimation(anim);

    updateTextColor(sun, model.getRepeatingDay(AlarmModel.SUNDAY));
    updateTextColor(mon, model.getRepeatingDay(AlarmModel.MONDAY));
    updateTextColor(tue, model.getRepeatingDay(AlarmModel.TUESDAY));
    updateTextColor(wed, model.getRepeatingDay(AlarmModel.WEDNESDAY));
    updateTextColor(thur, model.getRepeatingDay(AlarmModel.THURSDAY));
    updateTextColor(fri, model.getRepeatingDay(AlarmModel.FRDIAY));
    updateTextColor(sat, model.getRepeatingDay(AlarmModel.SATURDAY));

    btnToggle.setChecked(model.isEnabled);



AlarmListActivity:

public class AlarmListActivity extends ListActivity 

    private AlarmListAdapter mAdapter;
    private AlarmDBHelper dbHelper = new AlarmDBHelper(this);
    private Context mContext;
    private boolean fromSettings;
    private ArrayList<ArrayList<AlarmModel>> matchingAlarms = new ArrayList<ArrayList<AlarmModel>>();

    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);

        if(getIntent().hasExtra("FromSettings"))
        fromSettings = getIntent().getExtras().getBoolean("FromSettings");

        mContext = this;

        requestWindowFeature(Window.FEATURE_ACTION_BAR);

        setContentView(R.layout.activity_alarmlist);

        setGroups();

        mAdapter = new AlarmListAdapter(this, dbHelper.getAlarms(), matchingAlarms);

        setListAdapter(mAdapter);
    
...

public void setGroups() 
        ArrayList<AlarmModel> group = new ArrayList<AlarmModel>();
        List<AlarmModel> mAlarms = dbHelper.getAlarms();
        for (int i = 0; i < mAlarms.size(); i++) 
            if ((i + 1) != mAlarms.size()) 
                boolean result = Arrays.equals(mAlarms.get(i).getRepeatingDays(), mAlarms.get(i + 1).getRepeatingDays());
                Log.i("Result", Boolean.toString(result));
                if (result) 
                    if (i == 0)group.add(mAlarms.get(i));
                    group.add(mAlarms.get(i+1));
                
                if (!result) 
                    if (i == 0)group.add(mAlarms.get(i));
                    matchingAlarms.add(group);
                    group = new ArrayList<AlarmModel>();
                    group.add(mAlarms.get(i+1));
                
            

            if ((i + 1) == mAlarms.size()) 
                boolean result1 = Arrays.equals(mAlarms.get(i).getRepeatingDays(), mAlarms.get(i - 1).getRepeatingDays());
                Log.i("Result_1", Boolean.toString(result1));
                if (result1) 
                    group.add(mAlarms.get(i));
                    matchingAlarms.add(group);
                
                if (!result1) 
                    matchingAlarms.add(group);
                    group = new ArrayList<AlarmModel>();
                    group.add(mAlarms.get(i));
                
            

        
        Log.i("Matching Alarms", String.valueOf(matchingAlarms.size()));
        Log.i("Group", String.valueOf(matchingAlarms.get(0).size()));
        Log.i("UnGrouped", String.valueOf(mAlarms.size()));

    

我认为真正的问题在于 getView 方法和其中的计时器。 正如你从下面的图片中看到的,我只有周五到周六去。第一项应该有重复日期的警报:Sun-Thurs

【问题讨论】:

【参考方案1】:

这是因为getView 被多次调用(ListView 上的每个项目至少调用一次)。

因此,在您的适配器上,当您使用所有这些 TextView 字段时,您每次都会覆盖它们的引用,并且只有最后一个是真正正确的。

要解决这个问题,最好的办法是应用Holder 模式。如果你用谷歌搜索它,你会发现大约一百万五十万个例子以及它是如何工作的。

private static class Holder 
    AlarmModel model;
    TextView txtTime,txtName,sun,mon,tue,wed,thur,fri,sat;
    ToggleButton btnToggle;
    Timer timer = new Timer();

然后将您的updateTimeAndDates 更新为:

updateTimeAndDates(Holder h) 
     h.timer.cancel();
     h.timer.purge();
     // carry on updating the values and create the re-schedule the updates.

我也建议不要使用计时器,只需在视图上使用.postDealayed(Runnable, long);。计时器根本不是做得很好的课程。

【讨论】:

以上是关于制作 ListView 时遇到问题,其中每个项目都显示模型的 ArrayList的主要内容,如果未能解决你的问题,请参考以下文章

片段中 ListView 的 setOnItemClickListener

每个项目中带有 Switch 和 TextView 的自定义 ListView

如何使用 firebase 获取 listView 中每个项目的数据?

使用 CardView BaseAdapter OnItemClick 自定义 ListView

ScrollView中嵌套ListView时,listview高度显示的问题

如何使 ListView 中的项目打开一个新的空活动