Ahmed Awad
Ahmed Awad

Reputation: 1815

Firebase simple chat client not retrieving values

I'm trying to build the simplest android chatting app based on firebase, I've taken the firebase list adapter for chats from their android chat example. and used my own model class but the damn thing won't work. here are the classes and log:

Message model class:

import java.util.Date;

import org.json.JSONException;
import org.json.JSONObject;
import com.shaded.fasterxml.jackson.annotation.JsonIgnore;


public class Message {
    int messageId;
    String messageContent;

    // int chatID;
    // int senderID;
    // int recieverID;
    // Date timeStamp;
    // String messageType;

    /**
     * Message constructor to create message object
     * 
     * @param messageID
     * @param messageContent
     * @param chatID
     *            {@link Chat}
     * @param senderID
     *            {@link User}
     * @param recieverID
     *            {@link User}
     * @param messageType
     */
    // public Message(int messageID, String messageContent, int chatID,
    // int senderID, int recieverID, MessageType messageType) {
    // this.messageID = messageID;
    // this.messageContent = messageContent;
    // this.chatID = chatID;
    // this.senderID = senderID;
    // this.recieverID = recieverID;
    // this.messageType = messageType;
    // }

    @JsonIgnore
    public Message(int messageId, String messageContent) {
        // this.messageContent = messageContent;
        this.messageId = messageId;
        this.messageContent = messageContent;
    }

    /**
     * Message constructor to create message object This will be used when the
     * user send the message and still no status for this message
     * 
     * @param messageContent
     * @param chatID
     *            {@link Chat}
     * @param senderID
     *            {@link User}
     * @param recieverID
     *            {@link User}
     * @param messageType
     */
    // public Message(String messageContent, int chatID, int senderID,
    // int recieverID, MessageType messageType) {
    // this.messageContent = messageContent;
    // this.chatID = chatID;
    // this.senderID = senderID;
    // this.recieverID = recieverID;
    // this.messageType = messageType;
    // }

    /**
     * Message constructor to create message object from JSON response This
     * constructor will be used to create an object from web service JSON
     * response
     * 
     * @param message
     * @throws JSONException
     */
    // public Message(JSONObject message) throws JSONException {
    // messageID = message.getInt("messageID");
    // messageContent = message.getString("messageContent");
    // chatID = message.getInt("chatID");
    // senderID = message.getInt("senderID");
    // recieverID = message.getInt("recieverID");
    // messageType = MessageType.values()[message.getInt("messageType")];
    // }

    /**
     * 
     * @return messageID
     */
     public int getMessageId() {
     return messageId;
     }

     /**
     *
     * @param messageID
     */
     public void setMessageId(int messageId) {
     this.messageId = messageId;
     }

    /**
     * 
     * @return messageContent
     */
     public String getMessageContent() {
     return messageContent;
     }

    /**
     * 
     * @param messageContent
     */
     public void setMessageContent(String messageContent) {
     this.messageContent = messageContent;
     }

    /**
     * 
     * @return chatID
     */
    // public int getChatID() {
    // return chatID;
    // }
    //
    // /**
    // *
    // * @param chatID
    // */
    // public void setChatID(int chatID) {
    // this.chatID = chatID;
    // }

    /**
     * 
     * @return senderId
     */
//   public int getSenderId() {
//   return senderId;
//   }
    //
    // //
    // // /**
    // // *
    // // * @param senderID
    // // */
//   public void setSenderId(int senderId) {
//   this.senderId = senderId;
//   }

    /**
     * 
     * @return recieverID
     */
    // public int getRecieverID() {
    // return recieverID;
    // }
    //
    // /**
    // *
    // * @param recieverID
    // */
    // public void setRecieverID(int recieverID) {
    // this.recieverID = recieverID;
    // }

    /**
     * 
     * @return timeStamp
     */
    // public Date getTimeStamp() {
    // return timeStamp;
    // }
    //
    // /**
    // *
    // * @param timeStamp
    // */
    // public void setTimeStamp(Date timeStamp) {
    // this.timeStamp = timeStamp;
    // }

    /**
     * 
     * @return messageType
     */
//  public MessageType getMessageType() {
//      return messageType;
//  }
    //
    // /**
    // *
    // * @param messageType
    // */
    // public void setMessageType(MessageType messageType) {
    // this.messageType = messageType;
    // }

}

Here's the adapter class:

import android.app.Activity;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;

import com.firebase.client.ChildEventListener;
import com.firebase.client.DataSnapshot;
import com.firebase.client.FirebaseError;
import com.firebase.client.Query;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * User: greg
 * Date: 6/21/13
 * Time: 1:47 PM
 */

/**
 * This class is a generic way of backing an Android ListView with a Firebase location.
 * It handles all of the child events at the given Firebase location. It marshals received data into the given
 * class type. Extend this class and provide an implementation of <code>populateView</code>, which will be given an
 * instance of your list item layout and an instance your class that holds your data. Simply populate the view however
 * you like and this class will handle updating the list as the data changes.
 * @param <Message> The class type to use as a model for the data contained in the children of the given Firebase location
 */
public abstract class FirebaseListAdapter<Message> extends BaseAdapter {

private Query ref;
private Class<Message> modelClass;
private int layout;
private LayoutInflater inflater;
private List<Message> models;
private Map<String, Message> modelNames;
private ChildEventListener listener;


/**
 * @param ref The Firebase location to watch for data changes. Can also be a slice of a location, using some
 *            combination of <code>limit()</code>, <code>startAt()</code>, and <code>endAt()</code>,
 * @param modelClass Firebase will marshall the data at a location into an instance of a class that you provide
 * @param layout This is the layout used to represent a single list item. You will be responsible for populating an
 *               instance of the corresponding view with the data from an instance of modelClass.
 * @param activity The activity containing the ListView
 */
public FirebaseListAdapter(Query ref, Class<Message> modelClass, int layout, Activity activity) {
    this.ref = ref;
    this.modelClass = modelClass;
    this.layout = layout;
    inflater = activity.getLayoutInflater();
    models = new ArrayList<Message>();
    modelNames = new HashMap<String, Message>();
    // Look for all child events. We will then map them to our own internal ArrayList, which backs ListView
    listener = this.ref.addChildEventListener(new ChildEventListener() {
        @Override
        public void onChildAdded(DataSnapshot dataSnapshot, String previousChildName) {

            Log.v("KK", "starded listener");
            Message model = dataSnapshot.getValue(FirebaseListAdapter.this.modelClass);
            modelNames.put(dataSnapshot.getName(), model);
            Log.v("KK", "faga3");

            // Insert into the correct location, based on previousChildName
            if (previousChildName == null) {
                models.add(0, model);
            } else {
                Message previousModel = modelNames.get(previousChildName);
                int previousIndex = models.indexOf(previousModel);
                int nextIndex = previousIndex + 1;
                if (nextIndex == models.size()) {
                    models.add(model);
                } else {
                    models.add(nextIndex, model);
                }
            }

            notifyDataSetChanged();
        }

        @Override
        public void onChildChanged(DataSnapshot dataSnapshot, String s) {

            // One of the models changed. Replace it in our list and name mapping
            String modelName = dataSnapshot.getName();
            Message oldModel = modelNames.get(modelName);
            Message newModel = dataSnapshot.getValue(FirebaseListAdapter.this.modelClass);
            int index = models.indexOf(oldModel);

            models.set(index, newModel);
            modelNames.put(modelName, newModel);

            notifyDataSetChanged();
        }

        @Override
        public void onChildRemoved(DataSnapshot dataSnapshot) {

            // A model was removed from the list. Remove it from our list and the name mapping
            String modelName = dataSnapshot.getName();
            Message oldModel = modelNames.get(modelName);
            models.remove(oldModel);
            modelNames.remove(modelName);
            notifyDataSetChanged();
        }

        @Override
        public void onChildMoved(DataSnapshot dataSnapshot, String previousChildName) {

            // A model changed position in the list. Update our list accordingly
            String modelName = dataSnapshot.getName();
            Message oldModel = modelNames.get(modelName);
            Message newModel = dataSnapshot.getValue(FirebaseListAdapter.this.modelClass);
            int index = models.indexOf(oldModel);
            models.remove(index);
            if (previousChildName == null) {
                models.add(0, newModel);
            } else {
                Message previousModel = modelNames.get(previousChildName);
                int previousIndex = models.indexOf(previousModel);
                int nextIndex = previousIndex + 1;
                if (nextIndex == models.size()) {
                    models.add(newModel);
                } else {
                    models.add(nextIndex, newModel);
                }
            }
            notifyDataSetChanged();
        }

        @Override
        public void onCancelled(FirebaseError arg0) {
            // TODO Auto-generated method stub

        }
    });
}

public void cleanup() {
    // We're being destroyed, let go of our listener and forget about all of the models
    ref.removeEventListener(listener);
    models.clear();
    modelNames.clear();
}

@Override
public int getCount() {
    return models.size();
}

@Override
public Object getItem(int i) {
    return models.get(i);
}

@Override
public long getItemId(int i) {
    return i;
}

@Override
public View getView(int i, View view, ViewGroup viewGroup) {
    if (view == null) {
        view = inflater.inflate(layout, viewGroup, false);
    }

    Message model = models.get(i);
    // Call out to subclass to marshall this model into the provided view
    populateView(view, model);
    return view;
}

/**
 * Each time the data at the given Firebase location changes, this method will be called for each item that needs
 * to be displayed. The arguments correspond to the layout and modelClass given to the constructor of this class.
 *
 * Your implementation should populate the view using the data contained in the model.
 * @param v The view to populate
 * @param model The object containing the data used to populate the view
 */
protected abstract void populateView(View v, Message model);

}

and finally here's the log cat

    10-22 11:30:15.276: V/KK(14856): starded listener
10-22 11:30:15.296: D/AndroidRuntime(14856): Shutting down VM
10-22 11:30:15.296: W/dalvikvm(14856): threadid=1: thread exiting with uncaught exception (group=0x415b0ba8)
10-22 11:30:15.306: E/AndroidRuntime(14856): FATAL EXCEPTION: main
10-22 11:30:15.306: E/AndroidRuntime(14856): Process: ********, PID: 14856
10-22 11:30:15.306: E/AndroidRuntime(14856): com.firebase.client.FirebaseException: Failed to bounce to type
10-22 11:30:15.306: E/AndroidRuntime(14856):    at com.firebase.client.DataSnapshot.getValue(DataSnapshot.java:186)
10-22 11:30:15.306: E/AndroidRuntime(14856):    at ******$1.onChildAdded(FirebaseListAdapter.java:66)
10-22 11:30:15.306: E/AndroidRuntime(14856):    at com.firebase.client.core.ChildListenerContainer$1.run(ChildListenerContainer.java:49)
10-22 11:30:15.306: E/AndroidRuntime(14856):    at android.os.Handler.handleCallback(Handler.java:733)
10-22 11:30:15.306: E/AndroidRuntime(14856):    at android.os.Handler.dispatchMessage(Handler.java:95)
10-22 11:30:15.306: E/AndroidRuntime(14856):    at android.os.Looper.loop(Looper.java:136)
10-22 11:30:15.306: E/AndroidRuntime(14856):    at android.app.ActivityThread.main(ActivityThread.java:5017)
10-22 11:30:15.306: E/AndroidRuntime(14856):    at java.lang.reflect.Method.invokeNative(Native Method)
10-22 11:30:15.306: E/AndroidRuntime(14856):    at java.lang.reflect.Method.invoke(Method.java:515)
10-22 11:30:15.306: E/AndroidRuntime(14856):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)
10-22 11:30:15.306: E/AndroidRuntime(14856):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)
10-22 11:30:15.306: E/AndroidRuntime(14856):    at de.robv.android.xposed.XposedBridge.main(XposedBridge.java:132)
10-22 11:30:15.306: E/AndroidRuntime(14856):    at dalvik.system.NativeStart.main(Native Method)
10-22 11:30:15.306: E/AndroidRuntime(14856): Caused by: com.shaded.fasterxml.jackson.databind.JsonMappingException: Can not instantiate value of type [simple type, class com.annabsoft.androidapp.tilochatlibrary.models.Message] from String value; no single-String constructor/factory method
10-22 11:30:15.306: E/AndroidRuntime(14856):    at com.shaded.fasterxml.jackson.databind.deser.std.StdValueInstantiator._createFromStringFallbacks(StdValueInstantiator.java:428)
10-22 11:30:15.306: E/AndroidRuntime(14856):    at com.shaded.fasterxml.jackson.databind.deser.std.StdValueInstantiator.createFromString(StdValueInstantiator.java:299)
10-22 11:30:15.306: E/AndroidRuntime(14856):    at com.shaded.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromString(BeanDeserializerBase.java:1056)
10-22 11:30:15.306: E/AndroidRuntime(14856):    at com.shaded.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeOther(BeanDeserializer.java:136)
10-22 11:30:15.306: E/AndroidRuntime(14856):    at com.shaded.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:123)
10-22 11:30:15.306: E/AndroidRuntime(14856):    at com.shaded.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:2888)
10-22 11:30:15.306: E/AndroidRuntime(14856):    at com.shaded.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2034)
10-22 11:30:15.306: E/AndroidRuntime(14856):    at com.firebase.client.DataSnapshot.getValue(DataSnapshot.java:182)
10-22 11:30:15.306: E/AndroidRuntime(14856):    ... 12 more
10-22 11:35:15.466: I/Process(14856): Sending signal. PID: 14856 SIG: 9

Upvotes: 0

Views: 913

Answers (2)

sivaram636
sivaram636

Reputation: 429

Just try to include an empty constructor in Pojo class i.e Message class

Message () {
}

Upvotes: 0

jsfrocha
jsfrocha

Reputation: 1860

Just to formalize an answer so it can be useful to others searching this:

Using DataSnapshot.getValue(YourModel.Class) you can get a parsed object with the same structure that is defined in Firebase. Just make sure YourModel.class has that structure.

When serializing the returned object to a POJO, it must contain exactly the same properties as the Firebase object.

Upvotes: 1

Related Questions