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

Posted

技术标签:

【中文标题】Back4App 和 android studio,如何正确保存 ParseObject 错误【英文标题】:Back4App and android studio , How to properly save a ParseObject Error 【发布时间】:2021-08-07 10:50:03 【问题描述】:

这是我遇到的错误,由于我对 back4app 和 android studio 的理解非常有限(com.parse.ParseException: java.lang.IllegalStateException: Unable to对未保存的 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);
            
        );



    

这是我的帖子课程,其中一个特别之处是我在帖子课程中的关系。有一个包含对象评论的评论关系

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);

我的复习课

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$2$1.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$32.then(ParseObject.java:2282)
        at com.parse.ParseObject$32.then(ParseObject.java:2277)
        at com.parse.boltsinternal.Task$15.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$13.then(Task.java:816)
        at com.parse.boltsinternal.Task$13.then(Task.java:804)
        at com.parse.boltsinternal.Task$15.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.access$100(Task.java:28)
        at com.parse.boltsinternal.Task$11.then(Task.java:706)
        at com.parse.boltsinternal.Task$11.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$15$1.then(Task.java:924)
        at com.parse.boltsinternal.Task$15$1.then(Task.java:911)
        at com.parse.boltsinternal.Task$14.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$15.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.access$100(Task.java:28)
        at com.parse.boltsinternal.Task$11.then(Task.java:706)
        at com.parse.boltsinternal.Task$11.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$8.then(Task.java:562)
        at com.parse.boltsinternal.Task$8.then(Task.java:536)
        at com.parse.boltsinternal.Task$14.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$000(Task.java:28)
        at com.parse.boltsinternal.Task$10.then(Task.java:652)
        at com.parse.boltsinternal.Task$10.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$14.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$000(Task.java:28)
        at com.parse.boltsinternal.Task$10.then(Task.java:652)
        at com.parse.boltsinternal.Task$10.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$8.then(Task.java:552)
        at com.parse.boltsinternal.Task$8.then(Task.java:536)
        at com.parse.boltsinternal.Task$14.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$000(Task.java:28)
        at com.parse.boltsinternal.Task$10.then(Task.java:652)
        at com.parse.boltsinternal.Task$10.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$15$1.then(Task.java:922)
        at com.parse.boltsinternal.Task$15$1.then(Task.java:911)
        at com.parse.boltsinternal.Task$14.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$000(Task.java:28)
        at com.parse.boltsinternal.Task$10.then(Task.java:652)
        at com.parse.boltsinternal.Task$10.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$15$1.then(Task.java:922)
        at com.parse.boltsinternal.Task$15$1.then(Task.java:911)
        at com.parse.boltsinternal.Task$14.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$15.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.access$100(Task.java:28)
        at com.parse.boltsinternal.Task$11.then(Task.java:706)
        at com.parse.boltsinternal.Task$11.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$15$1.then(Task.java:922)
        at com.parse.boltsinternal.Task$15$1.then(Task.java:911)
        at com.parse.boltsinternal.Task$14.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$15.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)

【问题讨论】:

【参考方案1】:

您的问题发生是因为您没有等待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 ...
           
       );
    
);

【讨论】:

很抱歉,该解决方案对我不起作用。在我放置代码并替换它之后仍然是同样的错误。仍然说 java.lang.IllegalStateException: Unable to encoding an unsaved ParseFile。我认为文件可能有问题。 您检查过e 的值吗?也许第一个请求失败了。 问题已解决。路径错了!哈哈在我这边你的代码工作得很好

以上是关于Back4App 和 android studio,如何正确保存 ParseObject 错误的主要内容,如果未能解决你的问题,请参考以下文章

未收到在 Back4App 上解析的 Android 推送通知

从 android studio 在 bitnami Parse 服务器上设置电子邮件验证

back4App,使用alamofire查询

back4app 数据模型关系过滤

带有 Back4App 的 ios 推送通知证书

使用 Back4App 发送 ParsePush 通知