Method and implementation of Android transferring big data across processes

Time:2022-5-13

Recently, the image data will be transferred from the service side to the client side. The previous data is transferred through Aidl:

Create a Parcelable file

ImageData.java


public class ImageData implements Parcelable {
  private byte[] data;
  public byte[] getData() {
    return data;
  }

  public ImageData(byte[] dataIn) {
    this.data = dataIn;
  }

  public ImageData(Parcel in) {
    int arrayLength = in.readInt();
    if (arrayLength > 0) {
      data = new byte[arrayLength];
      in.readByteArray(data);
    }
  }

  @Override
  public void writeToParcel(Parcel dest, int flags) {
    if (data != null && data.length > 0) {
      dest.writeInt(data.length);
      dest.writeByteArray(data);
    } else {
      dest.writeInt(0);
    }
  }
  ...
}

test.aidl
interface test {
  void sendMessage(ImageData data);
}

Operation error:

    android.os.DeadObjectException: Transaction failed on small parcel; remote process probably died
        at android.os.BinderProxy.transactNative(Native Method)
        at android.os.BinderProxy.transact(BinderProxy.java:514)
        …

reason

The main reason for deadobjectexception here is that the buffer created by the binder is full:

kernel/msm-4.4/drivers/android/binder_alloc.c
 315     if (best_fit == NULL) {

341         pr_err(“%d: binder_alloc_buf size %zd failed, no address space\n”,
342                   alloc->pid, size);
343         pr_err(“allocated: %zd (num: %zd largest: %zd), free: %zd (num: %zd largest: %zd)\n”,
344                       total_alloc_size, allocated_buffers, largest_alloc_size,
345                  total_free_size, free_buffers, largest_free_size);
346            eret = ERR_PTR(-ENOSPC);
347              goto error_unlock;
348    }

If the data in transmission is greater than free_ Buffers, a deadobjectexception will be thrown

solve

1.socket
Socke transmission is not limited by size, but its implementation is complex

2. Documents
File transfer is relatively simple, but inefficient, and the higher version will be limited by the permissions of the Android system

3. Data cutting
Cutting large data into smaller data transmission is a scheme with good efficiency and complexity

Define data body:


public class SliceData implements Parcelable {
  private byte[] data;
  private int length;
  ...
}

Cutting data method:


  public static byte[][] divideArray(byte[] source, int chunkSize) {
    int totalLength = source.length;
    int arraySize = (int) Math.ceil(totalLength / (double) chunkSize);
    byte[][] ret = new byte[arraySize][chunkSize];
    int start = 0;
    int parts = 0;
    for (int i = 0; i < arraySize; i++) {
      if (start + chunkSize > totalLength) {
        System.arraycopy(source, start, ret[i], 0, source.length - start);
      } else {
        System.arraycopy(source, start, ret[i], 0, chunkSize);
      }
      start += chunkSize;
      parts++;
    }
    return ret;
  }

Build and send slicedata in order:


byte[][] divideData = divideArray(testBytes, 64 * 1024);//64k
for (byte[] item : divideData) {
  mEmitter.onNext(new SliceData(length, item));
}

Client reception:

int chunkSize = bytes.length;
if(buffer == null) {
  buffer = new byte[length];
  index = 0;
}
If (index + chunksize > bodylength) {// last data block
  System.arraycopy(bytes, 0, buffer, index, bodyLength - index);
  visualResultData.bitmap = BitmapFactory.decodeByteArray(buffer, 0, buffer.length);
  buffer = null;
  index = 0;
} else {
  System.arraycopy(bytes, 0, buffer, index, chunkSize);
  index += chunkSize;
}

4. Third party
The binder itself also uses MMAP. You can use the framework that implements MMAP, such as mmkv

5.Bitmap
If the transmitted data is bitmap, the putbinder scheme of bundle can also be used
Define binder:


class ImageBinder extends IRemoteGetBitmap.Stub {
  @Override
  public Bitmap getBitMap() throws RemoteException {
    return mBitmap;
  }
}

send out


Bundle bundle = new Bundle();
bundle.putBinder("bitmap", new ImageBinder());
intent.putExtras(bundle);

receive:


ImageBinder imageBinder = (ImageBinder) bundle.getBinder("bitmap");
Bitmap bitmap = imageBinder.getBitmap();

This is the end of this article on the implementation of Android cross process big data transmission. For more information about Android cross process big data transmission, please search the previous articles of developeppaer or continue to browse the relevant articles below. I hope you will support developeppaer in the future!

Recommended Today

Explain the ImageView size change of IOS uitableviewcell

Explain the ImageView size change of IOS uitableviewcell Example code: – (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ static NSString *CellIdentifier = @”Cell”; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; if(cell == nil){ cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier]; cell.textLabel.text = [self.arrStr objectAtIndex:indexPath.row]; UIImage *img = [UIImage imageNamed:[self.arrImg objectAtIndex:indexPath.row]]; cell.imageView.image = img; //ImageView size change of IOS uitableviewcell CGSize itemSize […]