Android - 列表视图项上的OnClickListener仅影响最后一行

时间:2017-02-06 16:20:20

标签: java android listview android-arrayadapter

我有一个自定义单元格的列表视图,其中包含计时器,文本视图和开关。此列表视图使用ArrayList中的dumby数据填充。无论何时单击一个开关,它总是会影响列表视图中的最后一项而不是我想要点击的那一项。

这是我的自定义timeTrackCellAdapter类

public class timeTrackCellAdapter extends ArrayAdapter {
    private final Activity activity;
    private final List timeParams;
    TimeView tView = null;
    View rowView;
    //Constructor
    public timeTrackCellAdapter(Activity activity, List objects){
        super(activity, R.layout.cell_layout, objects);
        this.activity = activity;
        this.timeParams = objects;
    }
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
         rowView = convertView;


        if(rowView == null)
        {
            // Get a new instance of the row layout view
            LayoutInflater inflater = activity.getLayoutInflater();
            rowView = inflater.inflate(R.layout.cell_layout, null);

            // Hold the view objects in an object,
            // so they don't need to be re-fetched
            tView = new TimeView();
            tView.timer = (Chronometer) rowView.findViewById(R.id.timeTracker);
            tView.jobText = (TextView) rowView.findViewById(R.id.secondaryRowText);
            tView.jobSwitch = (Switch) rowView.findViewById(R.id.timeSwitch);

            // Cache the view objects in the tag,
            // so they can be re-accessed later
            rowView.setTag(tView);
        } else {
            tView = (TimeView) rowView.getTag();
        }

        // Transfer the job/time from the data object
        // to the view objects
        final timeTrackCell currentTime = (timeTrackCell) timeParams.get(position);

        tView.timer.setBase(currentTime.getChronometerTime());
        tView.jobText.setText(currentTime.getJobString());
        tView.jobSwitch.setChecked(currentTime.getSwitchPosition());


        //OnClick for switch toggle
        tView.jobSwitch.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                Boolean newCheck = tView.jobSwitch.isChecked();
                System.out.println(tView.jobText.getText());

                //If newCheck returns true, the switch is being turned on
                //If newCheck returns false, the switch is being turned off
                tView.timer.stop();
                System.out.println(newCheck);
                if(newCheck){

                    tView.jobSwitch.setChecked(true);
                    tView.jobText.setText(currentTime.getJobString());
                    tView.timer.setBase(currentTime.getChronometerTime());
                    tView.timer.start();


                }else{

                    tView.timer.stop();
                    tView.jobSwitch.setChecked(false);
                    tView.jobText.setText(currentTime.getJobString());
                    tView.timer.setBase(currentTime.getChronometerTime());

                }


            }
        });

        return rowView;

    }


    protected static class TimeView {
        protected Chronometer timer;
        protected TextView jobText;
        protected Switch jobSwitch;
    }
}

这是我的timeTrackCell类,它包含我的适配器的所有获取和设置

public class timeTrackCell {
    private boolean switchPosition;
    private long chronometerTime;
    private String jobString;

    public timeTrackCell(boolean switchPosition, long chronometerTime, String jobString){
        this.switchPosition = switchPosition;
        this.chronometerTime = chronometerTime;
        this.jobString = jobString;
    }
    //sets
    public void setSwitchPosition(boolean switchPosition){
        this.switchPosition = switchPosition;
    }
    public void setChronometerTime(long chronometerTime){
        this.chronometerTime = chronometerTime;
    }
    public void setJobString(String jobString){
        this.jobString = jobString;
    }
    //gets
    public boolean getSwitchPosition(){
        return switchPosition;
    }
    public long getChronometerTime(){
        return chronometerTime;
    }
    public String getJobString(){
        return jobString;
    }


}

这是我的单元格的xml文件,cell_layout

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:minHeight="140px"
    >
    <!--140px Seems to be the right height for 7 cells per page-->
    <!-- Block for custom listview items -->
    <Chronometer
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:id="@+id/timeTracker"
        android:layout_gravity="left"
        android:textSize="25sp"
        android:paddingLeft="10px"
        android:layout_centerVertical="true">
    </Chronometer>

    <TextView
        android:id="@+id/secondaryRowText"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/timeTracker"
        android:textSize="15sp"
        android:paddingLeft="10px"
        android:paddingTop="30px"
        >
    </TextView>

    <Switch
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:id="@+id/timeSwitch"
        android:gravity="right"
        android:layout_centerVertical="true"
        android:focusable="false"
        android:clickable="false"
        >
    </Switch>
</RelativeLayout>

这是创建listview并填充数据的java类。 timeKeeping.java

public class timeKeeping extends AppCompatActivity {
    public String empName = "Zach";
    private ListView lv;
    //tempchange
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        /////
        //Button that shows who is logged in
        setContentView(R.layout.activity_time_keeping2);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
        fab.setImageResource(R.drawable.ic_temp_profile_image);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                String greetingString = "Welcome back, " + empName + "!";
                Snackbar.make(view, greetingString, Snackbar.LENGTH_LONG)
                        .setAction("Action", null).show();
            }
        });
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        /////
        lv = (ListView) findViewById(R.id.timeList);
        //DUMBY DATA TO TEST WITH
        final List timeData = new ArrayList();
        Long testData = (long) 1000000;
        String tempJobTest = "test job ";
        for(int i = 0; i<5;i++){
            String nTempJobTest = tempJobTest + i;
            timeData.add(new timeTrackCell(false, testData, nTempJobTest));

        }


        lv.setAdapter(new timeTrackCellAdapter(this, timeData));

    }
}

我很确定我的问题在于我的timeTrackCellAdapter类中的onClick,但如果不是,我可以提供更多代码。非常感谢任何帮助!!

3 个答案:

答案 0 :(得分:2)

您在每个tView中引用了同一个onView变量。因为变量在类范围内而不在方法范围内。如果创建5行,则第一行使用类变量,第二行使用(从第一行中删除引用),依此类推。

这就是为什么当你点击任何一行时,你正在修改最后添加的行。

解决方案可能只是在方法中创建一个局部变量。但是,我建议你使用RecyclerView,它是ListView的成功者。

无论如何,首先从类中删除变量:

public class timeTrackCellAdapter extends ArrayAdapter {
    private final Activity activity;
    private final List timeParams;
    View rowView;
    ....

然后,在方法中创建它:

@Override
public View getView(int position, View convertView, ViewGroup parent) {
     rowView = convertView;
     TimeView tView;

答案 1 :(得分:0)

致电notifyDataSetChanged();

tView.jobSwitch.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {

            Boolean newCheck = tView.jobSwitch.isChecked();
            System.out.println(tView.jobText.getText());

            //If newCheck returns true, the switch is being turned on
            //If newCheck returns false, the switch is being turned off
            tView.timer.stop();
            System.out.println(newCheck);
            if(newCheck){

                tView.jobSwitch.setChecked(true);
                tView.jobText.setText(currentTime.getJobString());
                tView.timer.setBase(currentTime.getChronometerTime());
                tView.timer.start();


            }else{

                tView.timer.stop();
                tView.jobSwitch.setChecked(false);
                tView.jobText.setText(currentTime.getJobString());
                tView.timer.setBase(currentTime.getChronometerTime());

            }
            //call this method
            notifyDataSetChanged();

        }

答案 2 :(得分:-2)

 @Override
 public View getView(int position, View convertView, ViewGroup parent
 {
    //OnClick for switch toggle
    tView.jobSwitch.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {

            Boolean newCheck = tView.jobSwitch.isChecked();
            System.out.println(tView.jobText.getText());

            //If newCheck returns true, the switch is being turned on
            //If newCheck returns false, the switch is being turned off
            tView.timer.stop();
            System.out.println(newCheck);
            if(newCheck){

                tView.jobSwitch.setChecked(true);
                tView.jobText.setText(currentTime.getJobString());
                tView.timer.setBase(currentTime.getChronometerTime());
                tView.timer.start();


            }else{

                tView.timer.stop();
                tView.jobSwitch.setChecked(false);
                tView.jobText.setText(currentTime.getJobString());
                tView.timer.setBase(currentTime.getChronometerTime());

            }


        }
    });

 }

在getView方法中设置监听器可能是您应用程序可能遇到的最大错误。这个方法被隐式调用,即使在任何项目发生单个更新时,您可能会创建一个MEMORY-BLACKHOLE,因为每次滚动或进行更新时都会调用getView(int,View,ViewGroup),因此您可能已经声明了在这种情况下,你的听众一千次。尝试一些其他代码片段来设置你的监听器,这不是一个解决方案,而是一个严格的建议