0

I'm following a tutorial on how to create a chat client with parse. LINK: https://github.com/codepath/android_guides/wiki/Building-Simple-Chat-Client-with-Parse When I press send in my application it says "parseapp" has stopped. I am a new programmer and am unsure why it is not working. There are no errors in my code. Although it must have something to do with the when the button is pressed or there are some variables that aren't being used. Please help! Thanks in advance.

Here is the main Actvity's code where I think has the greatest chance of where the problem is:

public class ChatActivity extends AppCompatActivity {
static final String TAG = ChatActivity.class.getSimpleName();
static final int MAX_CHAT_MESSAGES_TO_SHOW = 500;

static final String USER_ID_KEY = "userId";
static final String BODY_KEY = "body";

@Override
protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_chat);


    Parse.initialize(new Parse.Configuration.Builder(this)

            .applicationId("indexApp")
            .clientKey(null)
            .server("http://45.55.25.242:8000/parse/") // The trailing slash is important.



            .build()
    );

    // User login
    if (ParseUser.getCurrentUser() != null) { // start with existing user
        startWithCurrentUser();
    } else { // If not logged in, login as a new anonymous user
        login();
    }
}



// Get the userId from the cached currentUser object
void startWithCurrentUser() {
    // TODO:
    setupMessagePosting();
    {
        // Find the text field and button
        etMessage = (EditText) findViewById(R.id.etMessage);
        btSend = (Button) findViewById(R.id.btSend);
        lvChat = (ListView) findViewById(R.id.lvChat);
        mMessages = new ArrayList<>();
        // Automatically scroll to the bottom when a data set change notification is received and only if the last item is already visible on screen. Don't scroll to the bottom otherwise.
        lvChat.setTranscriptMode(1);
        mFirstLoad = true;
        final String userId = ParseUser.getCurrentUser().getObjectId();
        mAdapter = new ChatListAdapter(ChatActivity.this, userId, mMessages);
        lvChat.setAdapter(mAdapter);
        // When send button is clicked, create message object on Parse
        btSend.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String data = etMessage.getText().toString();
                ParseObject message = ParseObject.create("Message");
                message.put(Message.USER_ID_KEY, userId);
                message.put(Message.BODY_KEY, data);
                message.saveInBackground(new SaveCallback() {
                    @Override
                    public void done(ParseException e) {
                        Toast.makeText(ChatActivity.this, "Successfully created message on Parse",
                                Toast.LENGTH_SHORT).show();
                        refreshMessages();
                    }
                });
                etMessage.setText(null);
            }
        });
    }
}

    // Query messages from Parse so we can load them into the chat adapter

    void refreshMessages() {
        // Construct query to execute
        ParseQuery<Message> query = ParseQuery.getQuery(Message.class);
        // Configure limit and sort order
        query.setLimit(MAX_CHAT_MESSAGES_TO_SHOW);
        query.orderByAscending("createdAt");
        // Execute query to fetch all messages from Parse asynchronously
        // This is equivalent to a SELECT query with SQL
        query.findInBackground(new FindCallback<Message>() {
            public void done(List<Message> messages, ParseException e) {
                if (e == null) {
                    mMessages.clear();
                    mMessages.addAll(messages);
                    mAdapter.notifyDataSetChanged(); // update adapter
                    // Scroll to the bottom of the list on initial load
                    if (mFirstLoad) {
                        lvChat.setSelection(mAdapter.getCount() - 1);
                        mFirstLoad = false;
                    }
                } else {
                    Log.e("message", "Error Loading Messages" + e);
                }
            }
        });
    }

// Create an anonymous user using ParseAnonymousUtils and set sUserId
void login() {
    ParseAnonymousUtils.logIn(new LogInCallback() {
        @Override
        public void done(ParseUser user, ParseException e) {
            if (e != null) {
                Log.e(TAG, "Anonymous login failed: ", e);
            } else {
                startWithCurrentUser();
            }
        }
    });
}

EditText etMessage;
Button btSend;

ListView lvChat;
ArrayList<Message> mMessages;
ChatListAdapter mAdapter;
// Keep track of initial load to scroll to the bottom of the ListView
boolean mFirstLoad;

void setupMessagePosting() {
    // Find the text field and button
    etMessage = (EditText) findViewById(R.id.etMessage);
    btSend = (Button) findViewById(R.id.btSend);
    // When send button is clicked, create message object on Parse
    btSend.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            String data = etMessage.getText().toString();
            ParseObject message = ParseObject.create("Message");
            message.put(Message.USER_ID_KEY,    ParseUser.getCurrentUser().getObjectId());
            message.put(Message.BODY_KEY, data);
            message.saveInBackground(new SaveCallback() {
                @Override
                public void done(ParseException e) {
                    Toast.makeText(ChatActivity.this, "Successfully created message on Parse",
                            Toast.LENGTH_SHORT).show();
                }
            });
            etMessage.setText(null);
        }
    });
}

// Create a handler which can run code periodically
static final int POLL_INTERVAL = 1000; // milliseconds
Handler mHandler = new Handler();  // android.os.Handler
Runnable mRefreshMessagesRunnable = new Runnable() {
    @Override
    public void run() {
        refreshMessages();
        mHandler.postDelayed(this, POLL_INTERVAL);
            setContentView(R.layout.activity_chat);
            if (ParseUser.getCurrentUser() != null) {
                startWithCurrentUser();
            } else {
                login();
            }
            mHandler.postDelayed(mRefreshMessagesRunnable, POLL_INTERVAL);
        }

};

}

Here is the layout file:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:background="#ffffff"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.patri.parseapp.ChatActivity">
<ListView
    android:id="@+id/lvChat"
    android:transcriptMode="alwaysScroll"
    android:layout_alignParentTop="true"
    android:layout_alignParentLeft="true"
    android:layout_alignParentRight="true"
    android:layout_above="@+id/rlSend"
    android:layout_width="wrap_content"
    android:layout_height="match_parent" />
<RelativeLayout
    android:id="@+id/rlSend"
    android:layout_alignParentBottom="true"
    android:layout_width="match_parent"
    android:paddingTop="5dp"
    android:paddingBottom="10dp"
    android:paddingLeft="0dp"
    android:paddingRight="0dp"
    android:layout_height="wrap_content" >
    <EditText
        android:id="@+id/etMessage"
        android:layout_toLeftOf="@+id/btSend"
        android:layout_alignBottom="@+id/btSend"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="top"
        android:hint="hint"
        android:inputType="textShortMessage"
        android:imeOptions="actionSend"
        />
    <Button
        android:id="@+id/btSend"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center_vertical|right"
        android:paddingRight="10dp"
        android:layout_alignParentRight="true"
        android:text="send"
        android:textSize="18sp" >
    </Button>
</RelativeLayout>
</RelativeLayout>

Here's my adapter:

public class ChatListAdapter extends ArrayAdapter<Message> {
private String mUserId;

public ChatListAdapter(Context context, String userId, List<Message> messages) {
    super(context, 0, messages);
    this.mUserId = userId;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    if (convertView == null) {
        convertView = LayoutInflater.from(getContext()).
                inflate(R.layout.chat_item, parent, false);
        final ViewHolder holder = new ViewHolder();
        holder.imageOther = (ImageView)convertView.findViewById(R.id.ivProfileOther);
        holder.imageMe = (ImageView)convertView.findViewById(R.id.ivProfileMe);
        holder.body = (TextView)convertView.findViewById(R.id.tvBody);
        convertView.setTag(holder);
    }
    final Message message = getItem(position);
    final ViewHolder holder = (ViewHolder)convertView.getTag();
    final boolean isMe = message.getUserId() != null && message.getUserId().equals(mUserId);
    // Show-hide image based on the logged-in user.
    // Display the profile image to the right for our user, left for other users.
    if (isMe) {
        holder.imageMe.setVisibility(View.VISIBLE);
        holder.imageOther.setVisibility(View.GONE);
        holder.body.setGravity(Gravity.CENTER_VERTICAL | Gravity.RIGHT);
    } else {
        holder.imageOther.setVisibility(View.VISIBLE);
        holder.imageMe.setVisibility(View.GONE);
        holder.body.setGravity(Gravity.CENTER_VERTICAL | Gravity.LEFT);
    }
    final ImageView profileView = isMe ? holder.imageMe : holder.imageOther;
    Picasso.with(getContext()).load(getProfileUrl(message.getUserId())).into(profileView);
    holder.body.setText(message.getBody());
    return convertView;
}

// Create a gravatar image based on the hash value obtained from userId
private static String getProfileUrl(final String userId) {
    String hex = "";
    try {
        final MessageDigest digest = MessageDigest.getInstance("MD5");
        final byte[] hash = digest.digest(userId.getBytes());
        final BigInteger bigInt = new BigInteger(hash);
        hex = bigInt.abs().toString(16);
    } catch (Exception e) {
        e.printStackTrace();
    }
    return "http://www.gravatar.com/avatar/" + hex + "?d=identicon";
}

final class ViewHolder {
    public ImageView imageOther;
    public ImageView imageMe;
    public TextView body;
}
}

Here's an activity class related to how the messages work:

@ParseClassName("Message")
public class Message extends ParseObject {
public static final String USER_ID_KEY = "userId";
public static final String BODY_KEY = "body";

public String getUserId() {
    return getString(USER_ID_KEY);
}

public String getBody() {
    return getString(BODY_KEY);
}

public void setUserId(String userId) {
    put(USER_ID_KEY, userId);
}

public void setBody(String body) {
    put(BODY_KEY, body);
}
}

I don't think any other code will be of use but if code seems to be left out I will make an EDIT.

My error says

com.parse.ParseObject cannot be cast to com.example.patri.parseapp.Message

I have looked this error up and none of the solutions work on stackOverflow.

EDIT: Logcat

07-28 20:10:08.788 9922-9922/com.example.patri.parseapp E/AndroidRuntime: FATAL EXCEPTION: main Process: com.example.patri.parseapp, PID: 9922

    java.lang.ClassCastException: com.parse.ParseObject cannot be cast to com.example.patri.parseapp.Message
                                                                              at com.example.patri.parseapp.ChatListAdapter.getView(ChatListAdapter.java:40)
                                                                              at android.widget.AbsListView.obtainView(AbsListView.java:2347)
                                                                              at android.widget.ListView.measureHeightOfChildren(ListView.java:1270)
                                                                              at android.widget.ListView.onMeasure(ListView.java:1182)
                                                                              at android.view.View.measure(View.java:17565)
                                                                              at android.widget.RelativeLayout.measureChildHorizontal(RelativeLayout.java:727)
                                                                              at android.widget.RelativeLayout.onMeasure(RelativeLayout.java:463)
                                                                              at android.view.View.measure(View.java:17565)
                                                                              at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5537)
                                                                              at android.widget.FrameLayout.onMeasure(FrameLayout.java:436)
                                                                              at android.support.v7.widget.ContentFrameLayout.onMeasure(ContentFrameLayout.java:135)
                                                                              at android.view.View.measure(View.java:17565)
                                                                              at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5537)
                                                                              at android.support.v7.widget.ActionBarOverlayLayout.onMeasure(ActionBarOverlayLayout.java:391)
                                                                              at android.view.View.measure(View.java:17565)
                                                                              at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5537)
                                                                              at android.widget.FrameLayout.onMeasure(FrameLayout.java:436)
                                                                              at android.view.View.measure(View.java:17565)
                                                                              at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5537)
                                                                              at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1436)
                                                                              at android.widget.LinearLayout.measureVertical(LinearLayout.java:722)
                                                                              at android.widget.LinearLayout.onMeasure(LinearLayout.java:613)
                                                                              at android.view.View.measure(View.java:17565)
                                                                              at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5537)
                                                                              at android.widget.FrameLayout.onMeasure(FrameLayout.java:436)
                                                                              at com.android.internal.policy.impl.PhoneWindow$DecorView.onMeasure(PhoneWindow.java:2615)
                                                                              at android.view.View.measure(View.java:17565)
                                                                              at android.view.ViewRootImpl.performMeasure(ViewRootImpl.java:2045)
                                                                              at android.view.ViewRootImpl.measureHierarchy(ViewRootImpl.java:1196)
                                                                              at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1409)
                                                                              at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1084)
                                                                              at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:5990)
                                                                              at android.view.Choreographer$CallbackRecord.run(Choreographer.java:767)
                                                                              at android.view.Choreographer.doCallbacks(Choreographer.java:580)
                                                                              at android.view.Choreographer.doFrame(Choreographer.java:550)
                                                                              at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:753)
                                                                              at android.os.Handler.handleCallback(Handler.java:739)
                                                                              at android.os.Handler.dispatchMessage(Handler.java:95)
                                                                              at android.os.Looper.loop(Looper.java:135)
                                                                              at android.app.ActivityThread.main(ActivityThread.java:5343)
                                                                              at java.lang.reflect.Method.invoke(Native Method)
                                                                              at java.lang.reflect.Method.invoke(Method.java:372)
                                                                              at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:905)
                                                                              at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:700)
07-28 20:10:10.729 9922-9922/com.example.patri.parseapp I/Process: Sending signal. PID: 9922 SIG: 9
Lips_coder
  • 686
  • 1
  • 5
  • 17
Patrick J.
  • 117
  • 11
  • Possible duplicate of [Unfortunately MyApp has stopped. How can I solve this?](http://stackoverflow.com/questions/23353173/unfortunately-myapp-has-stopped-how-can-i-solve-this) – Mike M. Jul 29 '16 at 02:36
  • It's not I looked at the question. Thank you for the input. @MikeM. – Patrick J. Jul 29 '16 at 03:15
  • Yeah, it's a duplicate of that when you don't know how to go about debugging your crash, and since you didn't provide us with the information necessary to determine the cause, that's what we have to assume. – Mike M. Jul 29 '16 at 03:19
  • Please edit your question to include the logcat – OneCricketeer Jul 29 '16 at 03:20
  • It's plain to see the cause of the crash. "com.parse.ParseObject cannot be cast to com.example.patri.parseapp.Message" You can DownCast Message to ParseObject but you **can not** UpCast ParseObject to Message – Machinarius Jul 29 '16 at 03:35
  • Line 40 of `ChatListAdapter` is what? – OneCricketeer Jul 29 '16 at 03:42
  • I don't know if this is what your asking for but here is line 40: final Message message = getItem(position); @cricket_007 – Patrick J. Jul 29 '16 at 03:47
  • I'm not sure what your talking about. @Machinarius I'm a beginner, if it's possible to explain simpler could you? Thank you. Or providing an example would be great. – Patrick J. Jul 29 '16 at 03:49
  • I will provide more information next time @MikeM. – Patrick J. Jul 29 '16 at 03:51
  • @PatrickJ. Basic OOP. So much as any Sedan can be considered a Car but not any Car can be considered a Sedan, classes in proper OOP languages like java can not be more than what they are. Look at your own code and see how Message extends ParseObject. Your Message class is like the Sedan and the ParseObject class is like the car. Any Message can be a ParseObject but not any ParseObject can be a Message, you have to check if it _really_ is a sedan before treating it like one. – Machinarius Jul 29 '16 at 03:54
  • @Machinarius Can you be a little more helpful and try to find where the cast is happening? I'm unable to find it myself – OneCricketeer Jul 29 '16 at 03:58
  • @cricket_007 I can't find it either so i can only theorize about the cause of the error and let OP try and diagnose why it's happening. I'm sorry. – Machinarius Jul 29 '16 at 04:01
  • Thank you, I understand what your saying but I am unsure as how to fix my casting error. How can I check if it is a "sedan" before treating it like one? @Machinarius – Patrick J. Jul 29 '16 at 04:04
  • @PatrickJ. http://stackoverflow.com/a/18147236/528131 You can use the instanceof operator as described in that answer. – Machinarius Jul 29 '16 at 04:06
  • I'm sorry to keep hammering you with questions, I know you exactly what to do but I don't. Where and how would I use that in my code? In the MainActivity or the Message class? @Machinarius – Patrick J. Jul 29 '16 at 04:15
  • In the getView method. You could assign the getObject call result to an Object variable and check if it really is a Message object with the instanceof operator. If it's not you should throw an Exception of your own making like ```throw new Exception("Invalid message object detected")``` and put a breakpoint there so you can debug in context. – Machinarius Jul 29 '16 at 04:18

1 Answers1

1

Overall, I don't see why you are getting that error. But, as explained in the comments, all Message objects are a ParseObject, but not all ParseObject can be cast to a Message, therefore the error, but you aren't casting and your error seems to be at final Message message = getItem(position), where an implicit cast could be happening, but it shouldn't because you've extended ArrayAdapter<Message>

Here are some things you could try.

Declare the arraylist with the object type

mMessages = new ArrayList<Message>();

Make sure this string in here is the name of a Parse table

@ParseClassName("Message")

Implement the getItem method of the adapter.

public class ChatListAdapter extends ArrayAdapter<Message> {
    private String mUserId;
    private ArrayList<Message> messages;

public ChatListAdapter(Context context, String userId, ArrayList<Message> messages) {
    super(context, 0, messages);
    this.mUserId = userId;
    this.messages = messages;
}  

@Override 
public Message getItem(int position) { 
    return messages.get(position);
} 
OneCricketeer
  • 179,855
  • 19
  • 132
  • 245