I have an error when using a Parcelable Class.
I'm trying to pass an image as a ByteArray between activities, and eventually to a remote webservice.
java.lang.ClassNotFoundException: ...
Class not found when unmarshalling:
import java.util.UUID;
public class Property implements Parcelable {
#SerializedName("id")
#NonNull
private final String mId;
protected byte[] mImage;
public byte[] getmImage() { return mImage; }
public void setmImage(byte[] image){ mImage = image; }
#SerializedName("generalInformation")
private GeneralInformation mGeneralInformation;
#NonNull
public GeneralInformation getGeneralInformation() {
return mGeneralInformation;
}
public void setGeneralInformation(#NonNull final GeneralInformation generalInformation) {
mGeneralInformation = generalInformation;
}
#NonNull
public String getId() {
return mId;
}
#Override
public boolean equals(final Object o) {
return (o instanceof Property) && ((Property) o).mId.equals(mId);
}
#Override
public int hashCode() {
return mId.hashCode();
}
public static Property create() {
final Property model = new Property(UUID.randomUUID().toString());
model.setGeneralInformation(new GeneralInformation());
return model;
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(#NonNull final Parcel dest, final int flags) {
if(mImage != null) {
dest.writeInt(mImage.length);
dest.writeByteArray(mImage);
}
dest.writeString(mId);
dest.writeParcelable(mGeneralInformation, 0);
}
private Property(#NonNull final String id) {
mId = id;
}
protected Property(final Parcel in) {
if(mImage != null)
{
mImage = new byte[in.readInt()];
in.createByteArray();
}
mId = in.readString();
mGeneralInformation = in.readParcelable(GeneralInformation.class.getClassLoader());
}
public static final Parcelable.Creator<Property> CREATOR = new Parcelable.Creator<Property>() {
public Property createFromParcel(#NonNull final Parcel source) {
return new Property(source);
}
#NonNull
public Property[] newArray(final int size) {
return new Property[size];
}
};
}
Now I have a very limited understanding of the problem(s) I have with this class.
mImage is null when reading the Parcel. (Even when I know for sure that the byteArray is not null when I assign it to the Parcel.) I have tried to initialize mImage in its declaration so it not null but then I have that Class not found when unmarshalling error...
I'm almost sure the problem lies in
protected Property(final Parcel in) {
if(mImage != null)
{
mImage = new byte[in.readInt()];
in.createByteArray();
}
But I don't know how to fix it.
I'm lost for 2 days with this thing :/
Please see the below code for constructor with Parcel object.
protected Property(final Parcel in) {
mImage = new byte[in.readInt()];
in.readByteArray(mImage); // this will read the byte array from Parcel object(in) and store the value in mImage member variable.
mId = in.readString();
mGeneralInformation = in.readParcelable(GeneralInformation.class.getClassLoader());
}
Related
i'm trying to implement a lucene filter to remove a prefix from a term in a query.
It seems that sometime after multiple queries, the filter has been reused so the char buffer is dirty.
Code below is simplified, prefix is an external parameter.
public static class PrefixFilter extends TokenFilter {
private final PackedTokenAttributeImpl termAtt = (PackedTokenAttributeImpl) addAttribute(CharTermAttribute.class);
public PrefixFilter(TokenStream in) {
super(in);
}
#Override
public final boolean incrementToken() throws IOException {
if (!input.incrementToken()) {
return false;
}
String value = new String(termAtt.buffer());
value = value.trim();
value = value.toLowerCase();
value = StringUtils.removeStart(value, "prefix_");
if (value.isBlank()) {
termAtt.setEmpty();
} else {
termAtt.copyBuffer(value.toCharArray(), 0, value.length());
termAtt.setLength(value.length());
}
return true;
}
}
So after 10 or twelve queries, the value "prefix_a" became "abcde".
So i'm trying to add termBuffer offset end value in this way:
termAtt.setEmpty();
termAtt.resizeBuffer(value.length());
termAtt.copyBuffer(value.toCharArray(), 0, value.length());
termAtt.setLength(value.length());
termAtt.setOffset(0, value.length());
But i don't know if it's correct. Can anyone help me?
Thanks.
See if this helps you,
/**
* Standard number token filter.
*/
public class StandardnumberTokenFilter extends TokenFilter {
private final LinkedList<PackedTokenAttributeImpl> tokens;
private final StandardnumberService service;
private final Settings settings;
private final CharTermAttribute termAtt = addAttribute(CharTermAttribute.class);
private final PositionIncrementAttribute posIncAtt = addAttribute(PositionIncrementAttribute.class);
private State current;
protected StandardnumberTokenFilter(TokenStream input, StandardnumberService service, Settings settings) {
super(input);
this.tokens = new LinkedList<>();
this.service = service;
this.settings = settings;
}
#Override
public final boolean incrementToken() throws IOException {
if (!tokens.isEmpty()) {
if (current == null) {
throw new IllegalArgumentException("current is null");
}
PackedTokenAttributeImpl token = tokens.removeFirst();
restoreState(current);
termAtt.setEmpty().append(token);
posIncAtt.setPositionIncrement(0);
return true;
}
if (input.incrementToken()) {
detect();
if (!tokens.isEmpty()) {
current = captureState();
}
return true;
} else {
return false;
}
}
private void detect() throws CharacterCodingException {
CharSequence term = new String(termAtt.buffer(), 0, termAtt.length());
Collection<CharSequence> variants = service.lookup(settings, term);
for (CharSequence ch : variants) {
if (ch != null) {
PackedTokenAttributeImpl token = new PackedTokenAttributeImpl();
token.append(ch);
tokens.add(token);
}
}
}
#Override
public void reset() throws IOException {
super.reset();
tokens.clear();
current = null;
}
#Override
public boolean equals(Object object) {
return object instanceof StandardnumberTokenFilter &&
service.equals(((StandardnumberTokenFilter)object).service) &&
settings.equals(((StandardnumberTokenFilter)object).settings);
}
#Override
public int hashCode() {
return service.hashCode() ^ settings.hashCode();
}
}
https://github.com/jprante/elasticsearch-plugin-bundle/blob/f63690f877cc7f50360faffbac827622c9d404ef/src/main/java/org/xbib/elasticsearch/plugin/bundle/index/analysis/standardnumber/StandardnumberTokenFilter.java
I am trying to make a list of objects that are all of an abstract class, but each are there own class. This list needs to persistent so I figured I implement parcelable since I have done so in the past. Only not with different classes all of an abstract class.
I tried just making the abstract class parcelable but that can't have a creator that I am used to because (of course) you can't create an instance of it (because it is abstract). Reading around I noticed that people said you dont need a constructor in the abstract class, just in the subclasses.
AbstractFocusPower class
public abstract class AbstractFocusPower implements Parcelable {
private transient AppExtension app;
private ImplementSchool school;
private String name;
private int duration;
private int cost;
private int altCost;
private int requiredLevel;
private boolean isSelected;
private boolean isResonant;
private int nofSpirtBonusUsed;
/**
* Constructor for Focus Power with no alternative cost
*/
public AbstractFocusPower(AppExtension app, ImplementSchool school, String name, int requiredLevel, int duration, int cost, boolean isSelected) {
this.app = app;
this.school = school;
this.name = name;
this.requiredLevel = requiredLevel;
this.duration = duration;
this.cost = cost;
this.altCost = -1;
this.isSelected = isSelected;
this.isResonant = false;
}
// I cut out the other constructors
public abstract AbstractFocusPower makeCopy();
public abstract String getDescription();
// I cut out the getters and setters
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(this.school == null ? -1 : this.school.ordinal());
dest.writeString(this.name);
dest.writeInt(this.duration);
dest.writeInt(this.cost);
dest.writeInt(this.altCost);
dest.writeInt(this.requiredLevel);
dest.writeByte(this.isSelected ? (byte) 1 : (byte) 0);
dest.writeByte(this.isResonant ? (byte) 1 : (byte) 0);
dest.writeInt(this.nofSpirtBonusUsed);
}
protected AbstractFocusPower(Parcel in) {
int tmpSchool = in.readInt();
this.school = tmpSchool == -1 ? null : ImplementSchool.values()[tmpSchool];
this.name = in.readString();
this.duration = in.readInt();
this.cost = in.readInt();
this.altCost = in.readInt();
this.requiredLevel = in.readInt();
this.isSelected = in.readByte() != 0;
this.isResonant = in.readByte() != 0;
this.nofSpirtBonusUsed = in.readInt();
}
Sample subclass
public class AegisFocusPower extends AbstractFocusPower {
public AegisFocusPower(AppExtension app) {
super(app, ImplementSchool.ABJURATION, app.getString(R.string.focus_power_name_aegis), 0, 1, 1, false);
}
#Override
public String getDescription() {
return getApp().getString(R.string.focus_power_desc_aegis, (1+((int) Math.floor(getApp().getCurrentCharacter().getOccultistLevel()/6.0))));
}
#Override
public AegisFocusPower makeCopy() {
return new AegisFocusPower(getApp());
}
public AegisFocusPower(Parcel in) {
super(in);
}
public static final Parcelable.Creator<AegisFocusPower> CREATOR = new Parcelable.Creator<AegisFocusPower>() {
public AegisFocusPower createFromParcel(Parcel in) {
return new AegisFocusPower (in);
}
public AegisFocusPower [] newArray(int size) {
return new AegisFocusPower[size];
}
};
}
Code where I use it
Gson gsonFocusPowers = new Gson();
String jsonFocusPowers = sharedPreferences.getString(FOCUS_POWERS_GSON, null);
Type typeFocusPower = new TypeToken<ArrayList<AbstractFocusPower>>() {
}.getType();
ArrayList<AbstractFocusPower> focusPowers;
focusPowers = gsonFocusPowers.fromJson(jsonFocusPowers, typeFocusPower);
if (focusPowers != null) {
this.focusPowers.addAll(checkForNewFocusPowers(focusPowers));
} else {
this.focusPowers = getNewFocusPowerList();
}
Unfortunately this gives me an error which I don't know how to fix.
java.lang.RuntimeException: Unable to create application nl.rekijan.occultistmentalfocushelper.AppExtension: java.lang.RuntimeException: Unable to invoke no-args constructor for class nl.rekijan.occultistmentalfocushelper.mvc.focuspowers.AbstractFocusPower. Registering an InstanceCreator with Gson for this type may fix this problem.
Edit: Not sure why that post is a duplicate. For starters it doesn't have an accepted answer. The answer requires a 3rd party library. The question isn't about multiple subclasses under a single abstract.
have you tried registering a type adapter, something like Using Gson and Abstract Classes ? I always add adapters both for specific formatting (for dates, big decimals, anything where you usually require a very specific format) but also for sub-classing.
In this case however, no adapter is needed, this is.. straight on?
public abstract class AbstractFocusPower implements Parcelable {
// just some property needed to be pushed through a constructor
protected final String myString;
protected AbstractFocusPower(String myString) {
this.myString = myString;
}
}
and then the impl (yeah added toString(), hashCode() and equals() the way I like them to be in domain objects..):
public class AegisFocusPower extends AbstractFocusPower {
boolean imParcelled;
public AegisFocusPower(String myString) {
super(myString);
}
#Override //yup the interface impl
public void parcelMe() {
imParcelled = true;
}
#Override
public String toString() {
return new StringBuilder("{ imParcelled : ").append(imParcelled).append(", myString : ").append(myString).append(" }").toString();
}
#Override
public int hashCode() {
return toString().hashCode();
}
#Override
public boolean equals(Object other) {
if (other == this) {
return true;
} else if (other == null || !(other instanceof AegisFocusPower)) {
return false;
} else {
return other.hashCode() == hashCode();
}
}
}
and then I can run the following junit :
#Test
public void AegisFocusPowerToJsonAndBack(){
// single instance
AegisFocusPower ea = new AegisFocusPower("apa");
String json = GSON.toJson(ea);
assertEquals("{\"imParcelled\":\"false\",\"myString\":\"apa\"}", json);
AegisFocusPower backAtYa = (AegisFocusPower) GSON.fromJson(json, AegisFocusPower.class);
assertEquals(backAtYa, ea);
// A list
AegisFocusPower ea2 = new AegisFocusPower("bepa");
AegisFocusPower ea3 = new AegisFocusPower("cepa");
List<AegisFocusPower> powerList = new ArrayList<>();
powerList.add(ea2);
powerList.add(ea3);
String jsonList = GSON.toJson(powerList);
assertEquals("[{\"imParcelled\":\"false\",\"myString\":\"bepa\"},{\"imParcelled\":\"false\",\"myString\":\"cepa\"}]", jsonList);
List<AegisFocusPower> backAtYaz = Arrays.asList(GSON.fromJson(jsonList,AegisFocusPower[].class));
assertEquals(backAtYaz.get(0), ea2);
assertEquals(backAtYaz.get(1), ea3);
}
whereas GSON is initialized simply like
private static final Gson GSON = (new GsonBuilder()).registerTypeAdapter(Boolean.class, new JsonBooleanDeAndSerializer()).create();
and the type adapter registered for booleans which I use is irrelevant for your problem.
This is.. simple enough and would work for you too?
Check your imports. You may have mistakenly imported wrong class in your pojo. i.e. I have imported android.net.TransportInfo instead of my own TransportInfo class
I have an issue with realm. I receive a custom object from an API. I assign this object to a POJO object using retrofit. Within this object I have an ArrayList of the ToDoItemobject which extends RealmObject.
I receive the data correctly with all attributes, everything gets correctly assigned. I run it through my synchronization algorithm and save it to realm in a writing transaction. But when retrieving the data after realm.commit(); the attributes of the objects are all 0 or null.
The method isManaged()is always false, even after the writing transaction, which I don't understand because in the official documentation is states that a POJO can be converted to a managed object using the copyToRealm method.
I already tried a number of things: creating the GetItemResponseClass as RealmObject, but not possible since it has to extend JSONObject to correctly receive the data from the API. I also tried to write the whole list directly to realm but the result was the same.
As a side note, it can be that my method syncPendingLists has some logic errors, but I couldn't debug it yet, since the attributes were always o and null. Thanks for any help.
Here my code from the Activity:
public class MainActivity extends AppCompatActivity{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Realm.init(this);
RealmConfiguration config = new RealmConfiguration.Builder().name("myrealm.realm").build();
Realm.setDefaultConfiguration(config);
realm = Realm.getDefaultInstance();
RealmResults<Counter> counterList = realm.where(Counter.class).findAll();
//setting up counterObject
if (counterList.isEmpty()) {
counterObject = new Counter();
COUNTER = counterObject.getCounter();
} else {
counterObject = counterList.get(0);
COUNTER = counterObject.getCounter();
}
initializeLists();
//Adding the Fragment
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.add(R.id.fragment_container, new DoneListFragment(), "DoneListFragment");
ft.add(R.id.fragment_container, new PendingListFragment(), "PendingListFragment");
ft.commit();
RetrofitClient retrofitClient = new RetrofitClient();
Retrofit retrofit = retrofitClient.getClient();
mAPIInterface = retrofit.create(ToDoistAPIInterface.class);
}
public void getRemoteItems() {
final ArrayList<ToDoItem> onlineItems = new ArrayList<ToDoItem>();
JSONArray array = new JSONArray();
array.put("items");
String auxMessage = array.toString();
mAPIInterface.getItems(RetrofitClient.TOKEN, "*", auxMessage).enqueue(new Callback<GetItemsResponseClass>() {
#Override
public void onResponse(Call<GetItemsResponseClass> call, Response<GetItemsResponseClass> response) {
GetItemsResponseClass itemsResponseClass = new GetItemsResponseClass();
itemsResponseClass = response.body();
remoteItemsList = itemsResponseClass.getItems();
boolean test = remoteItemsList.get(0).isManaged(); //returns false
boolean test1 = remoteItemsList.get(0).isValid(); //returns true refers to singleton RealmObject
syncPendingLists(pendingItemList, remoteItemsList);
}
#Override
public void onFailure(Call<GetItemsResponseClass> call, Throwable t) {
Snackbar.make(floatingButton, "Ups - Couldn't sync items, next time, I promise", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
}
});
}
private void initializeLists() {
RealmResults<ToDoItem> realmToDoItemPendingList = realm.where(ToDoItem.class).equalTo("checkedOffline", false).findAll();
initializingArrayListFromDB(realmToDoItemPendingList, pendingItemList);
RealmResults<ToDoItem> realmToDoItemDoneList = realm.where(ToDoItem.class).equalTo("checkedOffline", true).findAll();
initializingArrayListFromDB(realmToDoItemDoneList, doneItemList);
}
private void initializingArrayListFromDB(RealmResults<ToDoItem> realmToDoItemPendingList, ArrayList<ToDoItem> arrayList) {
int h;
for (h = 0; h < realmToDoItemPendingList.size(); h++) {
arrayList.add(realmToDoItemPendingList.get(h));
}
}
public void syncPendingLists(ArrayList<ToDoItem> offlinePendingList, ArrayList<ToDoItem> onlinePendingList) {
//is my sync algorithm, the important part is the for loop at the end of this method
boolean hasMatch = false;
boolean itemChanged = false;
Date offlineDate = null;
Date onlineDate = null;
if (!offlinePendingList.isEmpty()) {
for (ToDoItem item1 : offlinePendingList) {
if (item1.getId() < 10000) {
try {
createNewRemoteItem(item1);
} catch (JSONException e) {
e.printStackTrace();
}
} else {
for (int i = 0; i < onlinePendingList.size(); i++) {
if (item1.getId() == onlinePendingList.get(i).getId()) {
hasMatch = true;
onlinePendingList.remove(onlinePendingList.get(i));
//Compare Fields
if (!item1.getContent().equals(onlinePendingList.get(i).getContent())) {
itemChanged = true;
}
if (item1.getPriority() != onlinePendingList.get(i).getPriority()) {
itemChanged = true;
}
if (!item1.getDate_string().equals(onlinePendingList.get(i).getDate_string())) {
itemChanged = true;
}
if (itemChanged == true) {
//Format edit dates to date
DateFormat format = new SimpleDateFormat("dd/MM/yyyy", Locale.ENGLISH);
try {
offlineDate = format.parse(item1.getDateAdded());
} catch (ParseException e) {
e.printStackTrace();
}
try {
onlineDate = format.parse(onlinePendingList.get(i).getDateAdded());
} catch (ParseException e) {
e.printStackTrace();
}
//compare dates to see which was last edited
if (offlineDate.compareTo(onlineDate) > 0) {
try {
deleteRemoteItem(onlinePendingList.get(i), "item_delete");
createNewRemoteItem(item1);
} catch (JSONException e) {
e.printStackTrace();
}
} else if (offlineDate.compareTo(onlineDate) < 0) {
addOrUpdateToDB(item1);
}
}
}
if (!hasMatch) {
deleteObjectFromDB(item1);
}
}
}
}
}
for (ToDoItem onlineItem1 : onlinePendingList) {
boolean isManaged1 = onlineItem1.isManaged(); //returns false, which is ok since it is not yet in the realm db
onlineItem1.setLocalId(counterObject.getCounter());
addOrUpdateToDB(onlineItem1);
boolean asdf = onlineItem1.isManaged(); //it returns false, but it should return true
incrementCounter(counterObject);
}
initializeLists();
getPendingListFragment().refreshFragment();
}
private void addOrUpdateToDB(ToDoItem newItem) {
boolean test2= newItem.isManaged(); //returns false
realm.beginTransaction();
realm.copyToRealmOrUpdate(newItem);
//realm.copyToRealm(newItem); //I tried this method as well, but no difference
realm.commitTransaction();
boolean test3= newItem.isManaged(); //returns false, and here is the problem, it should return true, shouldn't it?
assignValuesToToDoItem(itemWithValues, newItem);
saveCounterToDB(counterObject);
}
}
Here my class code of ToDoItem:
public class ToDoItem extends RealmObject implements Parcelable {
public static final Creator<ToDoItem> CREATOR = new Creator<ToDoItem>() {
#Override
public ToDoItem createFromParcel(Parcel in) {
return new ToDoItem(in);
}
#Override
public ToDoItem[] newArray(int size) {
return new ToDoItem[size];
}
};
#PrimaryKey
private long localId;
private String content;
private boolean checkedOffline = false;
private int priority;
private String date_string;
private String temp_id;
private long id;
private String date_added;
public ToDoItem(String name) {
this.content = name;
}
public ToDoItem() {
}
protected ToDoItem(Parcel in) {
localId = in.readLong();
content = in.readString();
checkedOffline = in.readByte() != 0;
priority = in.readInt();
date_string = in.readString();
temp_id = in.readString();
id = in.readLong();
date_added=in.readString();
}
public int getPriority() {
return priority;
}
public void setPriority(int priority) {
this.priority = priority;
}
public boolean isCheckedOffline() {
return checkedOffline;
}
public void setCheckedOffline(boolean checkedOffline) {
this.checkedOffline = checkedOffline;
}
public Long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public void setRemote_id(Long remote_id) {
this.id = remote_id;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public boolean isDone() {
return checkedOffline;
}
public String getDate_string() {
return date_string;
}
public void setDate_string(String date_string) {
this.date_string = date_string;
}
public long getLocalId() {
return this.localId;
}
public void setLocalId(long i) {
this.localId = i;
}
public String getTemp_id() {
return temp_id;
}
public void setTemp_id(String temp_id) {
this.temp_id = temp_id;
}
public String getDateAdded() {
return date_added;
}
public void setDateAdded(String dateAdded) {
this.date_added = dateAdded;
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeLong(localId);
dest.writeString(content);
dest.writeByte((byte) (checkedOffline ? 1 : 0));
dest.writeInt((priority));
dest.writeString(date_string);
dest.writeString(temp_id);
dest.writeLong(id);
dest.writeString(date_added);
}
#Override
public String toString() {
return "localId: " + localId + "; content: " + content;
}
}
And here the code for the GetItemsResponseClass:
public class GetItemsResponseClass extends JSONObject {
private String sync_token;
#SerializedName("temp_id_mapping")
private HashMap<String, Long> temp_id_mapping;
private boolean full_sync;
#SerializedName("items")
private ArrayList<ToDoItem> items;
public GetItemsResponseClass(){
}
public String getSync_token() {
return sync_token;
}
public void setSync_token(String sync_token) {
this.sync_token = sync_token;
}
public HashMap<String, Long> getTemp_id_mapping() {
return temp_id_mapping;
}
public void setTemp_id_mapping(HashMap<String, Long> temp_id_mapping) {
this.temp_id_mapping = temp_id_mapping;
}
public boolean isFull_sync() {
return full_sync;
}
public void setFull_sync(boolean full_sync) {
this.full_sync = full_sync;
}
public ArrayList<ToDoItem> getItems() {
return items;
}
public void setItems(ArrayList<ToDoItem> items) {
this.items = items;
}
}
EDIT: Apparently it is a desired behavior that the object does not get saved with its attributes. Consequently to assign the values you have to use getters and setters. I added the following method, however even when debugging with a watch, as stated in the official documentation the values do not get assigned:
private void assignValuesToToDoItem(ToDoItem itemWithValues, ToDoItem newItem) {
realm.beginTransaction();
newItem.setContent(itemWithValues.getContent()); //the content variable stays null
newItem.setCheckedOffline(itemWithValues.isDone()); //stays false
newItem.setPriority(itemWithValues.getPriority());
newItem.setDate_string(itemWithValues.getDate_string());
newItem.setTemp_id(itemWithValues.getTemp_id());
newItem.setId(itemWithValues.getId());
newItem.setDate_added(itemWithValues.getDate_added());
realm.commitTransaction();
}
I added this line assignValuesToToDoItem(itemWithValues, newItem); in the main activity in the method private void addOrUpdateToDB(ToDoItem newItem) {...}
Same result...
I found out 2 very important things:
The attributes are saved, however in the debugging window they appear to be 0, false or null
Even putting a Debugging Watch does not show the correct values.
To see the real value how it is in the database you have to add a Watch and put the watch directly on the getters of the object. In my case I added a Watch and typed in "newItem.getContent()". With this line I got the title of my object. However just putting a Watch with "newItem" shows "null".
copyToRealm() and copyToRealmOrUpdate() returns the managed proxy as a return value of the function you're calling.
realm.copyToRealmOrUpdate(newItem);
realm.commitTransaction();
boolean test3= newItem.isManaged(); //returns false, and it should return false
Should be
newItem = realm.copyToRealmOrUpdate(newItem);
realm.commitTransaction();
boolean test3= newItem.isManaged(); //returns true
I've a base class BaseNewsItem, and 2 derived classes NewsItem and MovieNewsItem. Then, there's a MovieListingFeed class which holds a list of MovieNewsItem and is parcelable. It can parcel this list as and when required by any activity.
protected MovieNewsListingFeed(Parcel in) {
this.pg = in.readParcelable(PageDetail.class.getClassLoader());
this.items=new ArrayList<>();
in.readTypedList(items, MovieNewsItem.CREATOR);
}
I receive an error at the line :
in.readTypedList(items, MovieNewsItem.CREATOR);
Error:
Error:(60, 11) error: method readTypedList in class Parcel cannot be applied to given types; required: List<T>,Creator<T> found: ArrayList<CAP#1>,Creator<CAP#2> reason: inferred type does not conform to equality constraint(s) inferred: CAP#2 equality constraints(s): CAP#2,CAP#1 where T is a type-variable: T extends Object declared in method <T>readTypedList(List<T>,Creator<T>) where CAP#1,CAP#2 are fresh type-variables: CAP#1 extends BaseNewsItem from capture of ? extends BaseNewsItem CAP#2 extends BaseNewsItem from capture of ? extends BaseNewsItem
I'm a novice at Generics, so when I searched for the above error, I didn't completely get the solutions posted. I only added as I needed to convert ArrayList<MovieNewsItem> to ArrayList<BaseNewsItem>.
Relevant code from MovieNewsItem class:
public static final Creator<? extends BaseNewsItem> CREATOR = new Creator<MovieNewsItem>() {
public MovieNewsItem createFromParcel(Parcel source) {
return new MovieNewsItem(source);
}
public MovieNewsItem[] newArray(int size) {
return new MovieNewsItem[size];
}
};
Let me know if any further code snippets are needed.
UPDATE 1: (readTypedList from Android framework.)
public final <T> void readTypedList(List<T> list, Parcelable.Creator<T> c) {
int M = list.size();
int N = readInt();
int i = 0;
for (; i < M && i < N; i++) {
if (readInt() != 0) {
list.set(i, c.createFromParcel(this));
} else {
list.set(i, null);
}
}
for (; i<N; i++) {
if (readInt() != 0) {
list.add(c.createFromParcel(this));
} else {
list.add(null);
}
}
for (; i<M; i++) {
list.remove(N);
}
}
MovieNewsListingFeed.java (Problem file):
public class MovieNewsListingFeed implements Parcelable {
PageDetail pg;
public void setItems(ArrayList<? extends BaseNewsItem> items) {
this.items = items;
}
ArrayList<? extends BaseNewsItem> items;
public ArrayList<? extends BaseNewsItem> getItemsTemp() {
return itemsTemp;
}
public void setItemsTemp(ArrayList<? extends BaseNewsItem> itemsTemp) {
this.itemsTemp = itemsTemp;
}
ArrayList<? extends BaseNewsItem> itemsTemp;
public ArrayList<? extends BaseNewsItem> getItems() {
return items;
}
public PageDetail getPg() {
return pg;
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeParcelable(this.pg, flags);
dest.writeTypedList(items);
}
public MovieNewsListingFeed() {
}
protected MovieNewsListingFeed(Parcel in) {
this.pg = in.readParcelable(PageDetail.class.getClassLoader());
this.items = new ArrayList<>();
in.readTypedList(items, MovieNewsItem.CREATOR);
}
public static final Parcelable.Creator<MovieNewsListingFeed> CREATOR = new Parcelable.Creator<MovieNewsListingFeed>() {
public MovieNewsListingFeed createFromParcel(Parcel source) {
return new MovieNewsListingFeed(source);
}
public MovieNewsListingFeed[] newArray(int size) {
return new MovieNewsListingFeed[size];
}
};
}
MovieNewsItem.java:
public class MovieNewsItem extends BaseNewsItem implements Parcelable {
String hl;
String imageid;
String syn;
String id;
String dm;
String tn;
String dl = "";
String sectionHeader;
String upd;
String ud;
private int validListPosition = -1;
public int getValidListPosition() {
return validListPosition;
}
#Override
public void setTitle(String title) {
}
#Override
public void setId(String id) {
}
#Override
public void setDate(String date) {
}
#Override
public void setNewsType(int newsType) {
}
public String getFormatedDate() {
return formatedDate;
}
String formatedDate;
int position;
int newSectionType = NewsType.CONTENT_TYPE_NEWS;
String dayHeading;
public int getPosition() {
return position;
}
public void setPosition(int position) {
this.position = position;
}
public void setNewSectionType(int newSectionType) {
this.newSectionType = newSectionType;
}
public String getDayHeading() {
return dayHeading;
}
public void setDayHeading(String dayHeading) {
this.dayHeading = dayHeading;
}
#Override
public void setValidListPosition(int listPosition) {
}
public String getWu() {
return wu;
}
String wu;
public String getHl() {
return hl;
}
public String getImageid() {
return imageid;
}
public String getSyn() {
return syn;
}
public String getId() {
return id;
}
public String getDm() {
return dm;
}
public String getTn() {
return tn;
}
public String getDl() {
return dl;
}
public String getSectionHeader() {
return sectionHeader;
}
public MovieNewsItem() {
}
#Override
public String getTitle() {
return (!TextUtils.isEmpty(getSyn())) ? getSyn() : getHl();
}
#Override
public String getDate() {
return getFormatedDate();
}
#Override
public int getNewsType() {
return newSectionType;
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(this.hl);
dest.writeString(this.imageid);
dest.writeString(this.syn);
dest.writeString(this.id);
dest.writeString(this.dm);
dest.writeString(this.tn);
dest.writeString(this.dl);
dest.writeString(this.sectionHeader);
dest.writeString(this.upd);
dest.writeString(this.ud);
dest.writeInt(this.position);
dest.writeInt(this.newSectionType);
dest.writeString(this.dayHeading);
dest.writeString(this.wu);
}
protected MovieNewsItem(Parcel in) {
this.hl = in.readString();
this.imageid = in.readString();
this.syn = in.readString();
this.id = in.readString();
this.dm = in.readString();
this.tn = in.readString();
this.dl = in.readString();
this.sectionHeader = in.readString();
this.upd = in.readString();
this.ud = in.readString();
this.position = in.readInt();
this.newSectionType = in.readInt();
this.dayHeading = in.readString();
this.wu = in.readString();
}
public static final Creator<? extends BaseNewsItem> CREATOR = new Creator<MovieNewsItem>() {
public MovieNewsItem createFromParcel(Parcel source) {
return new MovieNewsItem(source);
}
public MovieNewsItem[] newArray(int size) {
return new MovieNewsItem[size];
}
};
#Override
public boolean equals(Object obj) {
MovieNewsItem newsItem = this;
if (obj instanceof MovieNewsItem) {
MovieNewsItem oldNewsItem = (MovieNewsItem) obj;
if (oldNewsItem != null &&
newsItem.id.equals(oldNewsItem.id)) {
return true;
}
}
return false;
}
}
BaseNewsItem.java:
public abstract class BaseNewsItem implements NewsItemType {
}
NewsItemType.java:
public interface NewsItemType extends Parcelable {
String getTitle();
String getId();
String getDate();
int getNewsType();
String getDayHeading();
int getValidListPosition();
int getPosition();
void setTitle(String title);
void setId(String id);
void setDate(String date);
void setNewsType(int newsType);
void setDayHeading(String dayHeading);
void setValidListPosition(int listPosition);
void setPosition(int position);
}
Your issue can be reproduced with this minimal example (replace ? extends Object by ? extends BaseNewsItem and the second list by a Parcelable.Creator and you'll see that the logic is exactly the same):
public void test() {
List<? extends Object> a1 = new ArrayList<> ();
List<? extends Object> a2 = new ArrayList<> ();
m(a1, a2); //your compilation error here
}
public <T> void m(List<T> a1, List<T> a2) { }
The problem is that the generic type of the two lists are unrelated: they both extend the same base class but that's all we know about them - for example a1 may be a List<String> and a2 a List<Integer>.
However the m method expects the two generic types to be the same - which is not what you are passing.
So you need to pass lists which have the same generic type, for example:
public void test() {
List<SomeBaseClass> a1 = new ArrayList<> ();
List<SomeBaseClass> a2 = new ArrayList<> ();
m(a1, a2); //compiles fine
}
public <T> void m(List<T> a1, List<T> a2) { }
This is due to type mis-match
Change
ArrayList<? extends BaseNewsItem> itemsTemp;
to
List<? extends BaseNewsItem> itemsTemp;
Change the method like this:
public final <T> void readTypedList(List<? extends BaseNewsItem> list, Parcelable.Creator<? extends BaseNewsItem> c) {
}
Hope it will work.
Activity 1, from where I send my Parcelable object:
Intent intent = new Intent(JobFieldAttribute.this, JobCamera.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
Bundle mBundle = new Bundle();
mBundle.putParcelable("FieldData", fieldData);
mBundle.putSerializable("JobTransaction",jobTransaction);
mBundle.putString("imgPos", 0+"");
intent.putExtra("parce",mBundle);
startActivity(intent);
My object class:
public class FieldData implements Parcelable {
private Integer id;
private String value;
private Integer job_transaction_id;
private Integer field_attribute_master_id;
private Boolean required;
private View view;
private String viewType;
private String viewLabel;
private String viewSubLabel;
private String viewHelpText;
//All Getter setter methods
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(0);
dest.writeString(value);
try{
dest.writeInt(job_transaction_id);
}
catch(Exception e){dest.writeInt(0);}
dest.writeInt(field_attribute_master_id);
try{
dest.writeByte((byte) (required ? 1 : 0));
}
catch(Exception e){dest.writeByte((byte)0);}
try{
dest.writeString(viewType);
}
catch(Exception e){dest.writeString("NOVIEWTYPE");}
try{
dest.writeString(viewLabel);
}
catch(Exception e){dest.writeString("NO LABEL");}
try{
dest.writeString(viewSubLabel);
}
catch(Exception e){dest.writeString("NO SUB LABEL");}
try{
dest.writeString(viewHelpText);
}
catch(Exception e){dest.writeString("NO HELP TEXT");}
}
public static final Parcelable.Creator<FieldData> CREATOR = new Parcelable.Creator<FieldData>() {
#Override
public FieldData createFromParcel(Parcel in) {
FieldData fieldData = new FieldData();
fieldData.id = in.readInt();
Log.i("Pracel in", ">> " + in.readString());
fieldData.value = in.readString();
fieldData.job_transaction_id = in.readInt();
fieldData.field_attribute_master_id = in.readInt();
fieldData.required = in.readByte() != 0;
fieldData.viewType = in.readString();
fieldData.viewLabel = in.readString();
fieldData.viewSubLabel = in.readString();
fieldData.viewHelpText = in.readString();
return fieldData;
}
#Override
public FieldData[] newArray(int size) {
return new FieldData[size];
}
};
}
My second activity, which receives this Parcelable object:
super.onCreate(savedInstanceState);
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
setContentView(R.layout.activity_job_camera);
FieldData fieldData = (FieldData) getIntent().getParcelableExtra("fieldData");
When i print my fieldData object, i get a NullPointerException. I cannot understand the reason for this error.
What am i doing wrong?
I am a newbie at android development and using Parcelable interface for passing object via Intent.
Please help.
You are putting FieldData but trying to get back fieldData. Combine it with #Dmitry Zaitsev's answer: getIntent().getBundleExtra("parce").getParcelableExtra("FieldData");
You're putting Bundle to your Intent extras, not FieldData directly. So, your code should look as follows:
getIntent().getBundleExtra("parce").getParcelableExtra("fieldData");