Welcome to the Treehouse Community

The Treehouse Community is a meeting place for developers, designers, and programmers of all backgrounds and skill levels to get support. Collaborate here on code errors or bugs that you need feedback on, or asking for an extra set of eyes on your latest project. Join thousands of Treehouse students and alumni in the community today. (Note: Only Treehouse students can comment or ask questions, but non-students are welcome to browse our conversations.)

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and a supportive community. Start your free trial today.

Android Build a Self-Destructing Message Android App Sending Messages Adding a File to the Message: Part 2

Can someone elaborate a bit more on how to send simple text?

I tried to add the option to send simple strings as the message instead of an image or video. I have added a button next to the camera in the Action Bar that starts a new Dialog with custom layout with an EditText and a button. Then I get the text from the EditText and via intent go to RecipientsActivity. But when I click on the send button I get an "IllegalArgumentException" : value may not be null;

Here is some code:

            case R.id.action_message:
            final Dialog messageDialog = new Dialog(this);
            messageDialog.setContentView(R.layout.message_bar);
            messageDialog.show();

            Button messageButton = (Button)messageDialog.findViewById(R.id.send_button);
            messageButton.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    EditText messageText = (EditText) messageDialog.findViewById(R.id.edit_text_message);
                    final String message = messageText.getText().toString();
                    if (TextUtils.isEmpty(message)) {
                        Toast.makeText(MainActivity.this, "Enter a message first!", Toast.LENGTH_SHORT).show();
                    } else {
                        Intent recipientsIntent = new Intent(MainActivity.this, RecipientsActivity.class);
                        recipientsIntent.putExtra(ParseConstants.TYPE_TEXT, message);
                        startActivity(recipientsIntent);
                    }

                }
            });

Do I need to adapt the RecipientsActivity to create the message in a different way if that message is not video or text? Perhaps some clues about the "mMediaUri" which in my case is empty as a text can't have that.

So yeah... just some directions of how to proceed will be nice :) Thanks!

I am getting near, but still struggling :(

Funny thing is I understand the way sending the images and videos work, but cannot adapt it for text - which should be trivia... I am trying to use the same way to upload the message as if it were image or video. Instead of calling startActivityForResult(), I am directly pointing to the RecipientsActivity with the message inside and a new TYPE_TEXT. So I guess now I have to handle that new "fileType" in RecipientsActivity when creating the message and omit the media URI. Perhaps put a new field to indicate text data is required as well? Any thoughts are welcome.

Ben Jakuben ? :)

5 Answers

Paul Stevens
Paul Stevens
4,125 Points

I have recently just done it for my Ribbit app. I will see if I can explain it here, I'm not very good yet so the code may not be the best, but it does work for me so far without problems.

First I added an icon to the action bar and changed the onOptionsItemSelected code in MainActivity to the following:

@Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int itemId = item.getItemId();

        switch(itemId) {
            case R.id.action_logout:
                ParseUser.logOut();
                navigateToLogin();
                break;
            case R.id.action_edit_friends:
                Intent intent = new Intent(this, EditFriendsActivity.class); 
                startActivity(intent);
                break;
            case R.id.action_camera:
                AlertDialog.Builder builder = new AlertDialog.Builder(this);
                builder.setItems(R.array.camera_choices, mDialogListener);
                AlertDialog dialog = builder.create();
                dialog.show();
                break;
            case R.id.action_message:

                //*********************************************************
                AlertDialog.Builder alert = new AlertDialog.Builder(this);
                alert.setTitle("Send Message.");
                alert.setMessage("Type your message below.");
                // Set an EditText view to get user input 
                final EditText input = new EditText(this);
                alert.setView(input);
                alert.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int whichButton) {
                  String value = input.getText().toString();
                    Intent recipientsIntent = new Intent(MainActivity.this, RecipientsActivity.class);
                    recipientsIntent.putExtra(ParseConstants.KEY_MESSAGE, value);
                    recipientsIntent.putExtra(ParseConstants.KEY_FILE_TYPE, ParseConstants.TYPE_TEXT);
                    startActivity(recipientsIntent);
                  }
                });
                alert.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
                  public void onClick(DialogInterface dialog, int whichButton) {
                    // Canceled. 
                  }
                });
                alert.show();
                //******************************************************
                break;
        }   

Here is my code for the onListItemclick in the InboxFragment:

@Override
    public void onListItemClick(ListView l, View v, int position, long id) {
        super.onListItemClick(l, v, position, id);
        ParseObject message = mMessages.get(position);
        String messageType = message.getString(ParseConstants.KEY_FILE_TYPE);
        String senderName = message.getString(ParseConstants.KEY_SENDER_NAME);
        String displayMessage = message.getString(ParseConstants.KEY_MESSAGE);
        ParseFile file = message.getParseFile(ParseConstants.KEY_FILE); 
        if (messageType.equals(ParseConstants.TYPE_IMAGE)) {
            //view the image
            Uri fileUri = Uri.parse(file.getUrl());
            Intent intent = new Intent(getActivity(), ViewImageActivity.class);
            intent.setData(fileUri);
            startActivity(intent);
        }else if (messageType.equals(ParseConstants.TYPE_VIDEO)){
            Uri fileUri = Uri.parse(file.getUrl());
            //view the video
            Intent intent = new Intent(Intent.ACTION_VIEW, fileUri);
            intent.setDataAndType(fileUri, "video/*");
            startActivity(intent);
        }else if (messageType.equals(ParseConstants.TYPE_TEXT)){

            //Toast.makeText(getActivity(),  displayMessage, Toast.LENGTH_LONG).show();
            AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
            builder.setTitle("Message from: " + senderName + ".");
            builder.setMessage(displayMessage);
            builder.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int whichButton) {

                }
            });
            AlertDialog dialog = builder.create();
            dialog.show();
        }

        //delete the message
        List<String> ids = message.getList(ParseConstants.KEY_RECIPIENT_IDS);

        if(ids.size() == 1) {
            //last recipient, delete the message
            message.deleteInBackground();

        }else {
            //remove recipients name
            ids.remove(ParseUser.getCurrentUser().getObjectId());

            ArrayList<String> idsToRemove = new ArrayList<String>();
            idsToRemove.add(ParseUser.getCurrentUser().getObjectId());

            message.removeAll(ParseConstants.KEY_RECIPIENT_IDS, idsToRemove);
            message.saveInBackground();
        }
    }

Here is my Parse Constants:

public final class ParseConstants {
    //Class name
    public static final String CLASS_MESSAGES = "Messages";

    //Field names
    public static final String KEY_USERNAME = "username";
    public static final String KEY_FRIENDSRELATION = "friendsRelation";
    public static final String KEY_RECIPIENT_IDS = "recipientIds";
    public static final String KEY_SENDER_ID ="senderId";
    public static final String KEY_SENDER_NAME ="senderName";
    public static final String KEY_FILE ="file";
    public static final String KEY_FILE_TYPE ="fileType";
    public static final String KEY_CREATED_AT = "createdAt";
    public static final String KEY_MESSAGE = "themessage";

    public static final String TYPE_IMAGE ="image";
    public static final String TYPE_VIDEO ="video";
    public static final String TYPE_TEXT ="message";


}

My MessageAdapter :

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder;

        if (convertView == null) {
            convertView = LayoutInflater.from(mContext).inflate(R.layout.message_item, null);
            holder = new ViewHolder();
            holder.iconImageView = (ImageView)convertView.findViewById(R.id.message_icon);
            holder.nameLabel = (TextView)convertView.findViewById(R.id.sender_label);
            convertView.setTag(holder);
        }else {
            holder = (ViewHolder)convertView.getTag();
        }

        ParseObject message =mMessages.get(position);
        if (message.getString(ParseConstants.KEY_FILE_TYPE).equals(ParseConstants.TYPE_IMAGE)) {
            holder.iconImageView.setImageResource(R.drawable.ic_action_picture);
        }else if (message.getString(ParseConstants.KEY_FILE_TYPE).equals(ParseConstants.TYPE_VIDEO)){
            holder.iconImageView.setImageResource(R.drawable.ic_action_play_over_video);
        }else {
            holder.iconImageView.setImageResource(R.drawable.ic_action_chat_light);
        }



        holder.nameLabel.setText(message.getString(ParseConstants.KEY_SENDER_NAME));

        return convertView;
    }

CreateMessage from RecipientsActivity:

protected ParseObject createMessage(){
        ParseObject message = new ParseObject(ParseConstants.CLASS_MESSAGES);
        message.put(ParseConstants.KEY_SENDER_ID, ParseUser.getCurrentUser().getObjectId());
        message.put(ParseConstants.KEY_SENDER_NAME, ParseUser.getCurrentUser().getUsername());
        message.put(ParseConstants.KEY_RECIPIENT_IDS, getRecipientIds());

        message.put(ParseConstants.KEY_FILE_TYPE, mFileType);

        //*************
        if (mFileType.equals(ParseConstants.TYPE_TEXT)) {
            message.put("themessage", mMyMessage);
            message.put(ParseConstants.KEY_FILE_TYPE, "message");
            return message;
        }else{
        //***************


            byte[] fileBytes = FileHelper.getByteArrayFromFile(this, mMediaUri);

            if (fileBytes == null) {
                return null;
            }else {
                if(mFileType.equals(ParseConstants.TYPE_IMAGE)) {
                    fileBytes = FileHelper.reduceImageForUpload(fileBytes);
                }
                String fileName = FileHelper.getFileName(this, mMediaUri, mFileType);
                ParseFile file = new ParseFile(fileName, fileBytes);
                message.put(ParseConstants.KEY_FILE, file);
                return message;
            }
        //***********
        }
        //***********

    }

onCreate from RecipientsActivity:

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
        setContentView(R.layout.activity_recipients);
        // Show the Up button in the action bar.
        setupActionBar();
        getListView().setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);

        mMediaUri = getIntent().getData();
        mFileType = getIntent().getExtras().getString(ParseConstants.KEY_FILE_TYPE);
        //***************
        mMyMessage = getIntent().getExtras().getString("themessage");
        //***************
    }

I think these are all the changes I made, I kind of muddled through this so not sure if it's everything, but please feel free to ask if there is anything else I may be able to clarify. I have just pasted a lot of code with no explanations really, sorry, but I hope it helps a bit. :D

Hey thanks for the help! I haven't finished the whole tutorial yet and I am not yet retrieving messages from Parse (just sending), so I don't need the MessageAdapter yet. But everything else seems perfect and does the job as you say!

I was missing something similar to the:

mMyMessage = getIntent().getExtras().getString("theMessage");

This is why it was complaining about IllegalArgumentException, but now it works.

Once again thanks!

Eric De Wildt
Eric De Wildt
Courses Plus Student 13,077 Points

I am using this code but when I click on the edit text area it crashes the app.

adnanalvee2
adnanalvee2
6,862 Points

I had a quick question as I'm confused in the method where the Menu choices are in "onOptionsItemSelected(MenuItem item)"

if you see it is a switch statement with four cases or options as we see in the app, which are

 **1. case R.id.action_logout:**

 **2. case R.id.action_edit_friends:**

 **3. case R.id.action_camera:**

 **4. case R.id.action_message:**

Though I haven't done the extra credit for messages, my question is why does the "Logout" and "EditFriends" options stays together in a separate small window, and the camera button is outside in the actionbar. Arent they all supposed to be together side by side as that seems more logical with the switch statement code.

Anyone explain please?

Paul Stevens
Paul Stevens
4,125 Points

No problem at all. Glad I could help. :)

Paul Stevens
Paul Stevens
4,125 Points

That's strange Eric,

Can you post the error it gives you in the LogCat. Hopefully it can tell us what line of code the error is happening on.

Paul :)

Carlos Fernando Gómez Carrero
Carlos Fernando Gómez Carrero
46,984 Points

Hi Paul, sending a text message works very well with your code, thanks for sharing

I cannot see the text that i send because as soon as i touch the recieved text, the app crashes :(

Paul thanks for taking the time to post your code!

Lend - I had the same problem and it was because I was creating the Uri even if it was a text message. You only want to create the Uri if the message is an image or video message. So in InboxFragment you can simply move the below line to your if/else statements for the cases where the message is an image or video as Paul does in his code:

Uri fileUri = Uri.parse(file.getUrl());