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.
Related
I made adapter for ListView. If I fill the elements array before creating the adapter and linking it to the listView, the elements are displayed.
But if I use the updateItems () method to add items when the button is clicked, nothing happens.
Code of adapter:
public class ListAdapter extends ArrayAdapter<Lf> {
private LayoutInflater inflater;
private int layout;
private List<Lf> lfs;
public ListAdapter(Context context, int resource, List<Lf> lfs) {
super(context, resource, lfs);
this.lfs = lfs;
this.layout = resource;
this.inflater = LayoutInflater.from(context);
}
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder;
if(convertView==null){
convertView = inflater.inflate(this.layout, parent, false);
viewHolder = new ViewHolder(convertView);
convertView.setTag(viewHolder);
}
else{
viewHolder = (ViewHolder) convertView.getTag();
}
Lf lf = lfs.get(position);
viewHolder.name.setText(lf.getLf());
viewHolder.freq.setText((int)lf.getFreq() + "");
return convertView;
}
public void updateItems(List<Lf> lfs) {
this.lfs.clear();
this.lfs.addAll(lfs);
this.notifyDataSetChanged();
}
private class ViewHolder {
final TextView name, freq;
ViewHolder(View view){
name = (TextView) view.findViewById(R.id.text_item_1);
freq = (TextView) view.findViewById(R.id.text_item_2);
}
}
}
Code of MainActivity:
public class MainActivity extends AppCompatActivity {
EditText editText1;
ListView listView;
ListAdapter adapter;
List<Lf> elements = new ArrayList<>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
editText1 = (EditText) findViewById(R.id.edit_text);
listView = (ListView) findViewById(R.id.fragment_list);
// Working... Elements print on screen
for(int i = 0; i < 10; i++) {
Lf temp = new Lf();
temp.setLf("mean");
temp.setFreq(100);
elements.add(temp);
}
adapter = new ListAdapter(this, R.layout.list_item, elements);
listView.setAdapter(adapter);
}
public void activity_button(View view) {
adapter.updateItems(elements);
}
}
If I click on the button, the existing items on the screen are cleared instead of a new one added. But in debug I see that elements normally passed to ListAdapter.
The problem is that your adapter's lfs's field and your activity's elements field both refer to the same List instance. This happens because you pass elements to the ListAdapter constructor, and then simply assign this.lfs = lfs.
So let's look at what happens when you pass elements to updateItems()...
public void updateItems(List<Lf> lfs) {
this.lfs.clear(); // this.lfs and the input lfs are the same list, so this clears both
this.lfs.addAll(lfs); // input lfs is now empty, so addAll() does nothing
this.notifyDataSetChanged();
}
Probably the best thing to do is to create a copy of the list in your adapter's constructor.
this.lfs = new ArrayList<>(lfs);
Now your adapter and activity will reference different lists, so this.lfs.clear() won't accidentally clear out the very list you're passing to it.
I made an GridView to organize TextView and Edit views, like a table , programatically, using an CustomAdapter. In getView() override method i create the views, add it to a arrayList and let the abstraction do its job. The problem arises when i try to acess the views outside the adapter class, in this case, in OnCreate of the activity. I was trying to get the array through getItems() method which returns the arrayList of views. But it returns am empty array (i check with a log that prints 0). And i'm wondering why is that happening? maybe the getView() methods runs only after i try to get the array in onCreate, somehow the onCreate finishes before the adapter is fully ready?
and if that's the case, where/when should i get the views?
Here's my activity and adapter class:
public class MatrizMultiplicationActivity extends AppCompatActivity {
MatrizGridAdapter gridAdapter;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_matriz_mult);
GridView gridView = (GridView) findViewById(R.id.grid_view);
gridView.setNumColumns(5);
gridAdapter = new MatrizGridAdapter(this,5,5);
gridView.setAdapter(gridAdapter);
ArrayList<EditText> matrix = gridAdapter.getItems();
Log.d("mSize", String.valueOf(matrix.size()));
}
public class MatrizGridAdapter extends BaseAdapter {
Context ctx;
int rows;
int coluns;
int size;
ArrayList<EditText> views;
public MatrizGridAdapter(Context ctx, int rows, int coluns)
{
this.ctx = ctx;
this.rows= rows;
this.coluns = coluns;
this.size = rows*coluns;
this.views = new ArrayList<EditText>();
}
// .. some methods
public ArrayList<EditText> getItems()
{
return views;
}
#Override
public int getCount() {
return size;
}
#Override
public EditText getItem(int position) {
if((views.size()<position))
{
return views.get(position);
}
return null;
}
#SuppressLint("ResourceAsColor")
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if(convertView==null)
{
CardView cardview = new CardView(ctx);
//code for setting CardView attributes
//...
//..
//layout logic, doesn't really matter
if(position==0)
{
TextView textView = new TextView(ctx);
//code for setting textView attributes
cardview.addView(textView);
cardview.setBackgroundColor(R.color.cinzarrom);
}
//layout logic, doesn't really matter
//it is the first row, so put the numbers of coluns above
else if(position<coluns)
{
//code for setting textView attributes
//...
//..
cardview.addView(textView);
cardview.setBackgroundColor(R.color.cinzarrom);
setMarginLeft(textView, MyMath.convertDpToPixels(20,ctx));
}
//it is the first colun in any row, so put the number of rows on the left
else if(position%coluns==0)
{
//code for setting textView attributes
cardview.addView(textView);
cardview.setBackgroundColor(R.color.cinzarrom);
setMarginLeft(textView, MyMath.convertDpToPixels(20,ctx));
}
//ARE THE VIEWS BEING ADDED BEFORE THE CALL TO ARRAY.SIZE?()
else {
EditText editText = new EditText(ctx);
//add it to the array who stores the text views
views.add(editText);
//code for setting textView attributes
cardview.setBackgroundColor(Color.BLUE);
cardview.addView(editText);
}
return cardview;
}
return convertView;
}
}
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();
}
I apologize if this is similar to other threads, but I have yet to find a good solution on how to update the ListView in my custom ArrayAdapter.
I'm extending FragmentActivity in order to create a custom Dialog popup for adding / updating new List entries (which works fine), but I can't seem to get the ListView in ServerActivityArrayAdapter to update after a change is made.
Obviously, adapter.notifyDataSetChanged(); in the ServersActivity class isn't enough, but I'm stumped as to how to get my ListView to update after the Save button is clicked in the ServerDialog popup. Any help would be greatly appreciated!
public class ServersActivity extends FragmentActivity {
private List<Server> server;
private ListView lv;
private ServerActivityArrayAdapter adapter;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.server_list);
server = getServers();
lv = (ListView) findViewById(android.R.id.list);
adapter = new ServerActivityArrayAdapter(this, R.layout.server_list_item, server);
lv.setAdapter(adapter);
lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
showServerDialog(position);
}
});
}
...
private void showServerDialog(int position) {
android.support.v4.app.FragmentManager fragmentManager = getSupportFragmentManager();
ServerDialog serverDialog = new ServerDialog(position);
ServerDialog.newInstance();
serverDialog.show(fragmentManager, "server_dialog");
}
ServerDialog class for adding new List entries
public class ServerDialog extends DialogFragment {
...
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.settings_fragment, container);
context = getActivity().getApplicationContext();
dbh = new DbHandler(context);
etName = (EditText) view.findViewById(R.id.etName);
etAddress = (EditText) view.findViewById(R.id.etAddress);
etPort = (EditText) view.findViewById(R.id.etPort);
swtchNumDoors = (Switch) view.findViewById(R.id.swtchNumDoors);
Button btnSave = (Button) view.findViewById(R.id.btnSave);
loadData();
String title = (!newServer) ? "Edit Server" : "Add A New Server " + ID;
getDialog().setTitle(title);
btnSave.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
server[ID] = String.valueOf(ID);
server[SERVER_NAME] = etName.getText().toString();
server[ADDRESS] = etAddress.getText().toString();
server[PORT] = etPort.getText().toString();
if (server[ADDRESS].isEmpty() || server[PORT].isEmpty()) {
Toast.makeText(context, "Invalid Entry", Toast.LENGTH_LONG).show();
} else {
saveData();
// TODO - notify ServersActivity of change
}
}
});
return view;
}
public class ServerActivityArrayAdapter extends ArrayAdapter<Server> {
private int layout;
private String[][] values;
private int defServer;
private static LayoutInflater inflater;
ServerActivityArrayAdapter class for displaying ListView
public ServerActivityArrayAdapter(Context context, int layout, List<Server> servers) {
super(context, layout, servers);
this.layout = layout;
int i = 0;
values = new String[servers.size()][5];
for (Server server : servers) {
values[i][0] = Integer.toString(server.id);
values[i][1] = server.name;
values[i][2] = server.address;
values[i][3] = Integer.toString(server.port);
values[i][4] = Integer.toString(server.num_doors);
defServer = (server.default_server) ? i : 0;
i++;
}
inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
private static class ViewHolder {
private TextView tvServerName;
private CheckBox cbDefault;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
ViewHolder holder;
View v = convertView;
try {
if(v == null) {
v = inflater.inflate(layout, parent, false);
holder = new ViewHolder();
holder.tvServerName = (TextView) v.findViewById(R.id.tvServerName);
holder.cbDefault = (CheckBox) v.findViewById(R.id.cbDefault);
v.setTag(holder);
} else {
holder = (ViewHolder) v.getTag();
}
holder.tvServerName.setText(values[position][1]);
holder.cbDefault.setChecked(defServer==position);
} catch (Exception e){
System.out.println(e);
}
return v;
}
You could use an interface and have a method in it maybe named updateListView().
Implement this interface in your FragmentActivity. In the implemented method, add code to update the listView.
And in the button code of your dialog, call ((Interfacename) getActivity).updateListView()
Your problem is in the implementation of the adapter. You are instantiating the ArrayAdapter with a List<Server> object (The super call) but then creating your own two dimensional array values to contain the data. You use the values array for the getView() method yet make no mention or show through code how you actually modify that data to update the adapter.
You should be calling back into the adapter to update it. EG, calling add(), remove(), etc. You only mention updating the DB which has nothing to do with updating your adapter. It's not linked in anyway to the DB. Even if you were to call into the previously mentioned mutate methods on the adapter, they wouldn't work unless you specifically override them. The default ArrayAdapter implementation will modify the List<Server> data and not the values two-dim array you created.
But if you find yourself override those mutate methods to support your values two-dim array...there's no point in subclassing the ArrayAdapter. Part of the point of the ArrayAdapter is handling all the data management for you. In such a situation you should be instead subclassing BaseAdapter.
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) );