I have a Bundle and I store it to the disk as a byte array. Now, when I retrieve it I take the byte array. How can I convert this again to Bundle?
byte fileContent[] = new byte[(int)file.length()];
int numerOfReturnedbytes = 0;
try {
//read the stream and set it into the byte array readFileByteArray
//and returns the numerOfReturnedbytes. If returns -1 means that
//that the end of the stream has been reached.
numerOfReturnedbytes = fis.read(fileContent);
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
if (numerOfReturnedbytes == -1) {
return;
} else {
//creating empty parcel object
Parcel parcel = Parcel.obtain();
//un-marshalling the data contained into the byte array to the parcel
parcel.unmarshall(fileContent, 0, numerOfReturnedbytes);
}
The fileContent is the byte array. Any ideas on how can I solve my problem?
To convert Bundle to ByteArray
public byte[] bundleToBytes(#NonNull Bundle bundle) {
Parcel parcel = Parcel.obtain();
parcel.writeBundle(bundle);
byte[] bytes = parcel.marshall();
parcel.recycle();
return bytes;
}
To convert ByteArray to Bundle
#NonNull
public Bundle bytesToBundle(byte[] bytes) {
Parcel parcel = Parcel.obtain();
parcel.unmarshall(bytes, 0, bytes.length);
parcel.setDataPosition(0);
Bundle bundle = parcel.readBundle(ClassWithinProject.class.getClassLoader());
parcel.recycle();
return bundle;
}
Don't do that. From the Android documentation:
Parcel is not a general-purpose serialization mechanism. This class (and the corresponding Parcelable API for placing arbitrary objects into a Parcel) is designed as a high-performance IPC transport. As such, it is not appropriate to place any Parcel data in to persistent storage: changes in the underlying implementation of any of the data in the Parcel can render older data unreadable.
This means, that after an OS upgrade the data written by your application could become unreadable.
Would it be something like :
Bundle bundle = Bundle.CREATOR.createFromParcel(parcel);
once you have the parcel ?
Edit
or is it
Bundle bundle = parcel.readParcelable(null);
? I don't remember. I'd read the documentation, but you know ...
(actually, i really don't know what is best, they appear to do pretty much the same thing)
Edit 2
There is also
Bundle bundle = parcel.readBundle();
Amazing the quantity of information in the documentation thingy. I should go there more often.
Related
I'm trying to read content from a Uri on Android, and I need the final Object type passed to the underlying SDK to by a nio.ByteBuffer.
I can get my hands on an InputStream, via ContentResolver but didn't find a way to wrap it with an nio.ByteBuffer.
Is there a way to convert a Uri content to a nio.ByteBuffer on Android?
I've ended up downloading the content of the Uri locally and open it via other method to get the ByteBuffer
Suppose you are working on an Activity,
private ByteBuffer getByteBuffer(Uri uri){
try{
InputStream iStream = getContentResolver().openInputStream(uri);
if(iStream!=null){
//value of MAX_SIZE is up to your requirement
final int MAX_SIZE = 5000000;
byte[] byteArr = new byte[MAX_SIZE];
int arrSize = 0;
while(true){
int value = iStream.read(byteArr);
if(value == -1){
break;
}else{
arrSize += value;
}
}
iStream.close();
return ByteBuffer.wrap(byteArr, 0, arrSize);
}
}catch(IOException e){
//do something
}
return null;
}
Notes:
(i) InputStream.read(byte[] b) will return an Integer which indicate total number of bytes read into the byte array b at each time.
(ii) If InputStream.read(Byte[] b) returns -1, it indicates that it is the end of the inputStream.
(iii) arrSize stores the total number of bytes read, i.e. the length of byte[] b
(iv) ByteBuffer.wrap(byte[] b, int offset, int length) will wrap the byte array to give a ByteBuffer. You may check this reference
(v) ContentResolver.openInputStream(Uri uri) and InputStream.read(byte[] b) will throw IOException so you must handle it.
(vi) Caution: IndexOutOfBoundException might happen if arrSize > MAX_SIZE, you may need to add if-else clause to handle such issue.
Please feel free to comment or change the code if there is any mistake or if there is a faster way to do that. Happy coding
I want to marshall and unmarshall a Class that implements Parcelable to/from a byte array. I am well aware of the fact that the Parcelable representation is not stable and therefore not meant for long term storage of instances. But I have a use case where I need to serialize a object and it's not a showstopper if the unmarshalling fails because of an internal Android change. Also the class is already implementing the Parcelable interface.
Given an class MyClass implements Parcelable, how can I (ab)use the Parcelable interface for marshalling/unmarshalling?
First create a helper class ParcelableUtil.java:
public class ParcelableUtil {
public static byte[] marshall(Parcelable parceable) {
Parcel parcel = Parcel.obtain();
parceable.writeToParcel(parcel, 0);
byte[] bytes = parcel.marshall();
parcel.recycle();
return bytes;
}
public static Parcel unmarshall(byte[] bytes) {
Parcel parcel = Parcel.obtain();
parcel.unmarshall(bytes, 0, bytes.length);
parcel.setDataPosition(0); // This is extremely important!
return parcel;
}
public static <T> T unmarshall(byte[] bytes, Parcelable.Creator<T> creator) {
Parcel parcel = unmarshall(bytes);
T result = creator.createFromParcel(parcel);
parcel.recycle();
return result;
}
}
With the help of the util class above, you can marshall/unmarshall instances of your class MyClass implements Parcelable like so:
Unmarshalling (with CREATOR)
byte[] bytes = …
MyClass myclass = ParcelableUtil.unmarshall(bytes, MyClass.CREATOR);
Unmarshalling (without CREATOR)
byte[] bytes = …
Parcel parcel = ParcelableUtil.unmarshall(bytes);
MyClass myclass = new MyClass(parcel); // Or MyClass.CREATOR.createFromParcel(parcel).
Marshalling
MyClass myclass = …
byte[] bytes = ParcelableUtil.marshall(myclass);
public static byte[] pack(Parcelable parcelable) {
Parcel parcel = Parcel.obtain();
parcelable.writeToParcel(parcel, 0);
byte[] bytes = parcel.marshall();
parcel.recycle();
return bytes;
}
public static <T> T unpack(byte[] bytes, Parcelable.Creator<T> creator) {
Parcel parcel = Parcel.obtain();
parcel.unmarshall(bytes, 0, bytes.length);
parcel.setDataPosition(0);
return creator.createFromParcel(parcel);
}
MyObject myObject = unpack(new byte[]{/* bytes */}, MyObject.CREATOR);
I want to parcel a Bundle from onSaveInstanceState method for storing it temporarily.
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
savedInstanceState.putBoolean(..);
savedInstanceState.putInt(..);
//...
super.onSaveInstanceState(savedInstanceState);
userInputs = savedInstanceState;
}
I only use putBoolean and putInt.
Somewhere else I save this data:
Parcel p1 = Parcel.obtain();
p1.writeBundle(userInputs);
byte[] b1 = p1.marshall();
and reuse it later:
Parcel p11 = Parcel.obtain();
p11.unmarshall(b1, 0, b1.length);
p11.setDataPosition(0);
Object o = p11.readValue(Bundle.class.getClassLoader());
Bundle result2 = (Bundle) o;
I get this Exception #p11.readValue
java.lang.RuntimeException: Parcel android.os.Parcel#41e42c70: Unmarshalling unknown type code 4292 at offset 0
I dont know, what is the problem.
I am using asyncTask to send images over sockets from Android to PC.
I am calling it like this
new SendImage().execute(data);
where data is of type byte[]
and my code is
private class SendImage extends AsyncTask<byte[],Void, Void> {
#Override
protected Void doInBackground(byte[] ... data) {
try{
final DataOutputStream dataOutputStream;
final BufferedOutputStream out = new BufferedOutputStream(RRAWsecurity.socket.getOutputStream());
int count = data.length;
dataOutputStream = new DataOutputStream(RRAWsecurity.socket.getOutputStream());
dataOutputStream.writeInt(count);
dataOutputStream.flush();
out.write(data, 0, count);
out.flush();
}catch(Exception e)
{
e.printStackTrace();
}
return null;
}
}
The problem is with this line
out.write(data, 0, count);
The error says
The method write(byte[], int, int) in the type BufferedOutputStream is not applicable for the arguments (byte[][], int, int)
I can't figure out why its asking for 2D array ?
Use data[0] instead of data. The ... notation is just some syntactical sugar for an array of the given type. So int... is actually an array of ints and your byte... is treated as an array of byte[] arrays, so it's actually byte[][].
Replace:
int count =data.length; to int count =data[0].length;
out.write(data,0,count); to out.write(data[0],0,count);
data is byte[][]. byte[] ... data is sameas byte[][] data.
Your byte array (byte[]) is one dimentional parameter but BufferedOutputStream's parameter byte[][]) is two dimentional array. Different dimention about array is very big problem. You must convert your array byte to two dimentional array.
All I need is convert byte[] to String. Then do something with that string and convert back to byte[] array. But in this testing I'm just convert byte[] to string and convert back to byte[] and the result is different.
to convert byte[] to string by using this:
byte[] byteEntity = EntityUtils.toByteArray(entity);
String s = new String(byteEntity,"UTF-8");
Then i tried:
byte[] byteTest = s.getBytes("UTF-8");
Then i complared it:
if (byteEntity.equals(byteTest) Log.i("test","equal");
else Log.i("test","diff");
So the result is different.
I searched in stackoverflow about this but it doesn't match my case. The point is my data is .png picture so the string converted is unreadable. Thanks in advance.
Solved
Using something like this.
byte[] mByteEntity = EntityUtils.toByteArray(entity);
byte[] mByteDecrypted = clip_xor(mByteEntity,"your_key".getBytes());
baos.write(mByteDecrypted);
InputStream in = new ByteArrayInputStream(baos.toByteArray());
and this is function clip_xor
protected byte[] clip_xor(byte[] data, byte[] key) {
int num_key = key.length;
int num_data = data.length;
try {
if (num_key > 0) {
for (int i = 0, j = 0; i < num_data; i++, j = (j + 1)
% num_key) {
data[i] ^= key[j];
}
}
} catch (Exception ex) {
Log.i("error", ex.toString());
}
return data;
}
Hope this will useful for someone face same problem. Thanks you your all for helping me solve this.
Special thanks for P'krit_s
primitive arrays are actually Objects (that's why they have .equals method) but they do not implement the contract of equality (hashCode and equals) needed for comparison. You cannot also use == since according to docs, .getBytes will return a new instance byte[]. You should use Arrays.equals(byteEntity, byteTest) to test equality.
Have a look to the answer here.
In that case my target was transform a png image in a bytestream to display it in embedded browser (it was a particular case where browser did not show directly the png).
You may use the logic of that solution to convert png to byte and then to String.
Then reverse the order of operations to get back to the original file.