0

I have one fragment layout with a background image. Programmatically I have to add the different layer to this image because I want to add some particular details depending of some data. There are three different details that it can change in 3 different way. ( there is a thread that works at 5/10hz and it loads the right details)

The following is my first implementation. In this version, I have done all of works in XML layout and in a programmatically way, when the user clicks on a certain button, I set the visibility of each image view. I have seen that is much expensive, and sometimes the inflate layout return null:

   <RelativeLayout  
       android:id="@+id/container"
       android:layout_width="match_parent"
       android:layout_height="match_parent" 
       android:background="@drawable/background"
     >

     <ImageView 
        android:id="@+id/layer1"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:visibility="gone"
        android:src="@drawable/ballgreen"/>
<ImageView 
        android:id="@+id/layer2"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:visibility="gone"
         android:src="@drawable/ballred"/>
<ImageView 
        android:id="@+id/layer3"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:visibility="gone"
          android:src="@drawable/ballyellow"/>

            ... 6 more image view layer....

</RelativeLayout>

Then I thought to use an async task to decode all drawable image, make a bitmap fusion and in a post execute load the result bitmap in a single image view. But the asynctask is not the better way to implement, because the user can click on that button many times and each time I have to call new asynctask ..

Are there a clever ways to implement all of this?

Goodbye and thanks a lot :)

EDIT : each layer is a detail that thread can add to that image. For example : a car, a tree, a red ball ecc ecc. In the xml example for me each imageview is a layer, and this is wrong. But I don't know the clever way to implement ..

EDIT2 : Moreover I know the maximum amount of layer, but there are many combinations. there are 3 point and for each point I can choice between 3 differents details

Edit3: i add some details , there is a thread that change laYer and not the user

aeroxr1
  • 1,014
  • 1
  • 14
  • 36
  • 2
    layer? what layer? what do you want to do with that layer? – pskink Sep 26 '15 at 08:15
  • @pskink each layer is a DETAIL that user can add to that image. For example : a car, a tree, a red ball ecc ecc. In the xml example for me each imageview is a layer, and this is wrong. But I don't know the clever way to implement. I edited the first post, and maybe I explained better – aeroxr1 Sep 26 '15 at 08:32
  • extend `BitmapDrawable` then – pskink Sep 26 '15 at 08:40
  • @pskink i extend bitmapDrawable and then ? – aeroxr1 Sep 26 '15 at 09:10
  • and then call `ImageView#setImageDrawable` – pskink Sep 26 '15 at 09:13
  • 1
    Simply position your ImageViews at the same location (i.e.: alignParentTop and alignParentLeft). Done. You don't need any compositing. – Phantômaxx Sep 26 '15 at 09:13
  • 1
    and please, please, don't use any additional `ImageView`s - its a waste of your time, resources and your code readibility – pskink Sep 26 '15 at 09:16
  • @Frank N. Stein is not the same way that I did ? is so expensive.. I have to load this "layer" images at high frequency :/ – aeroxr1 Sep 26 '15 at 09:17
  • 1
    as i said: just extend `BitmapDrawable` and override its `draw` method – pskink Sep 26 '15 at 09:18
  • 1
    @aeroxr1 No, you did not position the ImageViews correctly. Re-read my comment. Then it's only a matter to set the visibility (INVISIBLE/VISIBLE - not GONE). – Phantômaxx Sep 26 '15 at 09:21
  • thanks @pskink, do you suggest to do all of works in the ui thread ? or a better idea is to decode drawable in other thread ? I'm afraid that gc can't clean the not used images and then there is a memory leak :/ – aeroxr1 Sep 26 '15 at 09:22
  • 1
    gc will clean up `Bitmaps` as any other `Objects`: when there is no references to them in your code – pskink Sep 26 '15 at 09:25
  • If the image are changed at high frequency, the gc may have no time to find and remove the image with no references or i'm wrong ? @Frank N. Stein: why do you suggest to me to not use GONE ? my image have all the same pixel dimension, and is all trasparent apart of the details, but there is so many layer, and if I set it into xml is heavy. – aeroxr1 Sep 26 '15 at 09:29
  • 1
    Because GONE is stressful. It requires to recalculate the View positions. – Phantômaxx Sep 26 '15 at 09:31
  • 1
    Another idea is to have just the bare maximum amount of required layers and simply swap their images as needed. – Phantômaxx Sep 26 '15 at 09:32
  • ah ok :) Thanks ! I don't know that problem ! However I think that I will extend the bitmapDrawable, then I will edit the onDraw. But I have to decode drawable to bitmap and I don't know where is bettere to do that. In android example they does this in "worker" thread and not in ui thread. I have never extended the bitmapDrawable :) @Frank N. Stein Moreover I know the maximum amount of layer, but there are many combinations. there are 3 point and for each point I can choice between 3 differents details – aeroxr1 Sep 26 '15 at 09:37
  • 1
    i never seen in the android code that BitmapFactory is run in the background thread, see: ImageView, BitmapDrawable and so on, and if you think that using multiple ImageViews is a more simple solution you will be surprised very soon... Drawable class is that one that should be used for such cases, it does not bite... ;-) a quote from the docs: `"A Drawable is a general abstraction for "something that can be drawn."` – pskink Sep 26 '15 at 09:39
  • Thanks. Before I was referering to this code on android site : http://developer.android.com/training/displaying-bitmaps/process-bitmap.html#async-task – aeroxr1 Sep 26 '15 at 10:15
  • I add some more details in the first post. To Quickly explain i Told to you that the user change detail but in reality is a thread that works at 10hz that loads the right details – aeroxr1 Sep 26 '15 at 10:27

1 Answers1

1

Use the LayerDrawable class, adding new layers as the user enables them. I don't think you can remove layers from it, but you can create a new LayerDrawable each time the user disables a layer. Or you can use setDrawable(int, Drawable) to replace a layer.

This means you don't have to complicate your layouts, and should get rid of those pesky extra inflation/measure/layout passes.

As for the image loading / async task stuff: use an LRU cache for your bitmaps. When a layer is enabled, check the cache, and if it's there, just use it. Otherwise, use an async task to load it.

Snild Dolkow
  • 6,669
  • 3
  • 20
  • 32
  • `I don't think you can remove layers from it` - Try: `setDrawable(int, null)` – Phantômaxx Sep 26 '15 at 10:18
  • Hi ! Thanks to the answer. I add some more details in the first post. To Quickly explain i Told to you that the user change detail but in reality there is a thread that works at 10hz and it loads the right details. – aeroxr1 Sep 26 '15 at 10:28
  • @FrankN.Stein: I don't think that's a good idea. If I'm reading things correctly, that'd make `mDrawable` `null` in [draw()](https://android.googlesource.com/platform/frameworks/base/+/android-5.1.1_r18/graphics/java/android/graphics/drawable/LayerDrawable.java#513), which would give you a NullPointerException. – Snild Dolkow Sep 26 '15 at 10:54
  • @aeroxr1: the answer still applies. Use `LayerDrawable`, swapping out layers periodically. Use a cache for the child drawables that you intend to reuse, so that you don't have to load them repeatedly. – Snild Dolkow Sep 26 '15 at 10:55
  • @SnildDolkow you can `setDrawable` with null, see sources for API 23 – pskink Sep 26 '15 at 11:07
  • @pskink Mind linking it? I wasn't able to find anything like that in the [m-preview-2](https://android.googlesource.com/platform/frameworks/base/+/android-m-preview-2/graphics/java/android/graphics/drawable/LayerDrawable.java) code, at least. Are the real M (api 23) sources released yet? But that made me realize that `LayerDrawable.setDrawable(int, Drawable` is new in api 23, so it wouldn't work on older releases. In that case, I would try a `LayerDrawable` filled with `LevelListDrawable`s, changing the levels for each layer as appropriate. – Snild Dolkow Sep 26 '15 at 11:34
  • see [here](http://mirrors.neusoft.edu.cn/android/repository/sources-23_r01.zip) or just install them with "android" command from your sdk, but honestly playing with null Drawables in LayerList is not a good idea, i would definitely extend `BitmapDrawable` to have the full control of what and when and where is drawn (or even base `Drawable`) – pskink Sep 26 '15 at 11:38
  • Thanks guys ! Thus I have to decide between : layerdrawable vs extends BitmapDrawable and LRU cache yes or not :) – aeroxr1 Sep 26 '15 at 11:52
  • @aeroxr1 if you want just static behavior use `LayerDrawable`, if your `Drawable` has to be changed frequently use custom `BitmapDrawable`, for example you will be not able to use `LayerDrawable` to do things like are done [here](https://github.com/pskink/PatchworkDrawable) – pskink Sep 26 '15 at 12:16
  • In the most negative case I have to change the layer each 5/10 hz .. Do you suggest to me to also use LRU cache ? :) – aeroxr1 Sep 26 '15 at 12:57
  • there are 1 png image for background, there are 3 layer and for each layer I can choice to load between 3 png . Total kb are 150 kb , and in the worst case (xxhdpi image) the size is 1920*1080 – aeroxr1 Sep 26 '15 at 15:16