2016-02-15 1 views
4

Я пытаюсь обновить существующий RealmObject (IncidentCard), который включает RealmList типа IncidentPhoto. Объект обновляется без каких-либо проблем до тех пор, пока я не пытаться обновить RealmList, когда я включаю список, я получаю следующее сообщение об ошибке:Android Realm - Обновление триггеров RealmList IllegalArgumentException

E/AndroidRuntime: FATAL EXCEPTION: main 
E/AndroidRuntime: Process: com.trollvik.android.incidents247, PID: 31923 
E/AndroidRuntime: java.lang.IllegalArgumentException: Each element of 'value' must be a valid managed object. 
E/AndroidRuntime:  at io.realm.IncidentCardRealmProxy.setPhotos(IncidentCardRealmProxy.java:218) 
E/AndroidRuntime:  at com.trollvik.android.incidents247.activities.EditCardActivity.saveIncidentCard(EditCardActivity.java:155) 
E/AndroidRuntime:  at com.trollvik.android.incidents247.activities.EditCardActivity$1.onClick(EditCardActivity.java:95) 
E/AndroidRuntime:  at android.view.View.performClick(View.java:5197) 
E/AndroidRuntime:  at android.view.View$PerformClick.run(View.java:20926) 
E/AndroidRuntime:  at android.os.Handler.handleCallback(Handler.java:739) 
E/AndroidRuntime:  at android.os.Handler.dispatchMessage(Handler.java:95) 
E/AndroidRuntime:  at android.os.Looper.loop(Looper.java:145) 
E/AndroidRuntime:  at android.app.ActivityThread.main(ActivityThread.java:5944) 
E/AndroidRuntime:  at java.lang.reflect.Method.invoke(Native Method) 
E/AndroidRuntime:  at java.lang.reflect.Method.invoke(Method.java:372) 
E/AndroidRuntime:  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1388) 
E/AndroidRuntime:  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1183) 

Это класс IncidentCard:

public class IncidentCard extends RealmObject { 

    @PrimaryKey 
    private long id; 

    private String timestamp; 
    private String type; 
    private RealmList<IncidentPhoto> photos; 

    public IncidentCard() { 

    } 

    public IncidentCard(long id, String timestamp, String type){ 
    this.id = id; 
    this.timestamp = timestamp; 
    this.type = type; 
    } 

    public IncidentCard(long id, String timestamp, String type, RealmList<IncidentPhoto> photos){ 
    this.id = id; 
    this.timestamp = timestamp; 
    this.type = type; 
    this.photos = photos; 
    } 

    public long getId() { 
    return this.id; 
    } 

    public void setId(long id) { 
    this.id = id; 
    } 

    public String getTimestamp(){ 
    return this.timestamp; 
    } 

    public void setTimestamp(String timestamp) { 
    this.timestamp = timestamp; 
    } 

    public String getType(){ 
    return this.type; 
    } 

    public void setType(String type){ 
    this.type = type; 
    } 

    public RealmList<IncidentPhoto> getPhotos() { 
    return this.photos; 
    } 

    public void setPhotos(RealmList<IncidentPhoto> photos) { 
    this.photos = photos; 
    } 
} 

Это класс IncidentPhoto:

public class IncidentPhoto extends RealmObject { 

    private String photoPath; 

    public IncidentPhoto() { 

    } 

    public IncidentPhoto(String photoPath) { 
    this.photoPath = photoPath; 
    } 

    public String getPhotoPath(){ 
    return this.photoPath; 
    } 

    public void setPhotoPath(String photoPath){ 
    this.photoPath = photoPath; 
    } 
} 

Для запроса Realm DB Я создал этот вспомогательный класс:

public class IncidentDbHelper { 

    private Realm realm; 

    public IncidentDbHelper(Context context) { 
    realm = Realm.getInstance(context); 
    } 

    public void setObject(IncidentCard incidentCard) { 
    realm.beginTransaction(); 
    IncidentCard incident = realm.copyToRealmOrUpdate(incidentCard); 
    realm.commitTransaction(); 
    } 

    public IncidentCard getObject(Long id) { 
    return realm.where(IncidentCard.class).equalTo("id", id).findFirst(); 
    } 

    public void close(){ 
    if (realm != null) { 
     realm.close(); 
    } 
    } 
} 

Когда я добавить новую карту падающего я называю эту деятельность:

public class NewCardActivity extends AppCompatActivity { 

    private static final int REQUEST_IMAGE_CAPTURE = 1; 
    private static final String INSTANCE_STATE = "currentPhotoPath"; 
    private static final String INSTANCE_STATE_LIST = "currentPhotoList"; 

    private Context mContext; 

    private IncidentCard mIncidentCard; 

    private IncidentDbHelper mDbHelper; 
    private IncidentCardId mIncidentId; 
    private IncidentCardTimestamp mIncidentTimestamp; 
    private RealmConverter mRealmConverter; 

    private Resources mRes; 
    private PhotoPath mPath; 

    private String mCurrentPhotoPath; 
    private ArrayList<String> mCurrentPhotoList; 



    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 

    mContext = this; 
    mDbHelper = new IncidentDbHelper(mContext); 
    mIncidentCard = new IncidentCard(); 
    mRealmConverter = new RealmConverter(); 
    mCurrentPhotoList = new ArrayList<String>(); 
    mIncidentId = new IncidentCardId(); 
    mIncidentTimestamp = new IncidentCardTimestamp(); 
    mRes = getResources(); 
    mPath = new PhotoPath(); 

    // If savedInstanceState is empty, ignore this code. 
    if(savedInstanceState != null){ 
     mCurrentPhotoPath = savedInstanceState.getString(INSTANCE_STATE); 
     mCurrentPhotoList = savedInstanceState.getStringArrayList(INSTANCE_STATE_LIST); 
    } 
    } 

    protected void saveIncidentCard(){ 
    Realm realm = Realm.getInstance(this); 
    Spinner spinner = (Spinner) findViewById(R.id.content_new_card_type); 
    String incidentType = spinner.getSelectedItem().toString(); 

    realm.beginTransaction(); 
    mIncidentCard.setId(mIncidentId.getNewId()); 
    mIncidentCard.setTimestamp(mIncidentTimestamp.getNewTimestamp()); 
    mIncidentCard.setType(incidentType); 
    mIncidentCard.setPhotos(mRealmConverter.toRealmList(mCurrentPhotoList)); 
    realm.commitTransaction(); 

    mDbHelper.setObject(mIncidentCard); 
    } 

    @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_new_card, menu); 
    return true; 
    } 

    @Override 
    public boolean onOptionsItemSelected(MenuItem item) { 
    switch (item.getItemId()) { 
     case R.id.menu_new_photo: 
      dispatchTakePictureIntent(); 

     default: 
      // If we got here, the user's action was not recognized. 
      // Invoke the superclass to handle it. 
      return super.onOptionsItemSelected(item); 

    } 
    } 


    private void dispatchTakePictureIntent() { 
    Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); 
    File imageFile = null; 

    // Ensure that there's a camera activity to handle the intent 
    if (takePictureIntent.resolveActivity(getPackageManager()) != null) { 
     // Create the File where the photo should go 
     try { 
      imageFile = mPath.createImageFile(); 
      mCurrentPhotoPath = imageFile.getAbsolutePath(); 
     } catch (java.io.IOException e) { 
      Log.e(TAG, e.toString()); 
     } 

     // Continue only if the File was successfully created 
     if (imageFile != null) { 
      takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, 
        Uri.fromFile(imageFile.getAbsoluteFile())); 
      startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE); 
     } 
    } 
    } 

    @Override 
    public void onSaveInstanceState(Bundle savedInstanceState) { 
    super.onSaveInstanceState(savedInstanceState); 
    savedInstanceState.putString(INSTANCE_STATE, mCurrentPhotoPath); 
    savedInstanceState.putStringArrayList(INSTANCE_STATE_LIST, mCurrentPhotoList); 
    } 

    @Override 
    protected void onActivityResult(int requestCode, int resultCode, Intent data) { 
    if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) { 
     mCurrentPhotoList.add(mCurrentPhotoPath); 
    } 
    } 

    @Override 
    protected void onDestroy() { 
    super.onDestroy(); 
    mDbHelper.close(); 
    } 
} 

В то время как я захватить новые фотографии, которые я сохранить пути ранее захваченные фотографии в ArrayList типа String. Прежде чем я установил список путей к объекту IncidentCard, я конвертирую список в RealmList. Кажется, эта часть работает нормально.

Проблема возникает после того, как я пытаюсь сохранить существующий объект в EditCardActivity:

public class EditCardActivity extends AppCompatActivity { 

    private static final String INTENT_EXTRA = "EXTRA_INCIDENT_ID"; 
    private static final int REQUEST_IMAGE_CAPTURE = 2; 
    private static final String INSTANCE_STATE = "currentPhotoPath"; 
    private static final String INSTANCE_STATE_LIST = "currentPhotoList"; 

    private Context mContext; 
    private Long mIncidentId; 
    private IncidentCard mIncidentCard; 
    private IncidentDbHelper mDbHelper; 

    private IncidentCardTimestamp mIncidentTimestamp; 
    private RealmConverter mRealmConverter; 

    private Resources mRes; 
    private PhotoPath mPath; 

    Spinner mSpinnerType; 
    private String mCurrentPhotoPath; 
    private ArrayList<String> mCurrentPhotoList; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    mRealmConverter = new RealmConverter(); 

    mContext = this; 
    mDbHelper = new IncidentDbHelper(mContext); 
    mIncidentCard = new IncidentCard(); 
    mCurrentPhotoList = new ArrayList<String>(); 
    mIncidentTimestamp = new IncidentCardTimestamp(); 
    mRes = getResources(); 
    mPath = new PhotoPath(); 

    // If savedInstanceState is empty, ignore this code. 
    if(savedInstanceState != null){ 
     mCurrentPhotoPath = savedInstanceState.getString(INSTANCE_STATE); 
     mCurrentPhotoList = savedInstanceState.getStringArrayList(INSTANCE_STATE_LIST); 
    } 

    FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab); 
    fab.setOnClickListener(new View.OnClickListener() { 
     @Override 
     public void onClick(View view) { 
      saveIncidentCard(); 
      finish(); 
     } 
    }); 

    // Get Incident ID passed from Main Activity 
    Intent intent = getIntent(); 
    mIncidentId = intent.getLongExtra(INTENT_EXTRA, 0); 

    mIncidentCard = mDbHelper.getObject(mIncidentId); 

    mTextViewId = (TextView) findViewById(R.id.content_edit_card_id); 
    mSpinnerType = (Spinner) findViewById(R.id.content_edit_card_type); 

    ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, 
      android.R.layout.simple_spinner_dropdown_item, items); 
    mSpinnerType.setAdapter(adapter); 
    String compareValue = mIncidentCard.getType(); 
    if (!compareValue.equals(null)) { 
     int spinnerPosition = adapter.getPosition(compareValue); 
     mSpinnerType.setSelection(spinnerPosition); 
    } 

    mCurrentPhotoList = mRealmConverter.toArrayList(mIncidentCard.getPhotos()); 
    } 

    protected void saveIncidentCard(){ 
    Realm realm = Realm.getInstance(this); 
    Spinner spinner = (Spinner) findViewById(R.id.content_edit_card_type); 

    String incidentType = spinner.getSelectedItem().toString(); 

    realm.beginTransaction(); 
    mIncidentCard.setTimestamp(mIncidentTimestamp.getNewTimestamp()); 
    mIncidentCard.setType(incidentType); 
    mIncidentCard.setPhotos(mRealmConverter.toRealmList(mCurrentPhotoList)); 
    realm.commitTransaction(); 

    mDbHelper.setObject(mIncidentCard); 
    } 

    @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_edit_card, menu); 
    return true; 
    } 

    @Override 
    public boolean onOptionsItemSelected(MenuItem item) { 
    switch (item.getItemId()) { 
     case R.id.menu_edit_photo: 
      dispatchTakePictureIntent(); 

     default: 
      // If we got here, the user's action was not recognized. 
      // Invoke the superclass to handle it. 
      return super.onOptionsItemSelected(item); 

    } 
    } 


    private void dispatchTakePictureIntent() { 
    Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); 
    File imageFile = null; 

    // Ensure that there's a camera activity to handle the intent 
    if (takePictureIntent.resolveActivity(getPackageManager()) != null) { 
     // Create the File where the photo should go 
     try { 
      imageFile = mPath.createImageFile(); 
      mCurrentPhotoPath = imageFile.getAbsolutePath(); 
     } catch (java.io.IOException e) { 
      Log.e(TAG, e.toString()); 
     } 

     // Continue only if the File was successfully created 
     if (imageFile != null) { 
      takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, 
        Uri.fromFile(imageFile.getAbsoluteFile())); 
      startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE); 
     } 
    } 
    } 

    @Override 
    public void onSaveInstanceState(Bundle savedInstanceState) { 
    super.onSaveInstanceState(savedInstanceState); 
    savedInstanceState.putString(INSTANCE_STATE, mCurrentPhotoPath); 
    savedInstanceState.putStringArrayList(INSTANCE_STATE_LIST, mCurrentPhotoList); 
    } 

    @Override 
    protected void onActivityResult(int requestCode, int resultCode, Intent data) { 
    if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) { 
     mCurrentPhotoList.add(mCurrentPhotoPath); 
    } 
    } 

    @Override 
    protected void onDestroy() { 
    super.onDestroy(); 
    mDbHelper.close(); 
    } 
} 

Так что, если я закомментировать mIncidentCard.setPhotos() все, кажется, работает хорошо, но когда я пытаюсь установить фотографии к объекту IncidentCard запускается IllegalArgumentException.

Это метод, который я создал для преобразования ArrayLists в RealmLists:

public RealmList<IncidentPhoto> toRealmList(ArrayList<String> arrayList){ 
    mRealmList = new RealmList<IncidentPhoto>(); 
    for (int i = 0; i < arrayList.size(); i++){ 
     IncidentPhoto incidentPhoto = new IncidentPhoto(); 
     incidentPhoto.setPhotoPath(arrayList.get(i)); 
     mRealmList.add(incidentPhoto); 
    } 
    return mRealmList; 
} 

Я боролся с этим на некоторое время, и теперь я не понимаю, что я делаю неправильно, поэтому любая помощь будет с благодарностью.

Realm Exception 'value' is not a valid managed object Realm Java Doc

+0

Похоже, Вы пытаетесь добавить список строк, когда он требует списка Объекты IncidentPhoto. Я не думаю, что преобразование Arraylist в Realmlist преобразует строки в объекты IncidentPhoto. – TP89

+0

Ну, я использую тот же метод для преобразования ArrayList в RealmList в NewCardActivity, и он отлично работает. Пути сохранены, и я могу преобразовать каждую фотографию в растровые изображения в MainActivity. Fyi, я включил метод toRealmList() выше. –

ответ

9

Проблема заключается в том, при вызове сеттеры, чтобы установить RealmList, каждый элемент в списке должен управляться Realm уже.

Похожий вопрос здесь Adding standalone-objects to a RealmList

Вы можете изменить toRealmList, как показано ниже:

public RealmList<IncidentPhoto> toRealmList(Realm realm, ArrayList<String> arrayList) { 
    mRealmList = new RealmList<IncidentPhoto>(); 
    for (int i = 0; i < arrayList.size(); i++){ 
     // Create a IncidentPhoto object which is managed by Realm. 
     IncidentPhoto incidentPhoto = realm.createObject(IncidentPhoto.class); 
     incidentPhoto.setPhotoPath(arrayList.get(i)); 
     mRealmList.add(incidentPhoto); 
    } 
    return mRealmList; 
} 

или

public RealmList<IncidentPhoto> toRealmList(Realm realm, ArrayList<String> arrayList) { 
    mRealmList = new RealmList<IncidentPhoto>(); 
    for (int i = 0; i < arrayList.size(); i++){ 
     IncidentPhoto incidentPhoto = new IncidentPhoto(); 
     incidentPhoto.setPhotoPath(arrayList.get(i)); 
     // Copy the standalone object to Realm, and get the returned object which is managed by Realm. 
     incidentPhoto = realm.copyToRealm(incidentPhoto); 
     mRealmList.add(incidentPhoto); 
    } 
    return mRealmList; 
} 
+0

Он отлично работал! Спасибо! :) –

Смежные вопросы