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 Sending the Message

When saving in the background..app freezes before sending the message. Help please!

When I am trying to send the message I will hit the send button. The app freezes for 5secs or more before executing the send() and the finish(). Why is it freezing first before sending?

package com.thegreathoudini.kevin.odysity;

import android.app.AlertDialog;
import android.app.ListActivity;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.Toast;

import com.parse.FindCallback;
import com.parse.ParseException;
import com.parse.ParseFile;
import com.parse.ParseInstallation;
import com.parse.ParseObject;
import com.parse.ParsePush;
import com.parse.ParseQuery;
import com.parse.ParseRelation;
import com.parse.ParseUser;
import com.parse.SaveCallback;

import java.util.ArrayList;
import java.util.List;

public class RecipientsActivity extends ListActivity {

    public static final String TAG = RecipientsActivity.class.getSimpleName();

    protected ParseRelation<ParseUser> mFriendsRelations;
    protected ParseUser mCurrentUser;
    protected List<ParseUser> mFriends;
    protected ProgressBar mLoadingRecipients;
    protected MenuItem mSendMenuItem;
    protected Uri mMediaUri;
    protected String mFileType;
    protected EditText mCommentText;
    protected String mComment;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_recipients);
        getActionBar();

        getListView().setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);

        mMediaUri = getIntent().getData();
        mFileType = getIntent().getExtras().getString(ParseConstants.KEY_FILE_TYPE);
    }

    @Override
    protected void onResume() {
        super.onResume();

        mCommentText = (EditText) findViewById(R.id.commentEditText);
        mLoadingRecipients = (ProgressBar) findViewById(R.id.loadingRecipientsProgress);

        mCurrentUser = ParseUser.getCurrentUser();
        mFriendsRelations = mCurrentUser.getRelation(ParseConstants.KEY_Friends_Relations);


        mLoadingRecipients.setVisibility(View.VISIBLE);
        ParseQuery<ParseUser> query = ParseUser.getQuery();
        query.orderByAscending(ParseConstants.KEY_USERNAME);
        query.setLimit(1000);
        query.setCachePolicy(ParseQuery.CachePolicy.CACHE_ELSE_NETWORK);
        query.findInBackground(new FindCallback<ParseUser>() {
            @Override
            public void done(List<ParseUser> friends, ParseException e) {
                //Build the list of Parse relations

                mLoadingRecipients.setVisibility(View.INVISIBLE);
                if (e == null) {

                    mFriends = friends;
                    String[] friendsUsername = new String[mFriends.size()];
                    int i = 0;
                    for (ParseUser friendlist : mFriends) {
                        friendsUsername[i] = friendlist.get(ParseConstants.KEY_NAME).toString();
                        i++;

                        ArrayAdapter<String> adapter = new ArrayAdapter<String>(
                                RecipientsActivity.this, android.R.layout.simple_list_item_checked, friendsUsername);
                        setListAdapter(adapter);
                    }

                } else {
                    mLoadingRecipients.setVisibility(View.INVISIBLE);
                    Log.e(TAG, e.getMessage());
                    AlertDialog.Builder builder = new AlertDialog.Builder(RecipientsActivity.this);
                    builder.setTitle(R.string.signup_error_title)
                            .setMessage(R.string.no_friends_found)
                            .setPositiveButton(android.R.string.ok, null);
                    AlertDialog dialog = builder.create();
                    dialog.show();

                }
            }
        });
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_recipients, menu);
        mSendMenuItem = menu.getItem(0);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_send) {

            mComment = mCommentText.getText().toString();

            if(mComment.isEmpty()){
                mComment = "";
            }

            mLoadingRecipients.setVisibility(View.VISIBLE);
            ParseObject message = createMessage();
            if(message == null){
                //error
                mLoadingRecipients.setVisibility(View.INVISIBLE);
                AlertDialog.Builder builder = new AlertDialog.Builder(this);
                                    builder.setMessage(R.string.error_file)
                                           .setTitle(R.string.signup_error_title)
                                           .setPositiveButton(android.R.string.ok,null);
                AlertDialog dialog = builder.create();
                dialog.show();
            }
            else {


                send(message);
                mLoadingRecipients.setVisibility(View.INVISIBLE);
                finish();
            }

            return true;
        }

        return super.onOptionsItemSelected(item);
    }

    @Override
    protected void onListItemClick(ListView l, View v, int position, long id) {
        super.onListItemClick(l, v, position, id);

        if(l.getCheckedItemCount() > 0){
            mSendMenuItem.setVisible(true);
        }
        else {
            mSendMenuItem.setVisible(false);
        }


    }

    protected ParseObject createMessage(){

        ParseObject message = new ParseObject(ParseConstants.CLASS_MESSAGES);
                    message.put(ParseConstants.KEY_SENDERS_IDS , ParseUser.getCurrentUser().getObjectId());
                    message.put(ParseConstants.KEY_SENDER_NAME , ParseUser.getCurrentUser().getUsername());
                    message.put(ParseConstants.KEY_RECIPIENTS_IDS, getRecipientsIds());
                    message.put(ParseConstants.KEY_FILE_TYPE, mFileType);
                    message.put(ParseConstants.KEY_COMMENT_TEXT, mComment);

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

        if(fileByte == null){
            return null;
        }
        else {
         if (mFileType.equals(ParseConstants.TYPE_IMAGE)){
             fileByte = FileHelper.reduceImageForUpload(fileByte);

         }
            String fileName = FileHelper.getFileName(this, mMediaUri,mFileType);
            ParseFile file = new ParseFile(fileName, fileByte);
            message.put(ParseConstants.KEY_FILE, file);

            return message;

        }


    }

    protected ArrayList<String> getRecipientsIds(){
        ArrayList<String> recipientsList = new ArrayList<>();
        for(int i = 0; i<getListView().getCount() ; i++){
            if(getListView().isItemChecked(i)){
                recipientsList.add(mFriends.get(i).getObjectId());

            }

        }
        return  recipientsList;
    }

    protected void send(ParseObject message){
        message.saveInBackground(new SaveCallback() {
            @Override
            public void done(ParseException e) {

                if (e == null) {
                    //success
                    Toast.makeText(RecipientsActivity.this, R.string.success_message, Toast.LENGTH_LONG).show();

                    sendPushNotification();


                } else {
                    AlertDialog.Builder builder = new AlertDialog.Builder(RecipientsActivity.this);
                    builder.setMessage(R.string.error_file)
                            .setTitle(R.string.signup_error_title)
                            .setPositiveButton(android.R.string.ok, null);
                    AlertDialog dialog = builder.create();
                    dialog.show();
                }

            }
        });
    }
    protected  void sendPushNotification (){
        ParseQuery<ParseInstallation> query = ParseInstallation.getQuery();
        query.whereContainedIn(ParseConstants.KEY_USER_ID, getRecipientsIds());

        //send push notification
        ParsePush push = new ParsePush();
        push.setQuery(query);
        push.setMessage(getString(R.string.push_string , ParseUser.getCurrentUser().getUsername()));

        push.sendInBackground();
    }
}

Harry James Ben Jakuben

2 Answers

Harry James
Harry James
14,780 Points

Hey Kevin!

The "freeze" your talking about comes from this line here:

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

Depending on the size of the file, it can take a long time to get all of the file bytes.

If you would like to "prevent" the freeze, you could set up an ASyncTask to get the bytes in the background.

Note that you do not want to run any code for creating the Parse file and attaching it to the message until the ASyncTask says it's complete. Only when it is complete should you do this and return the message. This will also mean you'll have to change your methods around a bit to make this possible.


If you get stuck along the way, give me a shout and I'll try to help out :)

Thanks a bunch. I also have another quick question relating to the camera crashing when I take a photo. One of the users was testing this out and the app crashed when they tried to send a picture using the TAKE PICTURE action. When I tried to take a picture and send it using that option it works fine. The user has the new android lollipop upgrade and I do not. Does this matter?

Harry James

Harry James
Harry James
14,780 Points

Hey Kevin!

No, that shouldn't matter. I am using Lollipop on my device and the Take Photo option works fine.

Is this another Treehouse user having the issue? If so, feel free to link me over to the forum post and I'll take a look at the problem (Or if you'd rather try and solve it yourself for them - do so!).

Ok no problem Harry I did.

I am going to share the link just in case we find the solution and other people have to same problem.

https://teamtreehouse.com/forum/choose-pic-and-video-works-take-pic-and-video-crash