2

I am drawing a line segment with the specified start and stop x,y coordinates, using the specified paint on the following Bitmap image for each day dynamically -

chart_by_rule (Unexpected in >= 4.4) -

enter image description here

chart_by_rule (Expected) -

enter image description here

The following code should draw the line in the above bitmap. The lines are only drawn in Android versions < 4.4.

This is the code -

@Override
public View onCreateView(LayoutInflater inflater, 
ViewGroup container, Bundle savedInstanceState) 
{
    getActivity().runOnUiThread(new Runnable() 
    {
        @Override
        public void run() 
        {
            getChartLoaded();
        }
    });

}

public void getChartLoaded()
{
    if(dates_array.indexOf(today) == -1 || (redrawChart != null && redrawChart.equals("popback"))  || (getSetting("ZoneIDChanged","0").equals("1"))) 
    {
        redrawChartView(scal, zeroPadding, zeroPaddingDate);
        setSetting("ZoneIDChanged","0");
    } 
    else 
    {
        addChartViews(scal, zeroPadding, zeroPaddingDate);
    }

}

public void redrawChartView(Calendar scal, 
String zeroPadding, String zeroPaddingDate)
{
    Calendar cal = Calendar.getInstance(TimeZone.getTimeZone(driverTimeZone));
    while (scal.compareTo(cal) < 0) {
    cv = new ChartView();
    LinearLayout layout = cv.getChartView(i);
    i++;
    linearLayoutMap.put(date, layout);
    views.add(layout);
    }
}

public class ChartView 
{
    private Paint cPaint;
    float startHours = 0, endHours = 0, 
    startHeight = 0, endHeight = 0,
    scale = 0;

    public LinearLayout getChartView(final int number) 
    {
       getActivity().runOnUiThread(new Runnable() 
       {

          @Override
          public void run() {

          cPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
          cPaint.setStyle(Paint.Style.STROKE);
          cPaint.setColor(Color.BLACK);
          cPaint.setStrokeWidth(3);

          scale = getActivity().getBaseContext().getResources()
          .getDisplayMetrics().density;

          linearlayout = new LinearLayout(getActivity());

          final ImageView img = new ImageView(getActivity());

          BitmapFactory.Options options = new BitmapFactory.Options();
          options.inPurgeable = true;
          newBitmap = BitmapFactory.decodeResource(getResources(),
          chart_by_rule).copy(Bitmap.Config.ARGB_4444, true);
          canvas = new Canvas(newBitmap);
          img.setImageBitmap(newBitmap);
          img.setScaleType(ScaleType.FIT_XY);
          img.setTag(number);       
          float wFactor = (15 * scale);
          float hFactor = (float) ((19.35) * scale);
          float x1 = startHours * wFactor;
          float x2 = endHours * wFactor;
          float y1 = (2 * startHeight - 1) * hFactor;
          float y2 = (2 * endHeight - 1) * hFactor;

          canvas.drawLine(x1, y1, x2, y2, cPaint);
          canvas.save(Canvas.ALL_SAVE_FLAG);
          linearlayout.addView(img);
        }
     });
        return linearlayout;
   }
} 

This code is working fine in all the android versions smaller then 4.4.

In Android OS >= 4.4, I am getting no line drawn with the canvas on my linear layout that contains the image view.

Is there any change in these later OS versions regarding Canvas OR the problem can be somewhere else ?

More: I have different layout files for all the screen layouts.

This was checked with Motorola XT907.

This is the phone specification - http://wiki.cyanogenmod.org/w/Xt907_Info.

sjain
  • 23,126
  • 28
  • 107
  • 185
  • post where you initilized cPaint. – Rod_Algonquin Aug 01 '14 at 08:26
  • @Rod_Algonquin - The code is much more but I tried to put the relevant code. Please look if you can make of it. Thanks! – sjain Aug 01 '14 at 08:37
  • care to format the code a bit? – WarrenFaith Aug 01 '14 at 09:04
  • Have you tried with the emulator? I assume you are using CyanogenMod, make sure that the issue isn't coming from there. – BrainCrash Aug 01 '14 at 09:05
  • The problem is I am trying to run the code with emulator using `Genymotion` but the `Genymotion` is reporting some error (player.exe not responding) in starting the emulator. No, I am not using `CyanogenMod` and don't know about it. – sjain Aug 01 '14 at 09:18
  • @WarrenFaith - I formatted it before. If you want more formatting then please format it accordingly. Right now I have created android emulator to test with android version > 4.3. The emulator is slow but I need to take this option to test. – sjain Aug 01 '14 at 09:48
  • @VedPrakash this is not formatted code. If you have trouble understanding how formatted code should look like, I wonder how you can get 7k+ reputation here... – WarrenFaith Aug 01 '14 at 09:49
  • @WarrenFaith - To help others doesn't requires well formatting to gain reputation if you think it is a criteria. – sjain Aug 01 '14 at 09:55
  • @VedPrakash getting help requires a bit work from your side. Too bad that you don't get it. Personally I don't go through the code because even the first method is bad formatted. Instead of blabla against my criticism you could just have done it. And honestly, you call yourself a Senior with that kind of formatting? You wouldn't pass the first interview for a junior at my place... – WarrenFaith Aug 01 '14 at 10:10
  • @WarrenFaith - Ok I formatted the code a bit as you suggested. I didn't called myself a senior. This is your perception. You remain senior and let's me your junior dear Sir. Well said, I agree what you said. No doubt. – sjain Aug 01 '14 at 10:21
  • Your profile tells in bold that you are a senior: **Sr. Software Engineer (Information Technology)**, just saying... – WarrenFaith Aug 01 '14 at 10:29
  • Your code makes nearly no sense as you have stripped it to much. For example: `onCreateView()` is always called on the UIThread, so no need to wrap code into a runnable to call `runOnUiThread()`. That is also the case for `getChartView()` where you even stripped the complete `LinearLayout` stuff. You have no return statement there. In short: You stripped to much code for us to see anything odd because now nearly everything is odd... (where does Canvas draws on?) – WarrenFaith Aug 01 '14 at 10:33
  • @WarrenFaith - yes my main focus was on the Canvas which is drawing the line. The rest of the code was just a feed to give the general code logic to complete the canvas. I know its difficult to figure it out with the above code. So I just said, `if you know if there are some changes on Android >= 4.4` that any logic with Canvas, DateTimePicker can be affected. Please note that the same code is working on other android versions. I am not having 4.4 to test with. So I am forced to use emulator. Bit slow but the only option to figure out. – sjain Aug 01 '14 at 10:41
  • @WarrenFaith - Canvas draws on `ImageView` and `ImageView` is contained in a LinearLayout. – sjain Aug 01 '14 at 10:51

1 Answers1

2

It is the problem related to DiskLruCache to cache the pages.

NOTE: Where you created the instance of it is important.

DiskLruCache

Java implementation of a Disk-based LRU cache which specifically targets Android compatibility.

The DiskLruCache doc mentions,

This class is tolerant of some I/O errors. If files are missing from the filesystem, the corresponding entries will be dropped from the cache. If an error occurs while writing a cache value, the edit will fail silently. Callers should handle other problems by catching IOException and responding appropriately.

Solution:

I had -

final int DISK_CACHE_SIZE = 1024 * 1024 * memClass / 10;

cache = new DiskLruImageCache(getActivity(), DISK_CACHE_SUBDIR,
        DISK_CACHE_SIZE, CompressFormat.JPEG, 100);

where, DiskLruImageCache is a class.

This cache instance code was at onCreate() method of the fragment.

Removed the code from onCreate() and put it at onCreateView() method of fragment.

Now android 4.4 and greater versions are also showing the bitmap with drawn lines.

That was weird but there seems to be some changes in this respect that created such an issue.

Reuse Bitmaps

Then I found the article to reuse bitmap at whats-changed-in-android-4-4-kitkat.

As stated,

Bitmap.reconfigure() is included to modify an existing instance to fit a new dimension and pixel configuration. BitmapFactory has been updated as well for this reconfiguration behavior to reuse in Bitmap.

You could safely reconfigure an instance from 200×200 at ARGB_8888 to 100×100 at ARGB_8888, and then again to 300×300 at RGB_565, because all of those fit inside the initial allocation. If I tried to reconfigure it to 300×300 at ARGB_8888, however, an exception would be thrown. It is also important to note that you cannot reconfigure a Bitmap while it is attached to a view. This should be done after the element has been detached or moved off-screen.

So if your application can determine a suitable size for a single instance, even if it may be larger than the pixels needed at any given time, you can still reduce memory usage. A single 360KB Bitmap reused for both a 300×300 and 200×200 image (obviously not shown simultaneously) is better for everyone than needing 520KB (360KB + 160KB) for two separate instances.

I hope anyone who may face this issue later will get help from here.

sjain
  • 23,126
  • 28
  • 107
  • 185