I am building a Java android app and I am using realm.io for my database. My problem is I have a RealmList and my Custom ListView adapter only accepts RealmResults. Below is the code and more details.
I have an Chat class that has a RealmList, RealmList, userId and a chatId.
public class Chat extends RealmObject{
private RealmList<Friend> participants;
private RealmList<Message> messages;
#PrimaryKey
private String chatId;
private String userId;
...
}
In my activity where I am trying to display all the messages that the chat has, I can call chat.getMessages() to get all the messages for this chat as a RealmList but my ListView adapter below takes a RealmResult because it extends RealmBaseAdapter
public class MessageAdapter extends RealmBaseAdapter<Message> implements ListAdapter {
private String TAG = getClass().getSimpleName();
public MessageAdapter(Context context,
RealmResults<Message> realmResults,
boolean automaticUpdate) {
super(context, realmResults, automaticUpdate);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null)
{
convertView = inflater.inflate(R.layout.listitem_message, parent, false);
}
Message message = getRealmResults().get(position);
if (message != null)
{
((TextView) convertView.findViewById(R.id.message_content)).setText(message.getContent());
DateFormat dateFormat = new SimpleDateFormat("HH:mm", Locale.CANADA);
((TextView) convertView.findViewById(R.id.message_time)).setText(dateFormat.format(message.getTimestamp()));
}
return convertView;
}
public RealmResults<Message> getRealmResults() {
return realmResults;
}
}
Here is where I call it all
RealmList<Message> messages = chat.getMessages();
ListView messageList = (ListView) findViewById(R.id.message_list);
adapter = new MessageAdapter(this, messages, true);
messageList.setAdapter(adapter);
I am open to changing my RealmList to a RealmResult if possible (I have looked and it doesn't seem to be) or If I can use a RealmList in the custom realm adapter that would another solution. Anything to help me move forward would be great help.
thanks
Just do
chat.getMessages().where().findAll()
(Answer from here)
RealmBaseAdapter has a very simple implementation.
So in the case, you can pass the specific Chat to you adapter, and overload below methods:
#Override
public int getCount() {
if (realmResults == null || realmResults.size() == 0) {
return 0;
}
return realmResults.first().getMessages().size();
}
#Override
public T getItem(int i) {
if (realmResults == null || realmResults.size() == 0) {
return null;
}
return realmResults.first().getMessages().get(i);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// You message view here
}
Related
I m creating a sms app for that I am working with chat list appearance here is my Chatlist adapter class.
chatlistAdapter.java:
public class chatList_AdapterClass extends BaseAdapter {
private Context mContext;
private ArrayList<chatList_row> mArrayList;
ViewHolder mHolder=null;
public chatList_AdapterClass(Context context, ArrayList<chatList_row> arrayList) {
mContext = context;
mArrayList = arrayList;
}
public class ViewHolder{
TextView mReceivedMessage;
LinearLayout.LayoutParams mParams;
ViewHolder(View v){
mReceivedMessage=(TextView)v.findViewById(R.id.ChatListMessages);
}
}
#Override
public int getCount() {
return mArrayList.size();
}
#Override
public Object getItem(int i) {
return mArrayList.get(i);
}
#Override
public long getItemId(int i) {
return 0;
}
#Override
public View getView(int position, View ConvertView, ViewGroup parent) {
View row=ConvertView;
if (row == null){
LayoutInflater inflater=(LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
row=inflater.inflate(R.layout.chat_list_row,parent,false);
mHolder=new ViewHolder(row);
mHolder.mParams=(LinearLayout.LayoutParams)mHolder.mReceivedMessage.getLayoutParams();
row.setTag(mHolder);
}else {
mHolder=(ViewHolder)row.getTag();
}
mHolder.mReceivedMessage.setText(mArrayList.get(position).getMessageContent());
boolean send=mArrayList.get(position).getTypeofMessage().equals("send");
setChatRowAppearance(send,mHolder);
return row;
}
public void setChatRowAppearance(boolean send,ViewHolder mHolder){
if (send){
mHolder.mParams.gravity= Gravity.END;
mHolder.mReceivedMessage.setTextColor(Color.WHITE);
mHolder.mReceivedMessage.setBackgroundResource(R.drawable.bubble2);
}else {
mHolder.mParams.gravity= Gravity.START;
mHolder.mReceivedMessage.setTextColor(Color.WHITE);
mHolder.mReceivedMessage.setBackgroundResource(R.drawable.bubble1);
}
}
}
when I am sending and receiving SMS I am saving it to a database
Retrieving that from database and passing to a arraylist
From that arraylist I am creating chat appearance left and right
The problem is the after a sms send and receive the new sms should appear below the previous message but here my new messages are also appears in previous sms like ....
SEND SMS
1
3
Received sms
2
4
I have a list view and each item contains a check box and other various text views. In the Main Activity I have an ArrayList of objects called listOfStuff. From the main activity I'm defining and using a custom base adapter. In the getView method I defined a listener for the check box like so:
holder.cbCompletionStatus.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(holder.cbCompletionStatus.isChecked()){
listOfStuff.get(position).setComplete(1);
} else {
listOfStuff.get(position).setComplete(0);
};
}
});
My problem is that I don't know how to access the listOfStuff and the objects within it to modify the information within. The code in the if/else statement hopefully gives an idea what I was trying to do. Just a quick warning, I'm not only new to Android and Java, but to programming field on the whole. Thanks.
UPDATE:
So I ended up figuring this out on my own. I just had to make the listOfStuff Arraylist a static in the Main Activity. Then I could call a static function in the Main Activity to manipulate whatever data in the Array list I needed like so:
MainActivity.checkBoxClicked(result, position);
Here is my class:
class ImageInfoAdapter extends BaseAdapter{
#Override
public int getCount() {
if(viewcount == 0){
return 0;
}
return viewcount;
}
#Override
public Object getItem(int position) {
return isSentAlList.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View view, ViewGroup parent) {
final ViewHolder viewHolder;
View rowView=view;
if(rowView==null){
LayoutInflater layoutinflate = LayoutInflater.from(ListPictures.this);
rowView=layoutinflate.inflate(R.layout.listviewayout, parent, false);
viewHolder = new ViewHolder();
viewHolder.textViewisSentFlag = (TextView)rowView.findViewById(R.id.textViewisSentFlag);
viewHolder.imageViewToSent = (ImageView)rowView.findViewById(R.id.imageViewToSent);
viewHolder.checkBoxToSend = (CheckBox)rowView.findViewById(R.id.checkBoxToSend);
rowView.setTag(viewHolder);
} else{
viewHolder = (ViewHolder) rowView.getTag();
}
viewHolder.ref = position;
Log.i("InfoLog","viewHolder.ref = position; "+viewHolder.ref);
viewHolder.textViewisSentFlag.setText(isSentAlList.get(position));
Bitmap blob = BitmapFactory.decodeByteArray(imageAlList.get(position), 0, imageAlList.get(position).length);
viewHolder.imageViewToSent.setImageBitmap(blob);
viewHolder.checkBoxToSend.setClickable(true);
if(checked.containsKey(""+viewHolder.ref)){ ///if this id is present as key in hashmap
Log.i("InfoLog","checked.containsKey "+viewHolder.ref);
if(checked.get(""+viewHolder.ref).equals("true")){ //also check whether it is true or false to check/uncheck checkbox
Log.i("InfoLog","checked.get(position) "+viewHolder.ref);
viewHolder.checkBoxToSend.setChecked(true);
} else
viewHolder.checkBoxToSend.setChecked(false);
} else
viewHolder.checkBoxToSend.setChecked(false);
viewHolder.checkBoxToSend.setOnCheckedChangeListener(new OncheckchangeListner(viewHolder));
return rowView;
}//End of method getView
}//End of class ImageInfo
class ViewHolder{
private TextView textViewisSentFlag = null;
private ImageView imageViewToSent = null;
private CheckBox checkBoxToSend = null;
int ref;
}//End of class ViewHolder
/////////////////////////
and here is my oncheckchangedlistener
////////////////////////
class OncheckchangeListner implements OnCheckedChangeListener{
ViewHolder viewHolder = null;
public OncheckchangeListner(ViewHolder viHolder) {
viewHolder = viHolder;
}
#Override
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) {
if(viewHolder.checkBoxToSend.equals(buttonView)) {
if(!isChecked) {
Log.i("InfoLog","checked.get before "+checked.get(""+viewHolder.ref));
checked.put(""+viewHolder.ref,"false");
Log.i("InfoLog","checked.get after "+checked.get(""+viewHolder.ref));
} else
checked.put(""+viewHolder.ref,"true");
} else
Log.i("InfoLog","i m in checkchange ");
}
}
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.
I'm trying to populate a listview with data passed into the activity via a the intent that created it. The println statement you see confirms that the data is passed in correctly (i.e. the expected content is printed, meaning that the ArrayList referenced in the adapter is properly initialized). However, I keep getting a NullPointerException on the line
content.setText(Html.fromHtml(cmts.get(position).content));
There must be something wrong in the adapter - maybe in the getItem(), or perhaps my calls to cmts.get(position) isn't doing what I think it is, but at this point I can't figure it out.
public class CommentsView extends Activity {
ArrayList<Comment> cmts;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_comments_view);
cmts = (ArrayList<Comment>) getIntent().getExtras().getSerializable("clist");
for (Comment c : cmts) {
System.out.println("CMTinCV: " + c.content);
}
ListView lv = (ListView)findViewById(R.id.commentsList);
CommentAdapter ca = new CommentAdapter();
lv.setAdapter(ca);
}
class CommentAdapter extends BaseAdapter {
public CommentAdapter(){
}
#Override
public int getCount() {
return cmts.size()-1;
}
#Override
public Object getItem(int position) {
return cmts.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = getLayoutInflater().inflate(R.layout.commentbox, null);
TextView content = (TextView)findViewById(R.id.commentText);
TextView author = (TextView)findViewById(R.id.commentAuthor);
TextView date = (TextView)findViewById(R.id.commentDate);
content.setText(Html.fromHtml(cmts.get(position).content));
author.setText(cmts.get(position).author.name);
date.setText(cmts.get(position).date);
}
return convertView;
}
}
}
You need to access the textview's in your getview method as below:
convertView.findViewById(R.id.commentText); access it like this.
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = getLayoutInflater().inflate(R.layout.commentbox, null);
TextView content = (TextView)convertView.findViewById(R.id.commentText);
TextView author = (TextView)convertView.findViewById(R.id.commentAuthor);
TextView date = (TextView)convertView.findViewById(R.id.commentDate);
content.setText(Html.fromHtml(cmts.get(position).content));
author.setText(cmts.get(position).author.name);
date.setText(cmts.get(position).date);
}
return convertView;
}
Change your Adapter's constructor to this (if it's not an inner class for your activity) :
ArrayList<Comment> cmts;
public CommentAdapter(ArrayList<Comment> mComments){
this.cmts = mComments;
}
and these lines :
TextView content = (TextView)findViewById(R.id.commentText);
TextView author = (TextView)findViewById(R.id.commentAuthor);
TextView date = (TextView)findViewById(R.id.commentDate);
should be like :
TextView content = (TextView) convertView.findViewById(R.id.commentText);
TextView author = (TextView) convertView.findViewById(R.id.commentAuthor);
TextView date = (TextView) convertView.findViewById(R.id.commentDate);
Check if the variable is null or not first:
if(cmts.get(position) != null) {
content.setText(Html.fromHtml(cmts.get(position).content));
author.setText(cmts.get(position).author.name);
date.setText(cmts.get(position).date);
}
To create the adapter like this
CommentAdapter ca = new CommentAdapter(cmts);
And CommentAdapter class to create constructor like this
public CommentAdapter(ArrayList<Comment> cmts){
this.cmts = cmts;
}
And create local variable in CommentAdapter class
private ArrayList<Comment> cmts;
I use ListActivity with SpecialAdapter that show some log information.
I do not use background thread but I get an error when scroll list:
java.lang.IllegalStateException: The content of the adapter has changed but ListView did not receive a notification. Make sure the content of your adapter is not modified from a background thread, but only from the UI thread. [in ListView(16908298, class android.widget.ListView) with Adapter(class ru.FoxGSM.ui.DebugActivity$SpecialAdapter)]
Please, help me.
(FoxLog is static class that get log information, perhaps from another thread. But in list a want show FoxLog snapshot)
public class DebugActivity extends ListActivity {
private class SpecialAdapter extends BaseAdapter {
private LayoutInflater mInflater;
public SpecialAdapter(Context context) {
super();
// Cache the LayoutInflate to avoid asking for a new one each time.
mInflater = LayoutInflater.from(context);
}
public int getCount() {
return FoxLog.count();
}
public long getItemId(int index) {
return index;
}
public Object getItem(int index) {
return FoxLog.get(FoxLog.count()-index-1);
}
// Get the type of View
public View getView(int position, View convertView, ViewGroup parent) {
TextView text;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.debug_list, null);
text = (TextView)convertView.findViewById(R.id.text);
convertView.setTag(text);
} else
text = (TextView) convertView.getTag();
String s = (String) getItem(position);
if (s==null)
return convertView;
text.setText(s);
boolean isError = false;
if (s!=null && s.length()>0) {
String prefix = s.substring(0, 1);
if (prefix.equals("E") || prefix.equals("W"))
isError = true;
}
if (isError)
text.setBackgroundResource(R.color.red);
else
text.setBackgroundDrawable(null);
return convertView;
}
}
private void RefreshData() {
FoxLog.ReInit(this);
SpecialAdapter adapter = (SpecialAdapter)this.getListAdapter();
adapter.notifyDataSetChanged();
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.debug);
FoxLog.ReInit(this);
SpecialAdapter adapter = new SpecialAdapter(this);
setListAdapter(adapter);
Button mExit = (Button)findViewById(R.id.exit);
mExit.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
finish();
}
});
}
}