2017-02-06 84 views
1

我有一個列表視圖與自定義單元格,其中包含一個天文臺,一個文本視圖和一個開關。該列表視圖由來自ArrayList的dumby數據填充。無論何時單擊一個開關,它總是會影響列表視圖中的最後一個項目,而不是我打算單擊的那個項目。安卓 - 列表視圖項上的OnClickListener隻影響最後一行

這裏是我的自定義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和填充d的java類ATA。 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,但如果它是不是我可以提供更多的代碼。任何幫助非常感謝!

+2

這會是如果您更輕鬆你將listview重新格式化爲recyclerview,相信我 – mayosk

回答

2

您正在參考相同的每onView變量相同tView。因爲該變量在類範圍內而不在方法範圍內。如果創建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; 
+0

如果我沒有將tView聲明爲final,那麼我怎樣才能在我的setOnClickListener中引用它? – Joris

+0

爲什麼你想要它是最終的?在你的代碼沒有被宣佈爲最終.. – adalPaRi

+0

因爲它給了我錯誤「變量」tView「從內部類訪問,需要最終聲明」 – Joris

-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),所以您可能會聲明你的聽衆在這種情況下有一千次。嘗試一些其他的代碼片段來設置你的聽衆,這不是一個解決方案,但嚴格的建議

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(); 

     }