Android ListView with LinkedHashMap - scrambled list when scrolling - java

I've had trouble finding much documentation on using LinkedHashMap with a ListView for Android, but I was able to get the list to populate correctly with the below.
Unfortunately, when I scroll, the list is scrambled the same as it would be if I was using a regular HashMap. I'm not sure what I'm doing wrong.
MainActivity.java (only a portion):
public class MainActivity extends ListActivity {
private ListView dataList;
ArrayList<String> listItems=new ArrayList<String>();
ListViewAdapter adapter;
private ArrayList<LinkedHashMap<String, String>> list;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
dataList = (ListView)findViewById(android.R.id.list);
list=new ArrayList<LinkedHashMap<String,String>>();
adapter=new ListViewAdapter(this, list);
dataList.setAdapter(adapter);
addItems();
}
public void addItems() {
LinkedHashMap<String,String> row = new LinkedHashMap<String, String>();
row.put(KEY_COLUMN, key);
row.put(FIRST_COLUMN, dateTime);
row.put(SECOND_COLUMN, data1);
row.put(THIRD_COLUMN, data2);
row.put(FOURTH_COLUMN, data3);
list.add(row);
adapter.notifyDataSetChanged();
}
}
ListViewAdapter Class
public class ListViewAdapter extends BaseAdapter{
public ArrayList<LinkedHashMap<String, String>> list;
Activity activity;
TextView txtKey;
TextView txtFirst;
TextView txtSecond;
TextView txtThird;
TextView txtFourth;
public ListViewAdapter(Activity activity,ArrayList<LinkedHashMap<String, String>> list){
super();
this.activity = activity;
this.list = list;
}
#Override
public int getCount() {
// TODO Auto-generated method stub
return list.size();
}
#Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return list.get(position);
}
#Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return 0;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
if(convertView == null){
LayoutInflater inflater = activity.getLayoutInflater();
convertView = inflater.inflate(R.layout.list_row_columns, null);
txtKey = (TextView) convertView.findViewById(R.id.row_key);
txtFirst = (TextView) convertView.findViewById(R.id.date_time);
txtSecond = (TextView) convertView.findViewById(R.id.data1);
txtThird = (TextView) convertView.findViewById(R.id.data2);
txtFourth = (TextView) convertView.findViewById(R.id.data3);
}
LinkedHashMap<String, String> map = list.get(position);
txtKey.setText(map.get(KEY_COLUMN));
txtFirst.setText(map.get(FIRST_COLUMN));
txtSecond.setText(map.get(SECOND_COLUMN));
txtThird.setText(map.get(THIRD_COLUMN));
txtFourth.setText(map.get(FOURTH_COLUMN));
return convertView;
}
}

The simplest solution would be to use ArrayAdapter rather than rolling your own BaseAdapter subclass. But, assuming that you really want to extend BaseAdapter...
First, get rid of all of the widgets from the class declaration (e.g., TextView txtKey), moving them to be local variables inside of getView().
Then, populate those local variables whether or not you are inflating a new layout.
Other improvements:
Never use LayoutInflater.from() when you have an Activity. Call getLayoutInflater() on the Activity, so you get a LayoutInflater that knows about your themes and styles.
Use getItem(), instead of list.get(position), in getView(), so getView() and getItem() stay in sync.

Related

Having problems while trying to populate a todo listview using a custom adaptor?

I want a user to input data through an editable text and I want to receive that data through a custom made listview, for that I am trying to use a custom adapter to add a textfield into my listview, through the tostring() method I have converted the data from the editable textview to a string and I am adding that string within my custom adapter to an Arraylist variable values and I’m trying to display that data through get(0) but either the Arraylist is not populating correctly or the data is not displaying properly because whenever I type something within my editable text and press the add button nothing happens, before this I added the string to an Array Adapter and the listview was populating normally, what am I doing wrong?
public class todoFragment extends ListFragment {
private EditText mToDoField;
private Button mAdd;
UsersAdapter mAdapter;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getActivity().setTitle(R.string.todo_title);
}
public class UsersAdapter extends ArrayAdapter<String> {
public Context context;
public ArrayList<String> values;
public UsersAdapter(Context context, ArrayList<String> values) {
super(context, 0, values);
this.context = context;
this.values = values;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = LayoutInflater.from(getContext()).inflate(R.layout.todo_list, parent, false);
TextView todoTextView = (TextView) convertView.findViewById(R.id.todo_TextView);
todoTextView.setText(values.get(0));
return convertView;
}
}
#TargetApi(9) // remember this for isEmpty()
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_todo, container, false);
ArrayList<String> todoList = new ArrayList<String>();
mAdapter = new UsersAdapter(getActivity(), todoList);
ListView listViewToDo = (ListView) v.findViewById (android.R.id.list);
listViewToDo.setAdapter(mAdapter);
mToDoField = (EditText) v.findViewById(R.id.todo_editText);
mAdd = (Button)v.findViewById(R.id.add_button);
mAdd.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
String toDo = mToDoField.getText().toString().trim();
if (toDo.isEmpty()){
return;
}
mAdapter.values.add(toDo);
mToDoField.setText("");
}
});
return v;
}
}
Firstly, you should not be doing
todoTextView.setText(values.get(0));
Because this will always return the first element of the values list. You should do
todoTextView.setText(values.get(position));
Secondly,
mAdapter.values.add(toDo);
is not really right. It will work, but its not the best practise. Try using something like
mAdapter.add(toDo);
or
values.add(toDo);
Now once you've added the data to the list, you need to notify the adapter that the data set has been changed. This is done by
mAdapter.notifyDataSetChanged();
When you manually update the data don't forget to call:
mAdapter.notifyDataSetChanged();
Instead of mAdapter.values.add(toDo); UsemAdapter.add(toDo);
Look at the Add Method Of ArrayAdpter Class, it Itself use notifyDataSetChanged() so need to write any extra line of code:
public void add(T object) {
synchronized (mLock) {
if (mOriginalValues != null) {
mOriginalValues.add(object);
} else {
mObjects.add(object);
}
}
if (mNotifyOnChange) notifyDataSetChanged();
}

return Changed arrayList from adapter android

have gridview for which set adapter called ImageAdapter with parameter of arraylist. Inside the adapter have onclicklistener during which from the arraylist one item is removed and then when i use this line ImageAdapter.notifyDataSetChanged in the gridview item is removed. Now i need the changed arrayList in my activity so how can i get it.
Here's my code:
public class ImageAdapter extends BaseAdapter {
Context context;
ArrayList<String> listCheck = new ArrayList<String>();
ImageAdapter adapter = this;
public ImageAdapter(Context context, ArrayList<String> list) {
this.context = context;
listCheck = list;
}
#Override
public int getCount() {
return listCheck.size();
}
#Override
public Object getItem(int arg0) {
return null;
}
#Override
public long getItemId(int arg0) {
return 0;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
ViewHolder121 holder;
if (convertView == null) {
convertView = LayoutInflater.from(context).inflate(
R.layout.item_gridmain, null);
holder = new ViewHolder121();
holder.imageView = (ImageView) convertView
.findViewById(R.id.img_selected_image);
holder.close = (ImageButton) convertView
.findViewById(R.id.img_btn_cancel);
convertView.setTag(holder);
}
else {
holder = (ViewHolder121) convertView.getTag();
}
holder.close.setOnClickListener(new View.OnClickListener() {
public void onClick(View arg1) {
listCheck.remove(position);
adapter.notifyDataSetChanged();
}
}); Bitmap bm = decodeSampledBitmapFromUri(listCheck.get(position), 220,
220);
holder.imageView.setImageBitmap(bm);
return convertView;
} }
Fragment code:
ImageAdapter mainActivityAdapter = new ImageAdapter(getActivity(), ar1);
gridview_withimage.setAdapter(mainActivityAdapter);
question: How to get changed arraylist from ImageAdapter to called Fragement
How to get changed arraylist from ImageAdapter to called Fragement
Create a method in ImageAdapter which will return ArrayList used as data-source in Adapter:
public ArrayList<String> getModifyList() {
return listCheck;
}
Call getModifyList method in Fragment for getting ArrayList using Adapter object:
gridview_withimage.setAdapter(mainActivityAdapter);
gridview_withimage.postDelayed(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
ArrayList<String> arrNewList=mainActivityAdapter.getModifyList();
}
}, 100);
You can pass Fragment instance to Adapter.
private Fragment fragment;
public ImageAdapter(Context context, ArrayList<String> list,Fragment mfragment) {
this.context = context;
listCheck = list;
this.fragment=mfragment;
}
and Make one public method in your fragment and call using this instance of Fragment fragment;
You can create an interface like this
public interface ImageAdapterListener{
void onListChange(List<String> list);
}
And declare a member in ImageAdapter
private ImageAdapterListener listener;
public setListener(ImageAdapterListener listener){
this.listener = listener}
override the notifyDataSetChanged
#Override
void notifyDataSetChanged{
super.notifyDataSetChanged();
if(listener!= null) listener.onListChange(listCheck);
}
and make your fragment implement that interface.
class Myfragment extends Fragment implements ImageAdapterListener {
ImageAdapter mainActivityAdapter = new ImageAdapter(getActivity(), ar1);
gridview_withimage.setAdapter(mainActivityAdapter);
mainActivityAdapter.setListener(this);
#Override
void onListChange(List<String> list){
//do your stuff
}
}

ListView using BaseAdapter not showing in Activity

I'm trying to inflate a list using baseadapter within an activity. The list just doesn't inflate. From the logs implemented within the class, the getView() function doesn't even execute. Here's the code. -
public class CallLog extends Activity {
ListView logList;
List mList;
Context mCtx;
ArrayList<String> logName;
ArrayList<String> logNumber;
ArrayList<String> logTime;
#Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.reject_call_log);
mCtx = getApplicationContext();
ListView logList = (ListView) findViewById(R.id.log_list);
mList = new List(mCtx, R.layout.log_row);
logList.setAdapter(mList);
SharedPreferences savedLogName = PreferenceManager.getDefaultSharedPreferences(mCtx);
SharedPreferences savedLogNumber = PreferenceManager.getDefaultSharedPreferences(mCtx);
SharedPreferences savedLogTime = PreferenceManager.getDefaultSharedPreferences(mCtx);
try{
logName = new ArrayList(Arrays.asList(TextUtils.split(savedLogName.getString("logName", null), ",")));
logNumber = new ArrayList(Arrays.asList(TextUtils.split(savedLogNumber.getString("logNumber", null), ",")));
logTime = new ArrayList(Arrays.asList(TextUtils.split(savedLogTime.getString("logTime", null), ",")));
Collections.reverse(logName);
Collections.reverse(logNumber);
Collections.reverse(logTime);
}catch(NullPointerException e){
e.printStackTrace();
//TextView noLog = (TextView)findViewById(R.id.no_log);
}
}
public class List extends BaseAdapter {
LayoutInflater mInflater;
TextView nameText;
TextView numberText;
TextView timeText;
int timePos = 1;
public List(Context context, int resource) {
}
#Override
public int getCount() {
return 0;
}
#Override
public Object getItem(int i) {
return null;
}
#Override
public long getItemId(int i) {
return 0;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
if (convertView == null) {
v = mInflater.inflate(R.layout.row, null);
}
nameText = (TextView) v.findViewById(R.id.log_name);
numberText = (TextView) v.findViewById(R.id.log_number);
timeText = (TextView) v.findViewById(R.id.log_time);
nameText.setText(logName.get(position));
numberText.setText(logNumber.get(position));
timeText.setText(logTime.get(timePos) + logTime.get(timePos+1));
Log.d("RejectCall", "ListView");
timePos+=2;
return v;
}
}
}
Where is it all going wrong? Also, is there a better way to do what I'm trying to do?
Please replace the following code :
#Override
public int getCount() {
return 0;
}
with
#Override
public int getCount() {
return logName.size();
}
As list view only show the numbers of rows that is returned by this method and right now you are returning 0;
And after fetching the data in arraylist please use adapter.notifyDataSetChanged() to notify the list view.
You have to call notifyDataSetChanged() as you are filling data in array list after setting the adapter. so to notify the list view that data has been changed you have to call notify method(as above)
Your getItem() and getCount() haven't been implemented. If you want any kind of adapter to work for the list, these need to be implemented. Your list is also not holding any actual data, so getItem() has nothing to set.
Don't forget to call notifiyDataSetChanged() in your adapter after you set appropriate implementations for the above two functions.

ListView of ONLY drawables

I have a dynamic array of drawables and want to display them in a scrollable list. The thing I am having the most trouble with is the array adapter. I don't get any compile time errors with this code, but the runtime error I get is -
Process: com.example.michael.myandroidappactivity, PID: 12297
java.lang.IllegalStateException: ArrayAdapter requires the resource ID to be a TextView
I don't want to use a textview though! Here's the main code-
public class cards extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_show_old_cards);
ListView list = (ListView)findViewById(R.id.showCardList);
cardPile tmp = cardPile.getInstance();
ArrayList<Integer> discardPile = tmp.getDiscardPile();
ArrayAdapter<Integer> imgAdapt = new ArrayAdapter<Integer>(this,R.layout.listview_layout,discardPile);
list.setAdapter(imgAdapt);
}
}
You have to create a new class that extends the BaseAdapter interface and modify the getView method to return the view you want to show in your ListView. For example:
public class ImageAdapter extends BaseAdapter
{
private Context context;
private ArrayList<Integer> imagesIds;
public ImageAdapter(Context _context, ArrayList<Integer> _imageIds)
{
context = _context;
imageIds = _imageIds;
}
#Override
public int getCount()
{
return imgIds.size();
}
#Override
public Object getItem(int position)
{
return null;
}
#Override
public long getItemId(int position) {
return 0;
}
#Override
public View getView(int position, View convertView, ViewGroup parent)
{
ImageView view;
if( convertView != null ) // recycle call
{
view = (ImageView) convertView;
}
else
{
view = new ImageView(context);
image.setBackgroundResource(imageIds.get(position));
}
return view;
}
}
Then modify your listView adapter as:
list.setAdapter( new ImageAdapter( this, discardPile) );

No Solution for NullPointerException

I want to create a BaseAdapter for a ListView. From my database I get an ArrayList that contains the entries for the ListView. The onCreate Method works fine but if I click the button to insert data to the database and display it in the ListView my app crashes. I'm looking for the Solution but can't find it. Maybe you do.
Logcat says there is a NullPointerException at the point where the text of the TextView is set (LaunchActivity$CustomAdapter.getView).
LaunchActivity.java
public class LaunchActivity extends Activity {
ImageView buttonAdd;
EditText insertText;
SubjectAdapter helper;
ListView listView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_launch);
helper=new SubjectAdapter(this);
listView = (ListView) findViewById(R.id.listViewLaunch);
listView.setEmptyView(findViewById(R.id.emptyView));
insertText = (EditText) findViewById(R.id.editTextLaunch);
buttonAdd = (ImageView) findViewById(R.id.imageViewLaunch);
buttonAdd.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
String subject = insertText.getText().toString();
long id=helper.insertData(subject);
if(id<0){
Log.d("Personal", "insertData not successfull");
} else {
// Hiding the keyboard
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(insertText.getWindowToken(), 0);
// loading ListView with newly added data
loadListViewData();
Log.d("Personal", "insertData successfull");
Toast.makeText(LaunchActivity.this, subject+" hinzugefügt", Toast.LENGTH_LONG).show();
insertText.setText("");
}
}
});
loadListViewData();
}
public void loadListViewData() {
// database handler
SubjectAdapter helper = new SubjectAdapter(getApplicationContext());
// Get Data from Database and set ArrayList
ArrayList<String> list = (ArrayList<String>) helper.getData();
// Creating adapter for ListView
CustomAdapter adapter = new CustomAdapter(getApplicationContext(), list);
// attaching data adapter to ListView
listView.setAdapter(adapter);
}
class CustomAdapter extends BaseAdapter{
ArrayList<String> list = new ArrayList<String>();
Context context;
// Constructor
CustomAdapter(Context context, ArrayList<String> list){
this.list = list;
this.context = context;
}
#Override
public int getCount() {
// TODO Auto-generated method stub
return list.size();
}
#Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return list.get(position);
}
#Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View row = convertView;
// LayoutInflation and Recycling
if(row == null){
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.item_listview, parent, false);
}
TextView myText = (TextView) findViewById(R.id.textList);
// Get String from ArrayList
String temp = list.get(position);
// Set Text for TextView inside ListView
myText.setText(temp);
return row;
}
}
}
If row is null you have to inflate and assign the result to row!
row = inflater.inflate(R.layout.item_listview, parent, false);
Also you'll want to get myText from row:
TextView myText = (TextView) row.findViewById(R.id.textList);
First create object of ArrayList<String> in getData() and check code below:
public void loadListViewData() {
// database handler
SubjectAdapter helper = new SubjectAdapter(getApplicationContext());
// Get Data from Database and set ArrayList
ArrayList<String> list = helper.getData();
// Creating adapter for ListView
CustomAdapter adapter = new CustomAdapter(getApplicationContext(), list);
// attaching data adapter to ListView
listView.setAdapter(adapter);
}
class CustomAdapter extends BaseAdapter{
ArrayList<String> list = null;
Context context;
// Constructor
CustomAdapter(Context context, ArrayList<String> list){
this.list = list;
this.context = context;
}
#Override
public int getCount() {
// TODO Auto-generated method stub
return list.size();
}
#Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return list.get(position);
}
#Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View row = convertView;
// LayoutInflation and Recycling
if(row == null){
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.item_listview, parent, false);
}
TextView myText = (TextView) findViewById(R.id.textList);
// Get String from ArrayList
String temp = list.get(position);
// Set Text for TextView inside ListView
myText.setText(temp);
return row;
}
}
and make sure return type of getData() will be ArrayList<String>
hope it will help.

Categories