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() .
Related
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;
}
}
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
I used fragment in my app and i'm using SQLite to save local data. But when I finished saving data, and I swipe the page, my listView is not refreshed with new data (Only showing old data). I have tried to provide a method notifyDataSetChanged() on my adapter, but it's not working.
My Base Adapter class :
public class LocalDataAdapter extends BaseAdapter {
private Activity activity;
private ArrayList<LocalDataBean> data;
private static LayoutInflater inflater = null;
public LocalDataAdapter(Activity a, ArrayList<LocalDataBean> d) {
activity = a;
data = d;
inflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
#Override
public int getCount() {
return data.size();
}
#Override
public Object getItem(int position) {
return data.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
public void setItem(ArrayList<LocalDataBean> data){
this.data = data;
notifyDataSetChanged();
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = inflater.inflate(R.layout.list_item, null);
TextView nama_konsumen = (TextView) v.findViewById(R.id.nama_konsumen);
TextView no_telp = (TextView) v.findViewById(R.id.no_telp);
TextView no_hp_cdma = (TextView) v.findViewById(R.id.no_hp_cdma);
TextView no_hp_gsm = (TextView) v.findViewById(R.id.no_hp_gsm);
LocalDataBean obj = (LocalDataBean) getItem(position);
nama_konsumen.setText(obj.getNamaKonsumen());
no_telp.setText(obj.getNoTelp());
no_hp_cdma.setText(obj.getNoCMDA());
no_hp_gsm.setText(obj.getNoGSM());
return v;
}
}
My fragment class :
public class LocalDataFragment extends Fragment {
View view;
Activity act;
SQLHandlerBean utilSql;
ArrayList<LocalDataBean> localdatabean = new ArrayList<LocalDataBean>();
LocalDataAdapter adapter;
ListView list;
public static final String TAG = LocalDataFragment.class.getSimpleName();
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
view = inflater.inflate(R.layout.layout_local_data, null);
act = getActivity();
list = (ListView) view.findViewById(R.id.listViewLocalData);
utilSql = new SQLHandlerBean(this.act);
adapter = new LocalDataAdapter(act, localdatabean);
localdatabean = new ArrayList<LocalDataBean>();
list.setAdapter(adapter);
if (utilSql.ReadAllLocalData().size() < 1) {
Toast.makeText(act, "DATA EMPTY!", Toast.LENGTH_LONG).show();
} else {
localdatabean = utilSql.ReadAllLocalData();
Log.e(TAG, "TOTAL DATA : "+localdatabean.size());
adapter.setItem(localdatabean);
adapter.notifyDataSetChanged();
}
return view;
}
}
Is adapter.notifyDataSetChanged() placement correct?
No, the placement is not in the right place.
As you have placed the notifyDataSetChanged() inside of the onCreateView() method. It will be only invoked 1st time the fragment is launched.
Rather you can add a refresh button in your layout (or in you action bar). And along with the insertion/deletion method of the data, place the notifyDataSetChanged() at the bottom of the click event of that button.
By doing this user can refresh the page whenever they want.
And if you want to refresh the page by swipping the view then, SwipeRefreshLaoyout could be a perfect alternative.
You can check this blog.
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;
}
}
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