ubundude
ubundude

Reputation: 89

android listview setonclicklistener only selects first view

I have custom ListView with an adapter that lets users see entries made to a database. Everything with the ListView works fine, until I try to click on any but the first entry in the list. When clicked, the entry should be loaded into an editor. For some reason, no matter which entry is clicked, the first entry in the list is loaded into the editor. Here is the activity code for the ListView:

public class MainActivity extends Activity {

public static final String KEY_ID = "listviewId";
public static final String KEY_SHORT = "projectShortTextView";
public static final String KEY_FULL = "projectFullTextView";
public static final String KEY_HOURS = "listviewHoursTV";
public static final String KEY_PROID = "projectIdTV";
private SQLiteDatabase db;
private TimesheetDatabaseHelper dbHelp = new TimesheetDatabaseHelper(this);
/** Gets a valid calendar instance for use */
final Calendar c = Calendar.getInstance();
/** Strings for formatting the date's for use */
public String dateViewForm = "EEE MM/dd/yyyy";
public String dateForm = "MM/dd/yyyy";
public String timeForm = "HH:mm";
/** Strings to store formated calendar outputs */
public String date, dateView;
/** Prepares buttons and EditText for use */
public Button minusButton, plusButton, quickAdd;
public EditText dateEditText;
public ListView list;
TimestampAdapter adapter;
SimpleDateFormat formDateView = new SimpleDateFormat(dateViewForm, Locale.US);
 SimpleDateFormat formDate = new SimpleDateFormat(dateForm, Locale.US);
 SimpleDateFormat formTime = new SimpleDateFormat(timeForm, Locale.US);
 @Override
 protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    BugSenseHandler.initAndStartSession(MainActivity.this, "8b04fe90");
    setContentView(R.layout.activity_main);

    try {
        updateCheck();
    } catch (NameNotFoundException e1) {
        e1.printStackTrace();
    } catch (IOException e1) {
        e1.printStackTrace();
    } catch (InterruptedException e) {
        e.printStackTrace();
    } catch (ExecutionException e) {
        e.printStackTrace();
    }


    /** Method to get todays date and display it in the proper places */
    date = initialDates();

    getDailyTimestamps(date);

    /**
     * Implements the Minus Button with OnCLickListener and
     * calls the minusButtonHandler if called */
    minusButton = (Button)findViewById(R.id.minusButton);
    minusButton.setOnClickListener(new View.OnClickListener() {
        public void onClick(View v) {
            try {
                date = minusButtonHandler();
                getDailyTimestamps(date);
            } catch (ParseException e) {
                e.printStackTrace();
            }
        }
    });

    /**
     * Implements the Plus Button with OnCLickListener and
     * calls the plusButtonHandler if called */
    plusButton = (Button)findViewById(R.id.plusButton);
    plusButton.setOnClickListener(new View.OnClickListener() {
        public void onClick(View v) {
            try {
                date = plusButtonHandler();
                getDailyTimestamps(date);
            } catch (ParseException e) {
                e.printStackTrace();
            }
        }
    });

    quickAdd = (Button)findViewById(R.id.quickAddButton);
    quickAdd.setOnClickListener(new View.OnClickListener() {
        public void onClick(View v) {
            quickAddHandler(v);
            getDailyTimestamps(date);
        }
    });
}

@SuppressWarnings("deprecation")
private void updateCheck() throws NameNotFoundException, IOException, InterruptedException, ExecutionException {
    Log.d("Checking for updates", "true");
    String urlVersion;
    UpdateCheck check = new UpdateCheck();
    urlVersion = check.execute().get();

    Log.d("urlVerion", urlVersion);

    PackageInfo pInfo = getPackageManager().getPackageInfo(getPackageName(), 0);
    String packageVersion = pInfo.versionName;

    Log.d("Package Version", packageVersion);

    if (!urlVersion.equals(packageVersion)) {
        AlertDialog alert = new AlertDialog.Builder(this).create();
        alert.setTitle("Version Check");
        alert.setMessage("You're version is out of date. Please visit " 
                + "www.ubundude.com/p/beta.html to update to the latest version.");

        alert.setButton("OK", new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int which) {
            }
    });
        alert.show();
    }
}

@Override 
protected void onResume() {
    super.onResume();
    getDailyTimestamps(date);
}

private void getDailyTimestamps(String date) {
    ArrayList<HashMap<String, String>> stampList = new ArrayList<HashMap<String, String>>();

    /** Open the database table for reading and writing */
    db = dbHelp.getReadableDatabase();

    String getTimestamps = "select ti._id, pr.name, pr.shortcode, ti.hours, ti.project "
            + "from timestamp ti inner join projects pr "
            + "where ti.project = pr._id and ti.date_in = '" + date + "'";

    Cursor cu = db.rawQuery(getTimestamps, null);

    if(cu != null && cu.getCount() > 0){
        cu.moveToFirst();

        do {
            HashMap<String, String> map = new HashMap<String, String>();
            map.put(KEY_ID, Integer.toString(cu.getInt(0)));
            map.put(KEY_SHORT, cu.getString(1));
            map.put(KEY_FULL, cu.getString(2));
            map.put(KEY_HOURS, cu.getString(3));
            map.put(KEY_PROID, Integer.toString(cu.getInt(4)));

            stampList.add(map);

        } while(cu.moveToNext());
    }

    cu.close();
    db.close();

    list = (ListView)findViewById(R.id.timestampListView);

    adapter = new TimestampAdapter(this, stampList);
    list.setAdapter(adapter);

    list.setOnItemClickListener(new OnItemClickListener() {

        @Override
        public void onItemClick(AdapterView<?> parent, View view,
                int position, long id) {
            Log.d("ListView On Click", "Position: " + position);
            TextView idTV = (TextView)findViewById(R.id.listviewId);
            TextView proIdTV = (TextView)findViewById(R.id.projectIdTV);
            TextView full = (TextView)findViewById(R.id.projectShortTextView);
            String test = full.getText().toString();
            Log.d("Listview", "Project Name: " + test);
            int timeId = Integer.parseInt(idTV.getText().toString());
            Log.d("Listview", "Timestamp ID: " + timeId);
            int proId = Integer.parseInt(proIdTV.getText().toString());
            Log.d("Listview", "Project ID: " + proId);
            Intent intent = new Intent(MainActivity.this, TimestampEditorActivity.class);
            intent.putExtra("TIMESTAMP_ID", timeId);
            intent.putExtra("PROJECT_ID", proId);
            startActivity(intent);
        }
    });
}

private String initialDates() {
    dateView = formDateView.format(c.getTime());
    date = formDate.format(c.getTime());

    /** Sets the text in the dateEditText to the current date */
    dateEditText = (EditText)findViewById(R.id.dateEditText);
    dateEditText.setText(dateView, TextView.BufferType.NORMAL);

    return date;
}

/** Gets the next day and displays to dateEditText 
 * @throws ParseException */
private String plusButtonHandler() throws ParseException {

    c.setTime(formDateView.parse(dateView));
    c.add(Calendar.DAY_OF_MONTH, 1);

    dateView = formDateView.format(c.getTime());
    date = formDate.format(c.getTime());

    dateEditText = (EditText)findViewById(R.id.dateEditText);
    dateEditText.setText(dateView, TextView.BufferType.NORMAL);

    return date;
}

  /** Gets the previous day and displays to dateEditText 
   * @throws ParseException */
private String minusButtonHandler() throws ParseException {
    c.setTime(formDateView.parse(dateView));
    c.add(Calendar.DAY_OF_MONTH, -1);

    dateView = formDateView.format(c.getTime());
    date = formDate.format(c.getTime());

    dateEditText = (EditText)findViewById(R.id.dateEditText);
    dateEditText.setText(dateView, TextView.BufferType.NORMAL);

    return date;
}

/**
 * Intent to move to TimestampEditorActivity
 * 
 *  @param view Gets the current view context to pass with the intent
 */
public void addNewHandler(View view) {
    Intent intent = new Intent(this, TimestampEditorActivity.class);
    startActivity(intent);
 }

/**
 * Get current date and time and place them into Timestamp table as generic entry
 * 
 * @param view
 * @throws SQLException
 */
public void quickAddHandler(View view) throws SQLException {
    String timeIn, timeOut, dateIn, dateOut;
    int project = 1; //Will get from Default project in settings
    timeIn = formTime.format(c.getTime());
    timeOut = timeIn;
    dateIn = formDate.format(c.getTime());
    dateOut = dateIn;
    db = dbHelp.getWritableDatabase();
    String insertSQL = "insert into timestamp (date_in, time_in, date_out, time_out, hours, project) " +
            "values('" + dateIn + "', '" + timeIn + "', '" + dateOut +
            "', '" + timeOut + "', 0, '" + project + "')";
    try {
        db.execSQL(insertSQL);
    } catch(Exception e) {
        Log.d("save Fail", e.getLocalizedMessage(), e.fillInStackTrace());
    }
    db.close();
}


@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.activity_main, menu);
    return true;
}

}

Here is the xml for the ListView:

    <TextView
        android:id="@+id/projectShortTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:text="@string/defaultText"
        android:textAppearance="?android:attr/textAppearanceMedium" />

    <TextView
        android:id="@+id/projectFullTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_below="@+id/projectShortTextView"
        android:text="@string/defaultText"
        android:textAppearance="?android:attr/textAppearanceSmall" />

    <TextView
        android:id="@+id/listviewId"
        android:visibility="invisible"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_toRightOf="@+id/projectShortTextView" 
        android:text="@string/defaultInt" />

     <Button
         android:id="@+id/listviewEditButton"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_centerVertical="true"
         android:layout_toLeftOf="@+id/listviewHoursTV"
         android:background="@drawable/edit"
         android:focusable="false" />

     <TextView
         android:id="@+id/listviewHoursTV"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_alignParentRight="true"
         android:layout_centerVertical="true"
         android:text="@string/defaultTime"
         android:textAppearance="?android:attr/textAppearanceMedium" />

     <TextView
         android:id="@+id/projectIdTV"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_above="@+id/projectFullTextView"
         android:layout_toRightOf="@+id/listviewId"
         android:text="@string/defaultInt"
         android:visibility="invisible" />

 </RelativeLayout>

And here is the adapter: public class TimestampAdapter extends BaseAdapter { private Activity activity; private ArrayList> data; private static LayoutInflater inflater = null;

public TimestampAdapter(Activity a, ArrayList<HashMap<String, String>> d) {
    activity = a;
    data = d;
    inflater = (LayoutInflater)activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}

public int getCount() {
    return data.size();
}

public Object getItem(int position) {
    return data.get(position);
}

public long getItemId(int position) {
    return position;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    View vi = convertView;
    if(convertView==null)
        vi = inflater.inflate(R.layout.listview_timestamp, null);

    TextView projectShort = (TextView)vi.findViewById(R.id.projectShortTextView);
    TextView projectFull = (TextView)vi.findViewById(R.id.projectFullTextView);
    TextView stampId = (TextView)vi.findViewById(R.id.listviewId);
    TextView hoursEdit = (TextView)vi.findViewById(R.id.listviewHoursTV);
    TextView projectId = (TextView)vi.findViewById(R.id.projectIdTV);

    HashMap<String, String> timestamp = new HashMap<String, String>();
    timestamp = data.get(position);

    stampId.setText(timestamp.get(MainActivity.KEY_ID));
    projectShort.setText(timestamp.get(MainActivity.KEY_SHORT));
    projectFull.setText(timestamp.get(MainActivity.KEY_FULL));
    hoursEdit.setText(timestamp.get(MainActivity.KEY_HOURS) + " hrs");
    projectId.setText(timestamp.get(MainActivity.KEY_PROID));

return vi;
}

 }    

The debug lines in the above code show the proper position for each row clicked, but the id's for the first row's information are the only ones that show up. And that is consistent with only the first row getting loaded into the editor.

Upvotes: 1

Views: 1237

Answers (1)

A--C
A--C

Reputation: 36449

Your problem probably lies in these lines:

TextView idTV = (TextView)findViewById(R.id.listviewId);
TextView proIdTV = (TextView)findViewById(R.id.projectIdTV);
TextView full = (TextView)findViewById(R.id.projectShortTextView);

You are finding these views in the layout of the Activity, not in the row of the ListView. If these ids are also duplicated in the ListView, access the whole row via

view.findViewById(R.id.yourId);

If StampList is a list of complex Objects that contain all of this data, you can skip the finding of Views and simply use the adapter or the AdapterView to access the object.

Edit: You are using a HashMap, this should be easier:

@Override
public void onItemClick(AdapterView<?> parent, View view,
                        int position, long id) {
  HashMap <String,String> currentMap = stampList.get(position);
  Intent intent = new Intent(MainActivity.this, TimestampEditorActivity.class);
  intent.putExtra("TIMESTAMP_ID", currentMap.get(MainActivity.KEY_ID));
  intent.putExtra("PROJECT_ID", currentMap.get(MainActivity.KEY_PROID));
  startActivity(intent);
}

Just make sure to declare stampList as final. Alternatively, if you don't want to specify stampList as final replace

HashMap <String,String> currentMap = stampList.get(position);

with

HashMap <String,String> currentMap = (HashMap<String,String>)parent.getItemAtPosition(position);

Upvotes: 2

Related Questions