I apologize in advance if this is a duplicate. I am still new to android development and tried looking for a resolution however could not find one that works.
I am creating a to-do app and getting this error in my adapter.
java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String assignment.Model.getAssignment()' on a null object reference
at assignment.Adapter.getView(Adapter.java:39)
and the line of code that it is referencing to is
assignment.setText(modelItems[position].getAssignment());
I believe that the position that I am setting it as is what is causing the error but I'm not sure how to fix it.
Here's part of the rest of my code for reference:
MainActivity.Java - onActivityResult
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
String assignmentSentBack = data.getStringExtra("editAssignment");
Integer monthSentBack = data.getIntExtra("month", 0);
Integer daySentBack = data.getIntExtra("day", 0);
modelItems = new Model[100];
ArrayList<Model> modelArrayList = new ArrayList<>(Arrays.asList(modelItems));
modelArrayList.add(new Model(assignmentSentBack, (monthSentBack + 1) + "/" + daySentBack, 0));
lv = (ListView) findViewById(R.id.listAssignment);
ListAdapter adapter = new Adapter(this, modelItems);
lv.setAdapter(adapter);
}
Second Activity - onSendActivity (Button)
public void onSendAssignment (View view) {
EditText editAssignmentET = (EditText)
findViewById(R.id.editAssignment);
String editAssignment = String.valueOf(editAssignmentET.getText());
DatePicker datePickerDP = (DatePicker)
findViewById (R.id.datePicker);
Integer month = Integer.valueOf(datePickerDP.getMonth());
Integer day = Integer.valueOf(datePickerDP.getDayOfMonth());
Intent goingBack = new Intent();
goingBack.putExtra("editAssignment", editAssignment);
goingBack.putExtra ("month", month);
goingBack.putExtra("day", day);
setResult(RESULT_OK, goingBack);
finish();
}
Adapter
public class Adapter extends ArrayAdapter {
Model[] modelItems = null;
Context context;
public Adapter(Context context, Model[] resource) {
super(context, R.layout.row, resource);
this.context = context;
this.modelItems = resource;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = ((Activity) context).getLayoutInflater();
convertView = inflater.inflate(R.layout.row, parent, false);
TextView assignment = (TextView) convertView.findViewById(R.id.assignment);
TextView dueDate = (TextView) convertView.findViewById(R.id.dueDate);
CheckBox cb = (CheckBox) convertView.findViewById(R.id.checkBox);
assignment.setText(modelItems[position].getAssignment());
dueDate.setText(modelItems[position].getDueDate());
if (modelItems[position].getValue() == 1)
cb.setChecked(true);
else
cb.setChecked(false);
return convertView;
}
}
Model
public class Model {
String assignment;
String dueDate;
int value;
Model (String assignment, String dueDate, int value){
this.assignment = assignment;
this.dueDate = dueDate;
this.value = value;
}
public String getAssignment(){
return this.assignment;
}
public String getDueDate(){
return this.dueDate;
}
public int getValue(){
return this.value;
}
}
Any help is appreciated. Thank you.
you should try to wrap it in an inner Holder class and define the parameters in that class
public class Adapter extends ArrayAdapter {
Model[] modelItems = null;
Context context;
public Adapter(Context context, Model[] resource) {
super(context, R.layout.row, resource);
this.context = context;
this.modelItems = resource;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = ((Activity) context).getLayoutInflater();
if (convertView == null) {
holder = new ViewHolder();
convertView = vi.inflate(R.layout.list_layout, null);
// Find the child views.
holder.assignment= (TextView) convertView.findViewById(R.id.txt_name);
holder.dueDate= (Button) convertView.findViewById(R.id.btn_invite);
holder.cb= (Button) convertView.findViewById(R.id.btn_track);
convertView.setTag(holder);
//....
}
// Reuse existing row view
else {
holder = (ViewHolder)convertView.getTag();
}
return convertView;
}
class ViewHolder {
TextView assignment;
TextView dueDate;
CheckBox cb;
}
}
change
public class Adapter extends ArrayAdapter {
to
public class Adapter extends ArrayAdapter<Model> {
You have created model array of size 100 here:
modelItems = new Model[100];
So, 100 models are being created but all 100 indexes have null value.
Then you have created ArrayList using that array:
ArrayList<Model> modelArrayList = new ArrayList<>(Arrays.asList(modelItems));
So again your modelArrayList has 100 null objects. Which BTW you are using no where.
You are passing modelItems into constructor of Adapter. So now since all you items are null, you are getting this exception.
Try to do something like this:
ArrayList<Model> modelArrayList = new ArrayList<>();
modelArrayList.add(new Model(assignmentSentBack, (monthSentBack + 1) + "/" + daySentBack, 0));
Similarly add more model objects like that.
Pass this modelArrayList in your adapter's constructor and use this (instead of array) to display the list.
lv = (ListView) findViewById(R.id.listAssignment);
ListAdapter adapter = new Adapter(this, modelArrayList)
And thus your adapter will be like this:
ArrayList<Model> modelArrayList;
Context context;
public Adapter(Context context, ArrayList<Model> resource) {
super(context, R.layout.row, resource);
this.context = context;
this.modelArrayList = resource;
}
Related
I am creating a playlist with 2 lines of name and genre, how to I can delete it.
This is MainActivity :
String[] gene, sl;
...
adp = new Adapter(MainActivity.this, gene, sl);
lv.setAdapter(adp);
This is Adapter
public class Adapter extends ArrayAdapter<String> {
private final Activity context;
private final String[] gene;
private final String[] sl;
SharedPreferences preferences;
public Adapter(Activity context, String[] gene ,String[] sl) {
super(context, R.layout.activity_m , gene);
this.context = context;
this.gene = gene;
this.sl = sl;
}
private class ViewHolder{
TextView txtgene, txtsl;
}
#Override
public View getView(final int position, View view, ViewGroup parent) {
ViewHolder holder;
if (view == null) {
LayoutInflater inflater = context.getLayoutInflater();
view = inflater.inflate(R.layout.activity_m, null, true);
holder = new ViewHolder();
holder.txtgene = (TextView) view.findViewById(R.id.txtgene);
holder.txtsl = (TextView) view.findViewById(R.id.txtsl);
view.setTag(holder);
}else{
holder = (ViewHolder) view.getTag();
}
if (gene[position] != null) {
holder.txtgene.setText(gene[position]);
}
holder.txtsl.setText(sl[position]);
return view;
}
}
How to remove an item when you know its exact position ?
Thank !
You are using the ArrayAdapter constructor that takes an array. This in turn will create an immutable List internal to the ArrayAdapter. So, you will not be able to modify your adapter going this route.
Instead, make a new ArrayList from your array and call the ArrayAdapter constructor that takes a List.
So, change the super call in your Adapter constructor to this:
super(context, R.layout.activity_m, new ArrayList<>(Arrays.asList(gene)));
And then, when you want to remove an item given it's position, do this:
adp.remove(getItem(position));
PS: You should consider refactoring your gene and sl arrays into a class and then use it as the type of your List.
I'm creating a To-do list application and I have a question regarding to using checkboxes and its listeners in List Adapter. My single row in listview contains three TextViews and one Checkbox. I want to change background of single row when user "check" the checkbox. I have read that i should put checkbox listener in my adapter class and so I did it. Now is the problem - when i add few rows to my listview and left the checkbox unchecked for all of them all works fine, but when I add a row, check the checkbox and try to add another one I get error
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.view.View.setBackgroundColor(int)' on a null object reference
Below is code of my adapter. Thank you for any advice. I'm just starting with Android programming so thank you for understanding in advance.
public class ToDoAdapter extends ArrayAdapter<ToDoTask> {
ArrayList<ToDoTask> objects;
Context context;
int resource;
public ToDoAdapter(#NonNull Context context, #LayoutRes int resource, #NonNull ArrayList<ToDoTask> objects) {
super(context, resource, objects);
this.objects = objects;
this.context = context;
this.resource = resource;
}
#Override
public View getView(final int position, View convertView, final ViewGroup parent) {
View view = convertView;
ToDoHolder toDoHolder = null;
if (view == null) {
LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = layoutInflater.inflate(R.layout.row, parent, false);
toDoHolder = new ToDoHolder();
toDoHolder.rowTitle = (TextView) view.findViewById(R.id.rowTitle);
toDoHolder.rowDesc = (TextView) view.findViewById(R.id.rowDesc);
toDoHolder.rowDate = (TextView) view.findViewById(R.id.rowDate);
toDoHolder.rowIsDone = (CheckBox) view.findViewById(R.id.rowCheckBoxDone);
toDoHolder.rowIsDone.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
if(checked){
parent.getChildAt(position).setBackgroundColor(Color.parseColor("#8FE370"));
}
else
parent.getChildAt(position).setBackgroundColor(Color.WHITE);
}
});
view.setTag(toDoHolder);
} else {
toDoHolder = (ToDoHolder) view.getTag();
}
ToDoTask object = objects.get(position);
toDoHolder.rowTitle.setText(object.getTitle());
toDoHolder.rowDesc.setText(object.getDescription());
toDoHolder.rowDate.setText(object.getDate());
toDoHolder.rowIsDone.setChecked(object.getDone());
return view;
}
static class ToDoHolder {
TextView rowTitle;
TextView rowDesc;
TextView rowDate;
CheckBox rowIsDone;
}
}
Below is my MainActivity class which get details of single row element from "AddToDoTask" class.
public class MainActivity extends AppCompatActivity {
private final int requestCode = 1;
ArrayList<ToDoTask> lista = new ArrayList<>();
ToDoAdapter adapter = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button = (Button) findViewById(R.id.buttonAdd);
ListView listView = (ListView) findViewById(R.id.listView);
adapter = new ToDoAdapter(this, R.layout.row, lista);
listView.setAdapter(adapter);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent = new Intent(getApplicationContext(), AddToDoTask.class);
startActivityForResult(intent, requestCode);
}
});
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
String title, description, date;
Boolean isDone;
if (requestCode == 1) {
if (null != data) {
title = data.getStringExtra("title");
description = data.getStringExtra("description");
date = data.getStringExtra("date");
isDone = data.getBooleanExtra("done", false);
lista.add(new ToDoTask(title, description, date, isDone));
adapter.notifyDataSetChanged();
}
}
}
}
public class ToDoAdapter extends ArrayAdapter<ToDoTask> {
private ArrayList<ToDoTask> objects;
private Context context;
private int resource;
private SparseBooleanArray checkedPositions = new SparseBooleanArray();
public ToDoAdapter(#NonNull Context context, #LayoutRes int resource, #NonNull ArrayList<ToDoTask> objects) {
super(context, resource, objects);
this.objects = objects;
this.context = context;
this.resource = resource;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ToDoHolder toDoHolder;
if (convertView == null) {
LayoutInflater layoutInflater = LayoutInflater.from(context);
convertView = layoutInflater.inflate(R.layout.row, parent, false);
toDoHolder = new ToDoHolder();
toDoHolder.rowTitle = (TextView) convertView.findViewById(R.id.rowTitle);
toDoHolder.rowDesc = (TextView) convertView.findViewById(R.id.rowDesc);
toDoHolder.rowDate = (TextView) convertView.findViewById(R.id.rowDate);
toDoHolder.rowIsDone = (CheckBox) convertView.findViewById(R.id.rowCheckBoxDone);
convertView.setTag(toDoHolder);
} else {
toDoHolder = (ToDoHolder) convertView.getTag();
}
toDoHolder.rowTitle.setTag(position);
toDoHolder.rowIsDone.setTag(convertView);
toDoHolder.rowIsDone.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
View view = (View) compoundButton.getTag();
TextView title = (TextView) view.findViewById(R.id.rowTitle);
int pos = (int) title.getTag();
if (checked) {
checkedPositions.put(pos, true);
view.setBackgroundColor(Color.parseColor("#8FE370"));
} else {
checkedPositions.put(pos, false);
view.setBackgroundColor(Color.WHITE);
}
}
});
ToDoTask object = objects.get(position);
toDoHolder.rowTitle.setText(object.getTitle());
toDoHolder.rowDesc.setText(object.getDescription());
toDoHolder.rowDate.setText(object.getDate());
toDoHolder.rowIsDone.setChecked(object.getDone() || checkedPositions.get(position));
return convertView;
}
private class ToDoHolder {
private TextView rowTitle;
private TextView rowDesc;
private TextView rowDate;
private CheckBox rowIsDone;
}
}
You must add a layout in your row xml file and put layout in toDoHolder and just change the layouts background color. You can access child views like
layout.findViewByID(int ID);
I am trying to use custom font in my ListView adapter, but I am doing something wrongly.
I tried to use getAssets and getContext, but I can't use them in my app.
I hope that maybe someone can help me find the solution.
Adapter code in Java, as shown below:
public class ListviewAdapter extends BaseAdapter {
private LayoutInflater mLayoutInflater;
private ArrayList<Cwiczenie> listaCwiczen;
public ListviewAdapter(Context context, ArrayList<Cwiczenie> data) {
mLayoutInflater = LayoutInflater.from(context);
listaCwiczen = data;
}
#Override
public int getCount() {
return listaCwiczen == null ? 0 : listaCwiczen.size();
}
#Override
public Cwiczenie getItem(int position) {
return listaCwiczen.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View view, ViewGroup parent) {
View vi = view;
ViewHolder holder = null;
if (vi == null) {
vi = mLayoutInflater.inflate(R.layout.wierszlisty, parent, false);
holder = new ViewHolder();
holder.tvName = (TextView) vi.findViewById(R.id.nazwa_cwiczenia);
// holder.tvDescription = (TextView)
// vi.findViewById(R.id.textView_item_description);
vi.setTag(holder);
} else {
holder = (ViewHolder) vi.getTag();
}
Cwiczenie cwiczenie = getItem(position);
holder.tvName.setText(cwiczenie.getNazwa());
// holder.tvDescription.setText(item.getDescription());
return vi;
}
static class ViewHolder {
TextView tvName;
// TextView tvDescription;
}
}
holder.tvName = (TextView) vi.findViewById(R.id.nazwa_cwiczenia);
below this use this code:
Typeface tf = Typeface.createFromAsset(vi.getContext().getAssets(), "font/chiller.ttf");
holder.tvName.setTypeface(tf);
create a "font" folder inside assets folder and place your font file there. Instead of "chiller.ttf" write your font file name.
This code worked for me. I hope it will work for you too.
keep a reference to Typeface, as member variable, and initialize it in the constructor of your adapter:
Typeface tf;
public ListviewAdapter(Context context, ArrayList<Cwiczenie> data) {
tf = Typeface.createFromAsset(context.getAssets(),"fonts/yourfonts.ttf");
// other code
}
in getView() when you instantiate your row, assign the font
if (vi == null) {
vi = mLayoutInflater.inflate(R.layout.wierszlisty, parent, false);
holder = new ViewHolder();
holder.tvName = (TextView) vi.findViewById(R.id.nazwa_cwiczenia);
holder.tvName.setTypeface(tf ,1);
// holder.tvDescription = (TextView) vi.findViewById(R.id.textView_item_description);
vi.setTag(holder);
}
Since you pass in the context when calling the ListView constructor,
public ListviewAdapter(Context context, ArrayList<Cwiczenie> data) {
mLayoutInflater = LayoutInflater.from(context);
listaCwiczen = data;
}
Save the context into a variable? i.e.
// Allows you to use the context afterwards
private Context context = null;
public ListviewAdapter(Context context, ArrayList<Cwiczenie> data) {
this.context = context;
mLayoutInflater = LayoutInflater.from(context);
listaCwiczen = data;
}
And you can use it to get your assets.
Well, when you call "getContext()" ,it won't get the context of the activity you are in ,therefor, it won't work.What you want, is to get the context sent via the constructor and use it.
So, declare a context:
Private Context context;
Than ,in your constructor, go for this:
this.context = context;
This will practically get the context sent via the constructor and set it to your local variable.
Now you can use it like this:
context.getAssets()...//and so on
Right now I use setAdapter to update my ListView, but I think the proper way is to use notifiyDatasetChanged() and I can't get that to work in my main class (it's in the adapter). Here is the error:
The method notifyDatasetChanged() is undefined for the type ListAdapter
I'm guessing there is a better way of doing this - can anyone point me in the right direction?
Here's the relevant parts of my code:
public class ScoreList extends SherlockFragmentActivity {
private ListView listViewScore;
static List<Score> listScore = new ArrayList<Score>();
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.score_list);
ctx = this;
listScore = dbh.getAllScores();
listViewScore = (ListView) findViewById(R.id.score_list);
listViewScore.setAdapter(new ScoreListAdapter(ctx,
R.layout.score_row_item, listScore));
listViewScore.getAdapter().notifyDatasetChanged(); //this is where I get the error
}
}
Here's the adapter:
public class ScoreListAdapter extends ArrayAdapter<Score> {
private int resource;
private LayoutInflater inflater;
public ScoreListAdapter(Context ctx, int resourceId, List<Score> objects) {
super(ctx, resourceId, objects);
resource = resourceId;
inflater = LayoutInflater.from(ctx);
//context = ctx;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
convertView = (LinearLayout) inflater.inflate(resource, null);
Score score = getItem(position);
TextView txtName = (TextView) convertView.findViewById(R.id.name);
txtName.setText(score.getName());
TextView txtScoreChange = (TextView) convertView
.findViewById(R.id.scoreChange);
int scoreChange = Integer.parseInt(score.getScoreChange());
if (scoreChange > 0)
txtScoreChange.setText("+" + scoreChange);
else if (scoreChange < 0)
txtScoreChange.setText("" + scoreChange);
else
txtScoreChange.setText("");
TextView txtScoreTotal = (TextView) convertView
.findViewById(R.id.scoreTotal);
txtScoreTotal.setText(score.getScoreTotal());
final LinearLayout currentRow = (LinearLayout) convertView
.findViewById(R.id.scoreRowLayout);
notifyDataSetChanged();
return convertView;
}
}
Create an instance of your custom adapter, so you can use it anywhere you like...
public class ScoreList extends SherlockFragmentActivity {
private ListView listViewScore;
private ScoreListAdapter adapter;
static List<Score> listScore = new ArrayList<Score>();
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.score_list);
ctx = this;
listScore = dbh.getAllScores();
listViewScore = (ListView) findViewById(R.id.score_list);
adapter = new ScoreListAdapter(ctx, R.layout.score_row_item, listScore);
listViewScore.setAdapter(adapter);
adapter.notifyDatasetChanged();
}
}
By the way, if your listScore array is already loaded, then you do not need to use
adapter.notifyDatasetChanged();
Dont call the notifyDataSetChanged(); method while creation.
only call it when content of your listViewScore changes.. and to use it at that time-
replace
listView.getAdapter().notifyDatasetChanged();
with
((ScoreListAdapter)listView.getAdapter()).notifyDataSetChanged();
and see the magic...
thanks.
Working on figuring out my NullPointerException within my custom simplecursoradapter when trying to refresh the data in my view. When using SimpleCursorAdapter you cannot use NotifyDataSetChanged() so I need to create a new adapter and I am having difficulty passing on the data required.
public class DxSimpleCursorAdapter extends SimpleCursorAdapter {
Context context;
Activity activity;
DxDbAdapter dbh;
DxSimpleCursorAdapter adapter;
ListView lv;
protected String subcategory;
public DxSimpleCursorAdapter(Context context, int layout, Cursor c, String[] from, int[] to, String param) {
super(context, layout, c, from, to);
this.context=context;
this.activity=(Activity) context;
subcategory = param;
}
public DxSimpleCursorAdapter(Context context, int layout, Cursor c, String[] from, int[] to) {
super(context, layout, c, from, to);
this.context=context;
this.activity=(Activity) context;
}
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
LayoutInflater inflater = LayoutInflater.from(context);
View row = inflater.inflate(R.layout.list_detail, null);
ViewHolder holder = new ViewHolder();
holder.image = (ImageView) row.findViewById(R.id.fav);
holder.diagnosis = (TextView) row.findViewById(R.id.diagnosis);
holder.code = (TextView) row.findViewById(R.id.code);
row.setTag(holder);
return row;
}
class ViewHolder {
ImageView image;
TextView diagnosis;
TextView code;
}
class Status {
int status;
Long id;
}
#Override
public void bindView(View v, Context con, Cursor cursor) {
ViewHolder holder = (ViewHolder) v.getTag();
int favstatus = cursor.getInt(cursor.getColumnIndex(DxDbAdapter.FAV));
Status state = new Status();
if (favstatus == 1) {
holder.image.setImageResource(R.drawable.btn_star_on_normal);
state.status = 1;
}
else if (favstatus == 0) {
holder.image.setImageResource(R.drawable.btn_star_off_normal);
state.status = 0;
}
long id = cursor.getLong(cursor.getColumnIndex(DxDbAdapter.DIAG_ID));
state.id = id;
holder.image.setTag(state);
holder.diagnosis.setText(cursor.getString(cursor.getColumnIndex(DxDbAdapter.DIAG)));
holder.code.setText(cursor.getString(cursor.getColumnIndex(DxDbAdapter.DIAG_CODE)));
holder.image.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Status current_state = (Status) v.getTag();
ImageView fav = (ImageView) v.findViewById(R.id.fav);
fav.setImageResource(R.drawable.ic_fav);
if (current_state.status == 1) {
Toast toast = Toast.makeText(context,"Update fav status to 1",Toast.LENGTH_SHORT);
toast.show();
}
else if (current_state.status == 0) {
Toast toast = Toast.makeText(context,"Update fav status to 0",Toast.LENGTH_SHORT);
toast.show();
}
dbh = new DxDbAdapter(context);
dbh.open();
Cursor newCursor = dbh.fetch(1, subcategory);
String[] columns = new String[] {"diagnosis", "diagcode"};
int[] to = new int[] {R.id.diagnosis, R.id.code};
adapter = new DxSimpleCursorAdapter(context, R.layout.list_detail, newCursor, columns, to);
lv.setAdapter(adapter);
}
});
String diag = cursor.getString(cursor.getColumnIndex(DxDbAdapter.DIAG));
String code = cursor.getString(cursor.getColumnIndex(DxDbAdapter.DIAG_CODE));
holder.diagnosis.setText(diag);
holder.code.setText(code);
}
The issue is with subcategory = getIntent().getStringExtra("SUBCATEGORY"); and Cursor newCursor = dbh.fetch(1, subcategory); and that I have to reference the Activity that is using the adapter. I guess I am having issues on the correct syntax to reference the Activity so that I don't get a NullPointerException.
You should really pass in the subcategory from your parent activity since this value will not change while using your adapter (instead of retrieving it every single time you bind to a row)
Ex: from the parent activity you would do something like
String subcategory = getIntent().getStringExtra("SUBCATEGORY");
DxSimpleCursorAdapter adapter = DxSimpleCursorAdapter(context, layout, c, from, to, subcategory);
listView.setAdapter(adapter);
Then obviously you would need to modify the constructor of your adapter so it took that string and then assigned it to your subcategory variable within the adapter