Back4App 和 android studio,如何正确保存 ParseObject 错误

Back4App and android studio , How to properly save a ParseObject Error

这是我 运行 遇到的错误,由于我对 back4app 和 android studio 的理解非常有限(com.parse.ParseException:java.lang.IllegalStateException:无法对未保存的 ParseFile 进行编码。)。 我尝试过的一些解决方案是不可行的,而且似乎是 ParseFile 没有正确保存。我已经尝试了回调函数和进度函数,但似乎没有用。所以在这一点上我不知道如何解决这个问题 这是我撰写片段的代码

package com.example.rentahome.fragments;

import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.ImageDecoder;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.text.SpannableStringBuilder;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.FileProvider;
import androidx.fragment.app.Fragment;

import com.example.rentahome.ImageFilePath;
import com.example.rentahome.Post;
import com.example.rentahome.R;
import com.example.rentahome.Reviews;
import com.example.rentahome.databinding.FragmentComposeBinding;
import com.parse.Parse;
import com.parse.ParseException;
import com.parse.ParseFile;
import com.parse.ParseObject;
import com.parse.ParseRelation;
import com.parse.ParseUser;
import com.parse.ProgressCallback;
import com.parse.SaveCallback;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;

import static android.app.Activity.RESULT_OK;
import static com.parse.Parse.getApplicationContext;

public class ComposeFragment extends Fragment {
    public static final int CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE = 43;
    public static final int PICK_PHOTO_CODE = 21;

    private File photoFile;
    FragmentComposeBinding fragmentComposeBinding;
    private String photoFileName = "photo.jpg";
    public String realPath = new String();
    public static final String TAG = "ComposeFragment";

    public ComposeFragment() {
        // Required empty public constructor
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_compose, container, false);

    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        fragmentComposeBinding = FragmentComposeBinding.bind(view);
        fragmentComposeBinding.btnPicture.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                uploadImage();
            }
        });

        fragmentComposeBinding.btnSubmit.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String address = fragmentComposeBinding.etAddress.getText().toString();
                String price = fragmentComposeBinding.etPrice.getText().toString();
                String description = fragmentComposeBinding.etDescription.getText().toString();
                if(address.isEmpty()){
                    Toast.makeText(getContext(), "Address cannot be empty", Toast.LENGTH_SHORT).show();
                    return;
                }
                if(price.isEmpty()){
                    Toast.makeText(getContext(), "Price cannot be empty", Toast.LENGTH_SHORT).show();
                    return;
                }
                if(description.isEmpty()){
                    Toast.makeText(getContext(), "Description cannot be empty", Toast.LENGTH_SHORT).show();
                    return;
                }
                if(realPath == null || fragmentComposeBinding.ivPostImage.getDrawable()==null){
                    Toast.makeText(getContext(),"There is no image", Toast.LENGTH_SHORT).show();
                    return;
                }
                ParseUser currentUser = ParseUser.getCurrentUser();
                savePost(address, price, description, currentUser);
            }
        });
    }

    private void uploadImage() {
        // create Intent to upload a picture and return control to the calling application
        // Edit action for MediaStore


        Intent intent = new Intent(Intent.ACTION_PICK,
                MediaStore.Images.Media.EXTERNAL_CONTENT_URI);

        // Create a File reference for future access
        //photoFile = getPhotoFileUri(photoFileName);

        // wrap File object into a content provider
        // required for API >= 24
        // See https://guides.codepath.com/android/Sharing-Content-with-Intents#sharing-files-with-api-24-or-higher
        //Uri fileProvider = FileProvider.getUriForFile(getContext(), "com.example.rentahome.fileprovider", photoFile);
        //intent.putExtra(MediaStore.EXTRA_OUTPUT, fileProvider);

        // If you call startActivityForResult() using an intent that no app can handle, your app will crash.
        // So as long as the result is not null, it's safe to use the intent.
        if (intent.resolveActivity(getContext().getPackageManager()) != null) {
            // Start the image pick intent to pick photo from external folder
            startActivityForResult(intent, PICK_PHOTO_CODE);
        }
    }
    public Bitmap loadFromUri(Uri photoUri) {
        Bitmap image = null;
        try {
            // check version of Anrdoid on device
            if(Build.VERSION.SDK_INT > 27) {
                // newer version
                ImageDecoder.Source source = ImageDecoder.createSource(this.getContext().getContentResolver(), photoUri);
                image = ImageDecoder.decodeBitmap(source);
            } else {
                //support older
                image = MediaStore.Images.Media.getBitmap(this.getContext().getContentResolver(),photoUri);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return image;
    }

    private File getPhotoFileUri(String fileName) {
        // Get safe storage directory for photos
        // Use `getExternalFilesDir` on Context to access package-specific directories.
        // This way, we don't need to request external read/write runtime permissions.
        File mediaStorageDir = new File(getContext().getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), TAG);

        // Create the storage directory if it does not exist
        if (!mediaStorageDir.exists() && !mediaStorageDir.mkdirs()){
            Log.d(TAG, "failed to create directory..");
        }

        // Return the file target for the photo based on filename
        File file = new File(mediaStorageDir.getPath() + File.separator + fileName);

        return file;
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        if (requestCode == PICK_PHOTO_CODE && resultCode == RESULT_OK && data != null && data.getData() != null) {

            Uri uri = data.getData();


            realPath = ImageFilePath.getPath(getContext(), data.getData());
//                realPath = RealPathUtil.getRealPathFromURI_API19(this, data.getData());

            Log.i(TAG, "onActivityResult: file path : " + realPath);
            Log.i(TAG, "onActivityResult: file path : " + getContext().getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).getPath() );
            try {

                Bitmap bitmap = MediaStore.Images.Media.getBitmap(this.getContext().getContentResolver(), uri);
                // Log.d(TAG, String.valueOf(bitmap));
                fragmentComposeBinding.ivPostImage.setImageBitmap(bitmap);
            } catch (IOException e) {
                e.printStackTrace();
            }
        } else {
            Toast.makeText(getContext(), "Something Went Wrong", Toast.LENGTH_SHORT).show();
        }

//        if ((data != null) && requestCode == PICK_PHOTO_CODE) {
//            if (resultCode == RESULT_OK) {
//                Uri photoUri = data.getData();
//                // by this point we have the camera photo on disk
//                //Bitmap selectedImage = BitmapFactory.decodeFile(photoFile.getAbsolutePath());
//                //Load the image located at photoUri into selectedImage
//                Bitmap selectedImage = loadFromUri(photoUri);
//                // RESIZE BITMAP, see section below
//                // Load the taken image into a preview
//                fragmentComposeBinding.ivPostImage.setImageBitmap(selectedImage);
//
//            } else { // Result was a failure
//                Toast.makeText(getContext(), "Image not found", Toast.LENGTH_SHORT).show();
//            }
//        }
    }



    private void savePost(String address, String price, String description, ParseUser currentUser) {
        //Post post = new Post();
        ParseObject post = ParseObject.create("Post");

        File file = new File(realPath);


        ParseFile photo = new ParseFile(file);

        photo.saveInBackground();
//        post.setImage(photo);
//        int parsed_price = Integer.parseInt(price);
//        post.setPrice(parsed_price);
//        post.setDescription(description);
//        post.setUser(currentUser);
//        post.setAddress(address);
//        //photo.saveInBackground();
        ParseRelation<ParseObject> hi;
        //parse String price to int..
        post.put("image",photo);
        post.put("description",description);
        post.put("address",address);
        post.put("user",currentUser);
        post.put("price",price);
        //post.put("Reviews",hi);

//        Reviews gameScore = new Reviews();
//
//        gameScore.setlikesCount(0);
//        gameScore.setdislikesCount(0);
//        gameScore.setAuthor(currentUser);
//        gameScore.setRating((float) (5.0));
//        gameScore.setDescription("hi");
////
////        gameScore.put("Description","Hi ");
////        gameScore.put("author",currentUser);
////        gameScore.put("rating",(float)(5.0));
////        gameScore.put("likesCount",0);
////        gameScore.put("dislikesCount",0);
//
//        ParseRelation<Reviews> temp = new ParseRelation<Reviews>();
//        temp.add(gameScore);

        post.saveInBackground(new SaveCallback() {
            @Override
            public void done(com.parse.ParseException e) {
                if(e!=null){
                    Log.e(TAG,"Issue with saving posts..", e);
                    Toast.makeText(getContext(), "Error while saving", Toast.LENGTH_SHORT).show();
                    return;
                }
                Log.i(TAG,"Saved successfully!");
                fragmentComposeBinding.etDescription.setText("");
                fragmentComposeBinding.ivPostImage.setImageResource(0);
            }
        });



    }
}

这是我的 post class,它的特别之处之一是我在 post class 中的关系。有一个包含对象 reviews

的 reviews 关系
package com.example.rentahome;

import com.parse.ParseClassName;
import com.parse.ParseFile;
import com.parse.ParseObject;
import com.parse.ParseRelation;
import com.parse.ParseUser;

import java.util.ArrayList;

@ParseClassName("Post")
public class Post extends ParseObject {
    public static final String KEY_DESCRIPTION = "description";
    public static final String KEY_IMAGE = "image";     //image should be 'uploaded'
    public static final String KEY_USER = "user";
    public static final String KEY_CREATED_KEY = "createdAt"; //have to figure out how to implement
    public static final String KEY_address = "address";
    public static final String KEY_price = "price";
    public static final String KEY_reviews = "Reviews";
    public static final String KEY_objectID = "objectID";

    public String getDescription(){
        return getString(KEY_DESCRIPTION);
    }
    public void setDescription(String description){
        put(KEY_DESCRIPTION, description);
    }

    public ParseFile getImage(){
        return getParseFile(KEY_IMAGE);
    }
    public void setImage(ParseFile parseFile){
        put(KEY_IMAGE, parseFile);
    }

    public ParseUser getUser(){
        return getParseUser(KEY_USER);
    }
    public void setUser(ParseUser user){put(KEY_USER, user);}

    public String getAddress() {return getString(KEY_address);}
    public void setAddress(String address){ put(KEY_address, address);}

    public int getPrice(){return getInt(KEY_price);}
    public void setPrice(int price){put(KEY_price,price);}
    public String getobjectID(){return getString(KEY_objectID);}

    public ParseRelation<ParseObject>  getrelation() {return getRelation(KEY_reviews);}
    public void setrelation(ParseRelation<ParseObject>  relation){put(KEY_reviews, relation);}

    //public ParseRelation<ParseObject> getReviews(){return getRelation(KEY_reviews);}
    //public void setReviews(ParseRelation<ParseObject> reviews){put(KEY_reviews, reviews);}

    //public Date getCreatedAt() { return getDate(KEY_CREATED_KEY);}

我的评论class

package com.example.rentahome;

import com.parse.ParseClassName;
import com.parse.ParseObject;
import com.parse.ParseUser;

@ParseClassName("Reviews")
public class Reviews extends ParseObject {
    public static final String KEY_author = "author";
    public static final String KEY_description = "Description";
    public static final String KEY_likesCount = "likesCount";
    public static final String KEY_dislikesCount = "dislikesCount";
    public static final String KEY_rating = "rating";



    public String getDescription(){return getString(KEY_description);}
    public void setDescription(String description){put(KEY_description, description);}
    public ParseUser getAuthor(){return getParseUser(KEY_author); }
    public void setAuthor(ParseUser author){put(KEY_author,author);}
    public float getRating(){return (float)getDouble(KEY_rating);}
    public void setRating(float rating) {put(KEY_rating, rating);}
    public int getlikesCount() {return getInt(KEY_likesCount);}
    public void setlikesCount(int likesCount){put(KEY_likesCount, likesCount);}
    public int getdislikesCount() {return getInt(KEY_dislikesCount);}
    public void setdislikesCount(int dislikesCount){put(KEY_dislikesCount, dislikesCount);}
}

这是错误信息

E/ComposeFragment: Issue with saving posts..
    com.parse.ParseException: java.lang.IllegalStateException: Unable to encode an unsaved ParseFile.
        at com.parse.ParseTaskUtils.run(ParseTaskUtils.java:119)
        at android.os.Handler.handleCallback(Handler.java:938)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:223)
        at android.app.ActivityThread.main(ActivityThread.java:7656)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
     Caused by: java.lang.IllegalStateException: Unable to encode an unsaved ParseFile.
        at com.parse.ParseFile.encode(ParseFile.java:653)
        at com.parse.ParseEncoder.encode(ParseEncoder.java:77)
        at com.parse.ParseSetOperation.encode(ParseSetOperation.java:31)
        at com.parse.ParseEncoder.encode(ParseEncoder.java:126)
        at com.parse.ParseObjectCoder.encode(ParseObjectCoder.java:57)
        at com.parse.NetworkObjectController.saveAsync(NetworkObjectController.java:60)
        at com.parse.ParseObject.then(ParseObject.java:2282)
        at com.parse.ParseObject.then(ParseObject.java:2277)
        at com.parse.boltsinternal.Task.run(Task.java:907)
        at com.parse.boltsinternal.BoltsExecutors$ImmediateExecutor.execute(BoltsExecutors.java:113)
        at com.parse.boltsinternal.Task.completeAfterTask(Task.java:898)
        at com.parse.boltsinternal.Task.continueWithTask(Task.java:713)
        at com.parse.boltsinternal.Task.continueWithTask(Task.java:724)
        at com.parse.boltsinternal.Task.then(Task.java:816)
        at com.parse.boltsinternal.Task.then(Task.java:804)
        at com.parse.boltsinternal.Task.run(Task.java:907)
        at com.parse.boltsinternal.BoltsExecutors$ImmediateExecutor.execute(BoltsExecutors.java:113)
        at com.parse.boltsinternal.Task.completeAfterTask(Task.java:898)
        at com.parse.boltsinternal.Task.access0(Task.java:28)
        at com.parse.boltsinternal.Task.then(Task.java:706)
        at com.parse.boltsinternal.Task.then(Task.java:703)
        at com.parse.boltsinternal.Task.runContinuations(Task.java:946)
        at com.parse.boltsinternal.Task.trySetResult(Task.java:984)
        at com.parse.boltsinternal.TaskCompletionSource.trySetResult(TaskCompletionSource.java:45)
        at com.parse.boltsinternal.TaskCompletionSource.setResult(TaskCompletionSource.java:68)
        at com.parse.boltsinternal.Task.then(Task.java:924)
        at com.parse.boltsinternal.Task.then(Task.java:911)
        at com.parse.boltsinternal.Task.run(Task.java:866)
        at com.parse.boltsinternal.BoltsExecutors$ImmediateExecutor.execute(BoltsExecutors.java:113)
        at com.parse.boltsinternal.Task.completeImmediately(Task.java:857)
        at com.parse.boltsinternal.Task.continueWith(Task.java:659)
        at com.parse.boltsinternal.Task.continueWith(Task.java:670)
        at com.parse.boltsinternal.Task.run(Task.java:911)
        at com.parse.boltsinternal.BoltsExecutors$ImmediateExecutor.execute(BoltsExecutors.java:113)
        at com.parse.boltsinternal.Task.completeAfterTask(Task.java:898)
        at com.parse.boltsinternal.Task.access0(Task.java:28)
        at com.parse.boltsinternal.Task.then(Task.java:706)
        at com.parse.boltsinternal.Task.then(Task.java:703)
        at com.parse.boltsinternal.Task.runContinuations(Task.java:946)
        at com.parse.boltsinternal.Task.trySetResult(Task.java:984)
        at com.parse.boltsinternal.TaskCompletionSource.trySetResult(TaskCompletionSource.java:45)
        at com.parse.boltsinternal.TaskCompletionSource.setResult(TaskCompletionSource.java:68)
        at com.parse.boltsinternal.Task.then(Task.java:562)
        at com.parse.boltsinternal.Task.then(Task.java:536)
        at com.parse.boltsinternal.Task.run(Task.java:866)
        at com.parse.boltsinternal.BoltsExecutors$ImmediateExecutor.execute(BoltsExecutors.java:113)
        at com.parse.boltsinternal.Task.completeImmediately(Task.java:857)
        at com.parse.boltsinternal.Task.access[=14=]0(Task.java:28)
        at com.parse.boltsinternal.Task.then(Task.java:652)
        at com.parse.boltsinternal.Task.then(Task.java:649)
E/ComposeFragment:     at com.parse.boltsinternal.Task.runContinuations(Task.java:946)
        at com.parse.boltsinternal.Task.trySetResult(Task.java:984)
        at com.parse.boltsinternal.TaskCompletionSource.trySetResult(TaskCompletionSource.java:45)
        at com.parse.boltsinternal.TaskCompletionSource.setResult(TaskCompletionSource.java:68)
        at com.parse.boltsinternal.Task.run(Task.java:867)
        at com.parse.boltsinternal.BoltsExecutors$ImmediateExecutor.execute(BoltsExecutors.java:113)
        at com.parse.boltsinternal.Task.completeImmediately(Task.java:857)
        at com.parse.boltsinternal.Task.access[=14=]0(Task.java:28)
        at com.parse.boltsinternal.Task.then(Task.java:652)
        at com.parse.boltsinternal.Task.then(Task.java:649)
        at com.parse.boltsinternal.Task.runContinuations(Task.java:946)
        at com.parse.boltsinternal.Task.trySetError(Task.java:1001)
        at com.parse.boltsinternal.TaskCompletionSource.trySetError(TaskCompletionSource.java:52)
        at com.parse.boltsinternal.TaskCompletionSource.setError(TaskCompletionSource.java:77)
        at com.parse.boltsinternal.Task.then(Task.java:552)
        at com.parse.boltsinternal.Task.then(Task.java:536)
        at com.parse.boltsinternal.Task.run(Task.java:866)
        at com.parse.boltsinternal.BoltsExecutors$ImmediateExecutor.execute(BoltsExecutors.java:113)
        at com.parse.boltsinternal.Task.completeImmediately(Task.java:857)
        at com.parse.boltsinternal.Task.access[=14=]0(Task.java:28)
        at com.parse.boltsinternal.Task.then(Task.java:652)
        at com.parse.boltsinternal.Task.then(Task.java:649)
        at com.parse.boltsinternal.Task.runContinuations(Task.java:946)
        at com.parse.boltsinternal.Task.trySetError(Task.java:1001)
        at com.parse.boltsinternal.TaskCompletionSource.trySetError(TaskCompletionSource.java:52)
        at com.parse.boltsinternal.TaskCompletionSource.setError(TaskCompletionSource.java:77)
        at com.parse.boltsinternal.Task.then(Task.java:922)
        at com.parse.boltsinternal.Task.then(Task.java:911)
        at com.parse.boltsinternal.Task.run(Task.java:866)
        at com.parse.boltsinternal.BoltsExecutors$ImmediateExecutor.execute(BoltsExecutors.java:113)
        at com.parse.boltsinternal.Task.completeImmediately(Task.java:857)
        at com.parse.boltsinternal.Task.access[=14=]0(Task.java:28)
        at com.parse.boltsinternal.Task.then(Task.java:652)
        at com.parse.boltsinternal.Task.then(Task.java:649)
        at com.parse.boltsinternal.Task.runContinuations(Task.java:946)
        at com.parse.boltsinternal.Task.trySetError(Task.java:1001)
        at com.parse.boltsinternal.TaskCompletionSource.trySetError(TaskCompletionSource.java:52)
        at com.parse.boltsinternal.TaskCompletionSource.setError(TaskCompletionSource.java:77)
        at com.parse.boltsinternal.Task.then(Task.java:922)
        at com.parse.boltsinternal.Task.then(Task.java:911)
        at com.parse.boltsinternal.Task.run(Task.java:866)
        at com.parse.boltsinternal.BoltsExecutors$ImmediateExecutor.execute(BoltsExecutors.java:113)
        at com.parse.boltsinternal.Task.completeImmediately(Task.java:857)
        at com.parse.boltsinternal.Task.continueWith(Task.java:659)
        at com.parse.boltsinternal.Task.continueWith(Task.java:670)
        at com.parse.boltsinternal.Task.run(Task.java:911)
        at com.parse.boltsinternal.BoltsExecutors$ImmediateExecutor.execute(BoltsExecutors.java:113)
        at com.parse.boltsinternal.Task.completeAfterTask(Task.java:898)
        at com.parse.boltsinternal.Task.access0(Task.java:28)
        at com.parse.boltsinternal.Task.then(Task.java:706)
        at com.parse.boltsinternal.Task.then(Task.java:703)
        at com.parse.boltsinternal.Task.runContinuations(Task.java:946)
        at com.parse.boltsinternal.Task.trySetError(Task.java:1001)
        at com.parse.boltsinternal.TaskCompletionSource.trySetError(TaskCompletionSource.java:52)
        at com.parse.boltsinternal.TaskCompletionSource.setError(TaskCompletionSource.java:77)
        at com.parse.boltsinternal.Task.then(Task.java:922)
        at com.parse.boltsinternal.Task.then(Task.java:911)
        at com.parse.boltsinternal.Task.run(Task.java:866)
        at com.parse.boltsinternal.BoltsExecutors$ImmediateExecutor.execute(BoltsExecutors.java:113)
        at com.parse.boltsinternal.Task.completeImmediately(Task.java:857)
        at com.parse.boltsinternal.Task.continueWith(Task.java:659)
        at com.parse.boltsinternal.Task.continueWith(Task.java:670)
        at com.parse.boltsinternal.Task.run(Task.java:911)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
        at java.lang.Thread.run(Thread.java:923)

出现问题是因为您没有等待 photo.saveInBackground 完成。您的代码应如下所示:

ParseObject post = ParseObject.create("Post");
File file = new File(realPath);
ParseFile photo = new ParseFile(file);
photo.saveInBackground(new SaveCallback() {
   @Override
   public void done(com.parse.ParseException e) {
       // Handle success or failure here ...
       post.put("image",photo);
       post.put("description",description);
       post.put("address",address);
       post.put("user",currentUser);
       post.put("price",price);
    
       post.saveInBackground(new SaveCallback() {
           @Override
           public void done(com.parse.ParseException e) {
               // Handle success or failure here ...
           }
       });
    }
});