I know that question is stupid, but I need to create Spinner using Realm and get one column for this.
All I want is get one all columt to String array to use ArrayAdapter. How can I get this column? Or maybe the better way is extend ArrayAdapter where I will get all rows from that column using a loop? Tell me, please, the better solution.
There are special Adapters for Realm:
Documentation: https://realm.io/docs/java/latest/#adapters
Project-Page: https://github.com/realm/realm-android-adapters
Example-Code: https://github.com/realm/realm-android-adapters/blob/master/example/src/main/java/io/realm/examples/adapters/ui/listview/MyListAdapter.java
Example code:
public class MyListAdapter extends RealmBaseAdapter<TimeStamp> implements ListAdapter {
private static class ViewHolder {
TextView timestamp;
}
public MyListAdapter(OrderedRealmCollection<TimeStamp> realmResults) {
super(realmResults);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder;
if (convertView == null) {
convertView = LayoutInflater.from(parent.getContext())
.inflate(android.R.layout.simple_list_item_1, parent, false);
viewHolder = new ViewHolder();
viewHolder.timestamp = (TextView) convertView.findViewById(android.R.id.text1);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
TimeStamp item = adapterData.get(position);
viewHolder.timestamp.setText(item.getTimeStamp());
return convertView;
}
}
If you truly want to reinvent the wheel, then you should avoid ArrayAdapter in the first place. After all, it handles the actual binding between your elements and your views, which means you learn less!
So if you want to learn, you should create a BaseAdapter. With this, we'll recreate the RealmBaseAdapter.
Okay, so how it works is that you can extend BaseAdapter which expects the following methods:
public class MyAdapter extends BaseAdapter {
#Override
public int getCount() {
// return count;
}
#Override
public Object getItem(int position) {
// return item at position;
}
#Override
public long getItemId(int position) {
// return unique identifier at position index
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// implement view holder pattern
// bind view holder with data at position
// return bound view
}
}
And a RealmBaseAdapter also gives you a RealmChangeListener that is appended to a RealmResults that you provide on creation.
So your case would look like this
public class YourAdapter extends BaseAdapter {
RealmResults<YourObject> results;
final RealmChangeListener realmChangeListener = new RealmChangeListener() {
#Override
public void onChange(Object element) {
notifyDataSetChanged();
}
};
public YourAdapter(RealmResults<YourObject> results) {
this.results = results;
results.addChangeListener(realmChangeListener);
}
public void updateData(RealmResults<YourObject> results) {
if(this.results.isValid()) {
this.results.removeChangeListener(realmChangeListener);
}
this.results = results;
results.addChangeListener(realmChangeListener);
}
#Override
public int getCount() {
// return count;
if(results == null || !results.isValid()) {
return 0;
}
return results.size();
}
#Override
public YourObject getItem(int position) {
// return item at position;
return results.get(i);
}
#Override
public long getItemId(int position) {
// return unique identifier at position index
return position; // this is sufficient
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// implement view holder pattern
ViewHolder viewHolder;
if (convertView == null) {
convertView = LayoutInflater.from(parent.getContext())
.inflate(android.R.layout.simple_list_item_1, parent, false);
viewHolder = new ViewHolder(convertView);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
// bind view holder with data at position
YourObject item = results.get(position);
viewHolder.textView.setText(item.getNeededColumn());
// return bound view
return convertView;
}
private static class ViewHolder {
TextView textView;
public ViewHolder(View view) {
textView = (TextView)view.findViewById(android.R.id.text1);
}
}
}
And then you can do this:
YourAdapter yourAdapter = new YourAdapter(realm.where(YourObject.class).findAll());
listView.setAdapter(yourAdapter);
Although I kinda prefer RecyclerViews lately, but that's ok
Related
I have a list view that populates with information using a custom adapter, displaying a tree like structure. However, the 'Parent' level comments always repeat themselves. This is the code for my custom adapter:
class CommentListAdapter extends BaseAdapter {
private LayoutInflater layoutInflater;
public CommentListAdapter(CommentActivity commentActivity){
layoutInflater = (LayoutInflater) commentActivity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
#Override
public int getCount() {
return commentFeed.getCommentCount();
}
#Override
public Object getItem(int position) {
return position;
}
#Override
public long getItemId(int position) {
return position;
}
class listViewHolder {
RelativeLayout spacerRelLayout;
TextView authorText;
TextView bodyText;
TextView timeText;
listViewHolder(View v) {
spacerRelLayout = (RelativeLayout) v.findViewById(R.id.spacerLayout);
authorText = (TextView) v.findViewById(R.id.authorTextComment);
bodyText = (TextView) v.findViewById(R.id.commentTextView);
timeText = (TextView) v.findViewById(R.id.timeTextComment);
}
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View listItem = convertView;
listViewHolder holder;
if (listItem == null) {
listItem = layoutInflater.inflate(R.layout.comment_item_layout, parent, false);
holder = new listViewHolder(listItem);
listItem.setTag(holder);
} else {
holder = (listViewHolder) listItem.getTag();
}
holder.bodyText.setText(Html.fromHtml(commentFeed.getComment(position).getBody()));
holder.timeText.setText(commentFeed.getComment(position).getTime());
holder.authorText.setText(commentFeed.getComment(position).getAuthor());
holder.spacerRelLayout.getLayoutParams().width = commentFeed.getComment(position).getLevel() *10;
holder.spacerRelLayout.invalidate();
return listItem;
}
}
How can this be fixed?
getItem should look like this:
#Override
public Object getItem(int position) {
return commentFeed.getComment(position);
}
Then inside your getView you do this:
Comment comment = (Comment) getItem(position);
holder.bodyText.setText(Html.fromHtml(comment.getBody()));
// etc..
I want to know about how to delete child view at some position in list view and added the same at the top of the list. I tried using the following methods butit will generate the unsupported exception. How do that please can anybody help me.
lvAddedContacts.removeViewAt(AddUserView,nAddUserPosition );//Here i want to remove this view from the list
lvAddedContacts.addView(AddUserView, 0); //Add the same at the top
lvAddedContacts.invalidate();//list is refreshed
contactsAdapter.notifyDataSetChanged();
private class ContactsListViewAdapter extends BaseAdapter
{
private LayoutInflater mInflater;
public ContactsListViewAdapter(Context context) {
// Cache the LayoutInflate to avoid asking for a new one each time.
mInflater = LayoutInflater.from(context);
}
public int getCount()
{
int nListSize = DH_Constant.AddedContactsList_obj.response.size();
if(nListSize > 0)
{
return nListSize;
}
else
{
return 0;
}
}
public Object getItem(int position)
{
return position;
}
public long getItemId(int position) {
return position;
}
public View getView(final int position, View convertView, final ViewGroup parent)
{
ViewHolder holder;
convertView = mInflater.inflate(R.layout.added_contacts_list, null);
holder = new ViewHolder();
//getting the id's
holder.tvName = (TextView) convertView.findViewById(R.id.xrays_Name_tv);
holder.btnRemove = (Button) convertView.findViewById(R.id.xrays_removebtn);
//Name
String strName = DH_Constant.AddedContactsList_obj.response.get(position).Name;
holder.tvName.setText(strName);
//Change the color for differentiate the dicom and non dicom users
if(DH_Constant.AddedContactsList_obj.response.get(position).IsDicomUser)
{
holder.tvName.setTextColor(Color.rgb(0, 135, 137));
}
else
{
holder.tvName.setTextColor(Color.BLUE);
}
//Remove button Listener
holder.btnRemove.setBackgroundResource(R.layout.xrays_contact_removebtn_widget);
holder.btnRemove.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v)
{
lnIcontactId = DH_Constant.AddedContactsList_obj.response.get(position).ImportedContactsID;
nDicomUser = DH_Constant.AddedContactsList_obj.response.get(position).IsDicomUser?1:0;
//Alert for remove the contact
showDialog(DIALOG_removebtnalert);
}
});
//Copy the view and position if the user is added
if(DH_Constant.blnAddUserStatus)
{
System.out.println("IContactID(xrays):"+DH_Constant.lnAddUserID);
if(DH_Constant.AddedContactsList_obj.response.get(position).ImportedContactsID == DH_Constant.lnAddUserID)
{
nAddUserPosition = position;
AddUserView = convertView;
}
}
return convertView;
}
class ViewHolder
{
TextView tvName;
Button btnRemove;
}
}
Don't remove Views backed by an Adapter yourself, as it may result in weired behavior!! Your Implementation of BaseAdapter looks strange to me, too. Ie:
public Object getItem(int position)
{
return position;
}
public long getItemId(int position) {
return position;
}
doesn't seem to make any Sense!
You should use an ArrayAdapter passing a Model to it and just implement getView(int, View, ViewGroup) accordingly. If you then want to move an Item inside on Top, all you have to do is just:
ArrayAdapter adapter = //initialize with your Model Objects and set it as ListAdapter
Object someItemInsideList = //some Item
adapter.remove(someItemInsideList);
adapter.insert(someItemInsideList, 0);
adapter.notifyDataSetChanged();
I want to build a dynamic ListView (like a chat list with different layouts/bubbles).
My problem is, that each row has an individual height. My code below works,
but every time I scroll down or receive a new message,
the row with a different height gets heigher.
private class dialogAdapter extends BaseAdapter {
private LayoutInflater mInflater;
public dialogAdapter(Context context) {
mInflater = LayoutInflater.from(context);
}
#Override
public boolean hasStableIds() {
return true;
}
public int getCount() {
return dialog.size();
}
public int getViewTypeCount() {
return 999999;
}
public Object getItem(int position) {
return dialog.get(position);
}
public int getItemViewType(int position) {
return position;
}
public String getType(int position) {
return dialogType.get(position);
}
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
Log.w("DRAGII", "POS: "+position);
if (convertView == null) {
convertView = mInflater.inflate(R.layout.bubble, null);
holder = new ViewHolder();
holder.text = (TextView) convertView.findViewById(R.id.text);
holder.parser = new URLImageParser(holder.text);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
if (position <= dialogCache.size())
dialogCache.add(position, Html.fromHtml((String)getItem(position),
holder.parser, null));
holder.text.setText(dialogCache.get(position));
holder.type = getType(position);
int bubble = R.drawable.bubble;
if (holder.type.equals("R")) bubble = R.drawable.bubble_right;
else if (holder.type.equals("L")) bubble = R.drawable.bubble_left;
holder.text.setBackgroundResource(bubble);
return convertView;
}
class ViewHolder {
TextView text;
String type = "B";
URLImageParser parser;
}
}
What should I do?
Solved this problem by using TableLayout instead of ListView.
if u are adding tableRow programmatically to tableLayout, you will have performance issues. Think it again and find a way by using listView
i use the following code to list few items from array , while scrolling the list view items is append more with same data exit in array i don`t know what mistake i made.
Anyone pointed out where i made the mistake.
private static String array_spinner_subcategories[];
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
setContentView(R.layout.sub_categories);
setSubCat();
ListView sub_categories=(ListView)findViewById(R.id.sub_catlist);
sub_categories.setAdapter(new EfficientAdapter(this));
sub_categories.setAdapter(adapter);
sub_categories.setOnItemClickListener(subcatlistener);
cr=getContentResolver();
}
public String[] setSubCat(){
recordDB=new Viddatabase(this);
db=recordDB.getWritableDatabase();
array_spinner_subcategories=recordDB.subcategoriesList(db);
recordDB.close();
return array_spinner_subcategories;
}
private OnItemClickListener subcatlistener = new OnItemClickListener() {
public void onItemClick(AdapterView parent, View v, int position,
long id) {
System.gc();
Toast.makeText(SubCategories.this,array_spinner_subcategories[position],
Toast.LENGTH_LONG).show();
}
};
private static class EfficientAdapter extends BaseAdapter {
private LayoutInflater mInflater;
public EfficientAdapter(Context context) {
mInflater = LayoutInflater.from(context);
}
public int getCount() {
return array_spinner_subcategories.length;
}
public Object getItem(int position) {
return position;
}
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup parent) {
System.gc();
ViewHolder holder;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.albumlist, null);
holder = new ViewHolder();
holder.subCategories = (TextView) convertView.findViewById(R.id.albumDetails);
holder.subCategories.setText(array_spinner_subcategories[position]);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
return convertView;
}
static class ViewHolder {
TextView subCategories;
}
}
Move the holder.subCategories.setText(array_spinner_subcategories[position]); line in getView() method below the else block
In your getView method, you are only setting data in the view when you create a new view.
The ListView recycles views, so you will very likely be passed in a a view to reuse, which is why it is referred to as a convertview.
You need to be calling setText on the view every time this is called, otherwise you are just handing back the convertview unchanged and thus you are getting the same values repeated.
Simple but little tricky, if I have
list.setAdapter(new ArrayAdapter<String>(this,R.layout.double_row, R.id.doubleRow, articleItemsHelper));
it works if articleItemsHelper is String, but I wanna have HTML formatting in there so when articleItemsHelper is type Spanned this (adapter) doesn't work.
ArrayList<Spanned> articleItemsHelper = new ArrayList<Spanned>();
What's the solution?
EDIT: here is the solution - custom adapter
private static class SpannedAdapter extends BaseAdapter {
private LayoutInflater mInflater;
private ArrayList<Spanned> mArticleList;
public SpannedAdapter(Context context, ArrayList<Spanned> articleList) {
mInflater = LayoutInflater.from(context);
mArticleList = articleList;
}
public int getCount() {
return mArticleList.size();
}
public Object getItem(int position) {
return position;
}
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.single_row, null);
holder = new ViewHolder();
holder.text = (TextView) convertView.findViewById(R.id.singleRow);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.text.setText(mArticleList.get(position));
return convertView;
}
static class ViewHolder {
TextView text;
}
}
Then just regularly call
list.setAdapter(new SpannedAdapter(this, articleItemsHelper));
where
articleItemsHelper
is
ArrayList<Spanned>
Old thread but I found an other way to do it, it can help people:
simpleAdpt = new ArrayAdapter<Note>(this, R.layout.notelist, listeNotes ){
public View getView(int position, View view, ViewGroup viewGroup)
{
View v = super.getView(position, view, viewGroup);
Note n = (Note) this.getItem(position);
((TextView)v).setText(Html.fromHtml("<b>"+n.getTitre() + "</b> <br/>"+n.getNote()));
return v;
}
};
This is how ArrayAdapter set the text of the rows:
T item = getItem(position);
if (item instanceof CharSequence) {
text.setText((CharSequence)item);
} else {
text.setText(item.toString());
}
As you can see, what it would do in your case is to call the toString method, and that's why it does not work. So, go ahead and write your own adapter, you have no choice in this case.