I am making a search engine for my Android app that involves a database. My current implementation is as follows:
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, R.layout.result_item, R.id.txtVerbName, verbs);
AutoCompleteTextView txtSearch = (AutoCompleteTextView) findViewById(R.id.txtSearch);
txtSearch.setAdapter(adapter);
However, you will notice I have put "txtVerbName" (which is a TextView) as the textview that gets its value changed with the array attached ("verbs"). How can I make this work so that I can attach a value to txtVerbName and then also attach a different value to another textview in the same layout?
Use a Custom Adapter to accomplish this:
public class AutoCompleteCursorAdapter extends CursorAdapter implements Filterable {
private TextView txtVerbName, txtVerbDefinition;
private Cursor mCursor;
private Context mContext;
private final LayoutInflater mInflater;
public AutoCompleteCursorAdapter(Context context, Cursor c) {
super(context, c, true);
mInflater = LayoutInflater.from(context);
mContext = context;
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
TextView txtVerbName = (TextView) view.findViewById(R.id.txtVerbName);
TextView txtVerbDefinition = (TextView) view.findViewById(R.id.txtVerbDefinition);
txtVerbName.setText(cursor.getString(1));
txtVerbDefinition.setText(cursor.getString(2));
}
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
final View view = mInflater.inflate(R.layout.result_item, parent, false);
return view;
}
#Override
public Cursor runQueryOnBackgroundThread(CharSequence constraint) {
// this is how you query for suggestions
if (getFilterQueryProvider() != null) {
return getFilterQueryProvider().runQuery(constraint);
}
if (constraint != null) {
DBAdapter db = new DBAdapter(mContext);
db.open();
mCursor = db.getVerbsContaining(constraint);
mCursor.moveToFirst();
db.close();
}
return mCursor;
}
}
Related
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;
}
I have a special class, a custom adapter for my ListView and I need to get some data from another Activity. But my implementation of the method GetIntent()GetExtras() isn't working. What is wrong?
Here is my custom adapter code:
public class CustomAdapter extends ArrayAdapter<String> {
int myColor,myWidth;
private final Context context;
private final String[] values;
public CustomAdapter(Context context, String[] values) {
super(context, R.layout.list_item, values);
this.context = context;
this.values = values;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// return super.getView(position, convertView, parent);
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View rowView = inflater.inflate(R.layout.list_item, parent, false);
TextView textView = (TextView) rowView.findViewById(R.id.ColorTextButton);
ImageView imageView = (ImageView) rowView.findViewById(R.id.imageViewIcon);
TextView textView1 = (TextView) rowView.findViewById(R.id.HelpButton);
textView.setText(values[position]);
String s = values[position];
System.out.println(s);
if (s.equals("Monday")) {
imageView.setImageResource(R.drawable.arrow2);
textView.setBackgroundColor(Color.YELLOW);
} else if (s.equals("Wednesday")) {
imageView.setImageResource(R.drawable.arrow2);
textView1.setBackgroundColor(Color.GREEN);
} else if (s.equals("Friday")) {
imageView.setImageResource(R.drawable.arrow2);
} else {
imageView.setImageResource(R.drawable.arrow);
}
return rowView;
}
}
If you want the data to be accessable From a few activities you should think about use a singleton data Class. so in stead of trying to get pass the data from your adapter to a second activity both the adaper and the Activity use the same method to get the data class
public class DataProvider {
private static DataProvider instance;
public static DataProvider getInstance()
{
if(null == instance){instance = new DataProvider();}
return instnace;
}
public String[] getObjects(){
return this.myStringArray;
}
// add more methods in here to retrieve and count your data as you need
}
then in your Activity you can
// somewhere
myStingArrayInMyActivity = DataProvider.getInstance().getObjects()
also in you adapter
you can do
public class CustomAdapter extends ArrayAdapter<String> {
int myColor,myWidth;
private final Context context;
private final String[] values;
public CustomAdapter(Context context, String[] values) {
super(context, R.layout.list_item, values);
this.context = context;
this.values = values;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// your code
textView.setText(DataProvider.getInstance.getObjects[position]);
String s = DataProvider.getInstance.getObjects[position];
/// your code
return rowView;
}
}
why in every example i see that extends the class ArrayAdapter it overrides the constructor that accepts T[] objects and references its own private variable to that and uses the referenced variable in the override of getView?
how can this be dynamic adding of objects?
will values be updated when a new item is added to the ArrayAdapter using add method?
can i instead of implementing my own adapter just use addheaderview in listview?
public class MySimpleArrayAdapter extends ArrayAdapter<String> {
private final Context context;
private final String[] values;
public MySimpleArrayAdapter(Context context, String[] values) {
super(context, R.layout.rowlayout, 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);
View rowView = inflater.inflate(R.layout.rowlayout, parent, false);
TextView textView = (TextView) rowView.findViewById(R.id.label);
ImageView imageView = (ImageView) rowView.findViewById(R.id.icon);
textView.setText(values[position]);
// change the icon for Windows and iPhone
String s = values[position];
if (s.startsWith("iPhone")) {
imageView.setImageResource(R.drawable.no);
} else {
imageView.setImageResource(R.drawable.ok);
}
return rowView;
}
}
I'm trying to fetch the data stored using a custom CursorAdapter, but so far it is failing silently. It just loads a blank view and doesn't print anything.
Here is the onCreateView for the main fragment:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
View view = inflater.inflate(R.layout.network_listview, container, false);
mListView = (ListView)view.findViewById(R.id.network_listview);
aToken = getSherlockActivity().getIntent().getStringExtra("token");
aTokenSecret = getSherlockActivity().getIntent().getStringExtra("token_secret");
context = getSherlockActivity().getBaseContext();
ConfigurationBuilder builder = new ConfigurationBuilder();
builder.setOAuthConsumerKey(Const.CONSUMER_KEY);
builder.setOAuthConsumerSecret(Const.CONSUMER_SECRET);
builder.setOAuthAccessToken(aToken);
builder.setOAuthAccessTokenSecret((aTokenSecret));
Configuration configuration = builder.build();
mTwitter = new TwitterFactory(configuration).getInstance();
mListAdapter = getListAdapter();
mListView.setAdapter(mListAdapter);
updateList();
return view;
}
getListAdapter():
CursorAdapter getListAdapter() {
CursorAdapter ad = new TweetAdapter(getSherlockActivity(), null);
return ad;
}
TweetAdapter:
public class TweetAdapter extends CursorAdapter
{
private ImageLoader imageLoader;
private static class ViewHolder
{
private ImageView profileView;
private TextView updated;
private ImageView favoriteIcon;
private TextView name;
private TextView message;
private TextView retweeted_by;
private ViewHolder(View row)
{
profileView = (ImageView)row.findViewById(R.id.preview);
updated = (TextView)row.findViewById(R.id.updated);
favoriteIcon = (ImageView)row.findViewById(R.id.favorite_icon);
name = (TextView)row.findViewById(R.id.name);
message = (TextView)row.findViewById(R.id.message);
retweeted_by = (TextView)row.findViewById(R.id.retweeted_by);
}
}
public TweetAdapter(Context context, Cursor c){
super(context, c, true);
}
#Override
public void bindView(View row, Context context, Cursor cursor)
{
// this doesnt print out anything, even though there is data in the database
String tweetText = cursor.getString(cursor.getColumnIndex(Tweets.COL_TEXT_PLAIN));
System.out.println("Tweet Text: " + tweetText);
}
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent)
{
LayoutInflater inflater = (LayoutInflater) parent.getContext()
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View row = inflater.inflate(R.layout.item_tweet, parent, false);
ViewHolder viewHolder = new ViewHolder(row);
row.setTag(viewHolder);
return row;
}
}
updateList():
void updateList()
{
mCursor = getCursor();
Cursor oldCursor = mListAdapter.swapCursor(mCursor);
mListAdapter.notifyDataSetChanged();
if (oldCursor != null) {
oldCursor.close();
}
}
You pass a null Cursor when constructing the TweetAdapter instance, so your adapter starts out with no data. Then updateList() replaces the adapter's null Cursor with whatever is in mCursor (which you do not show in the code you provided).
If mCursor is also null, then your code will end up either displaying no content (which is what you are seeing) or throwing an uncaught exception.
So, make sure you actually do a query that fills in the mCursor variable before calling updateList() .
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