Hot questions for Using RxJava 2 in arrays

Question:

I have JSON Arrays in this form:

[6, 7, 8, 9, 10, 11]

[122402538, 12240345, 122496, 122617, 1227473, 1228495]

Now i want to merge each Long value with the other, keeping intact its index, like this:

[{"id": 6, "timestamp":122402538}, {"id": 7, "timestamp": 12240345}, {"id": , "timestamp": 12240345},...]

I have tried to loop and then add the values into a JSONObject like this:

JSONArray array = object.getJSONArray("theFirstArray");
for (int i = 0; i < array.length(); i++){
jo = array.getLong(i);
jsonObject.put("id", jo);
jsonArray.put(jsonObject);
}

JSONArray timestamp = object.getJSONArray("theSecondArray");
 for (int i = 0; i < timestamp .length(); i++){
 Long jos = timestamp .getLong(i);
 jsonObject.put("timeStamp", jos);
 jsonArray.put(jsonObject);
}

But, unfortunately, its the last values that are put into the array.

How do i merge both values of both arrays into one JSONObject, then have a list of all those JSONObjects?.

I have looked at other questions, even from the phps, javascripts, none have helped.

Or is there a way to do this using RxJava2?.

Any help is appreciated.


Answer:

Let's combine both array using RxJava

JSONArray combinedArray = new JSONArray();


    List<Integer> idList = Arrays.asList(6, 7, 8, 9, 10, 11);
    List<Integer> timestampList = Arrays.asList(122402538, 12240345, 122496, 122617, 1227473, 1228495);

    final int[] counter = {0}; // assuming your both array are of same size.
    Observable.fromIterable(idList)
            .map(id -> {
                        JSONObject singleObject = new JSONObject();
                        singleObject.put("id:", id);
                        singleObject.put("timestamp:", timestampList.get(counter[0]));
                        counter[0]++;
                        combinedArray.put(singleObject);
                        return Observable.just(combinedArray);
                    }
            )
            .toList()  //jsonArrayObservable is observable json array, if you want to your later on
            .doOnSuccess(jsonArrayObservable -> Log.d("jsonArrayObservable -> ", combinedArray.toString()))
            .subscribe();

OUTPUT

 jsonArrayObservable -> :[{"id:":6,"timestamp:":122402538},{"id:":7,"timestamp:":12240345},{"id:":8,"timestamp:":122496},{"id:":9,"timestamp:":122617},{"id:":10,"timestamp:":1227473},{"id:":11,"timestamp:":1228495}]

UPDATE without support of java 8

Observable.fromIterable(idList)
            .map(new Function<Integer, Object>() {
                     @Override
                     public Object apply(Integer id) throws Exception {
                         JSONObject singleObject = new JSONObject();
                         singleObject.put("id:", id);
                         singleObject.put("timestamp:", timestampList.get(counter[0]));
                         counter[0]++;
                         combinedArray.put(singleObject);
                         return Observable.just(combinedArray);
                     }
                 }
            )
            .toList()  //jsonArrayObservable is observable json array, if you want to your later on
            .doOnSuccess(jsonArrayObservable -> Log.d("jsonArrayObservable -> ", combinedArray.toString()))
            .subscribe();

Output

Question:

I have the following code done using for loops. This iterates over three arrays and updates the contents of an array.

for(MyPackage rPackage : rPackages){
  for(Products product : rPackage.getProducts()){
    for(SkuDetails skuItem : skuDetails){
      if(product.getId().equals(skuItem.getSku())){
         product.setSkuItem(skuItem);
         break;
       }
      }
     }
   }
return rPackages;

Can this iteration be replaced using RXJava Observables?


Answer:

It is not recommended to use RxJava for this kind of operations, but in fact the reactive approache is not that much slower than the Stream-API.

Please have a look at this the implementation:

Environment:

dependencies {
  testCompile 'org.assertj:assertj-core:3.8.0'
  testCompile("org.junit.jupiter:junit-jupiter-api:5.0.1")
  testRuntime("org.junit.jupiter:junit-jupiter-engine:5.0.1")
}

Test

  @Test
  void name3() {
    Product product = new Product(1);
    Product product1 = new Product(2);
    Product product2 = new Product(3);
    Product product3 = new Product(4);
    Product product4 = new Product(5);

    SkuDetail skuDetail1 = new SkuDetail(3);
    SkuDetail skuDetail2 = new SkuDetail(5);
    MyPackage myPackage =
        new MyPackage(Arrays.asList(product, product1, product2, product3, product4));

    List<Product> products =
        Stream.of(skuDetail1, skuDetail2)
            .map(
                sku ->
                    myPackage
                        .products
                        .stream()
                        .filter(p -> p.id == sku.sku)
                        .findFirst()
                        .map(
                            p -> {
                              return new Product(
                                  p.id); // create new product -> copy over all values
                            }))
            .filter(Optional::isPresent)
            .map(Optional::get)
            .collect(Collectors.toList());

    assertThat(products.size()).isEqualTo(2);
    assertThat(products).extracting("id").contains(3);
    assertThat(products).extracting("id").contains(5);
  }

  class MyPackage {
    List<Product> products;

    public MyPackage(List<Product> products) {
      this.products = products;
    }
  }

  class Product {
    int id;

    public Product(int id) {
      this.id = id;
    }
  }

  class SkuDetail {
    int sku;

    public SkuDetail(int sku) {
      this.sku = sku;
    }
  }

Question:

I try to download several image from url address. After i decode byte[] to bitmap and set it to ImageView. This code works perfect.

Request request = new Request.Builder()
                            .url(imageUrl)
                            .build();

                    new OkHttpClient().newCall(request).enqueue(new Callback() {
                        @Override
                        public void onFailure(Call call, IOException e) {}

                        @Override
                        public void onResponse(Call call, Response response) throws IOException {
                            try {
                                ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
                                int current;
                                while ((current = response.body().byteStream().read()) != -1) {
                                    outputStream.write((byte) current);
                                }
                                byte[] array = outputStream.toByteArray();
                                ..........
                            }
                        }
                    });

But if i use rxjava2, and retrofit2 it doesn't work out. Byte array come out with many 0 values.

public interface ImageApi {

@GET
Observable<ResponseBody> requestImage(@Url String utl);}



Observable(imageUrl()).subscribe(new Observer<ResponseBody>() {
                        @Override
                        public void onSubscribe(@NonNull Disposable d) {}

                        @Override
                        public void onNext(@NonNull ResponseBody responseBody) {
                            try {
                                if (responseBody != null && responseBody.bytes() != null) {
                                    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
                                    int current;
                                    while ((current = responseBody.byteStream().read()) != -1) {
                                        outputStream.write((byte) current);
                                    }
                                    byte[] array = outputStream.toByteArray(); 
                                }
                        }

What i doing wrong ? What difference between OkHttpClient request and Retrofit2 ?

p.s. i don't need to use Glide or Picasso.


Answer:

responseBody.bytes() != null - The call to bytes() reads the entire stream and then closes the response. Trying to access responseBody.byteStream() afterwards always returns a closed stream.

The correct code would be:

byte[] array = responseBody.bytes();

Since responseBody cannot be null (RxJava2 forbids it) and bytes() always returns a value or throws an exception.