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