3

I'm using Mono for Android (latest version as of this post) with the Visual Studio plugin to build an Android application. It targets API Level 8, Android 2.2 framework.

The app runs fine on a Motorola Droid running Android version 2.2.2 It crashes with almost no output from the debugger on Motorola Droid X2 running Android 2.3.3

The only output is: The program 'Mono' has exited with code 255 (0xff).

The crash happens in this method on the line that starts with using (Bitmap...

public static Drawable GetDrawable(string url) {
    try {
        HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url);
        using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
        using (Bitmap bitmap = Android.Graphics.BitmapFactory.DecodeStream(response.GetResponseStream())) {
            Drawable image = (Drawable)(new BitmapDrawable(bitmap));
            return image;
        }
    }
    catch {
        return null;
    }
}

If I set a breakpoint on that line it breaks correctly but I can't find anything wrong. If I set a breakpoint after that line the debugger simply detaches and the app force quits.

I have a similar method that returns an object from JSON and it works fine. So, I'm fairly sure it's related to the dynamic bitmap creation but at this point I've tried everything I can think of.

UPDATE:

I just reproduced this problem in a small, self-contained project available here: DrawableTest.zip

Here's the full code:

using System;
using System.Net;
using System.Threading;
using Android.App;
using Android.Widget;
using Android.OS;
using Android.Graphics;
using Android.Graphics.Drawables;

namespace DrawableTest {
    [Activity(Label = "DrawableTest", MainLauncher = true, Icon = "@drawable/icon")]
    public class Activity1 : Activity {

        ImageView mImage;
        Button mButton;
        public const string mImageUrl = "http://i.stpost.com/erez4/erez?src=ProductImages/3576U_02.tif&tmp=MediumLargeG4&redirect=0&headers=proxy";

        protected override void OnCreate(Bundle bundle) {
            base.OnCreate(bundle);

            SetContentView(Resource.Layout.Main);

            mImage = FindViewById<ImageView>(Resource.Id.MyImage);
            mButton = FindViewById<Button>(Resource.Id.MyButton);

            mButton.Click += new EventHandler(mButton_Click);
        }

        void mButton_Click(object sender, EventArgs e) {
            ThreadPool.QueueUserWorkItem(o => AsyncImageLoad());
        }

        private Drawable GetDrawable(string url) {
            try {
                HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url);
                using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
                using (Bitmap bitmap = Android.Graphics.BitmapFactory.DecodeStream(response.GetResponseStream())) {
                    Drawable image = new BitmapDrawable(bitmap);
                    return image;
                }
            }
            catch (Exception e) {
                return null;
            }
        }

        private void AsyncImageLoad() {
            Drawable image = GetDrawable(mImageUrl);

            RunOnUiThread(() => {
                mImage.SetImageDrawable(image);
            });
        }
    }
}
Community
  • 1
  • 1
profexorgeek
  • 1,190
  • 11
  • 21
  • What url are you reading from? That would make it easier to help reproduce the issue. – jonp Sep 24 '11 at 03:00
  • I'm creating a list of products using a custom list adapter. I request JSON for the product list and do a secondary request for the product image. An example image URL would be: http://i.stpost.com/erez4/erez?src=ProductImages/3576U_02.tif&tmp=MediumLargeG4&redirect=0&headers=proxy – profexorgeek Sep 26 '11 at 15:33

2 Answers2

4

This is probably a bug in our Stream mapping code, similar to: http://bugzilla.xamarin.com/show_bug.cgi?id=1054

This should be fixed in the next release (1.9.x, probably).

As a workaround, try copying response.GetResponseStream() into a System.IO.MemoryStream, and then pass the MemoryStream to BitmapFactory.DecodeStream().

Update

I had the right idea, but the wrong approach. Instead of using BitmapFactory.DecodeStream(), use BitmapFactory.DecodeByteArray(). The following code works for me in your DrawableTest.zip app:

private Drawable GetDrawable(string url)
{
    try {
        HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(url);
        using (HttpWebResponse response = (HttpWebResponse) request.GetResponse())
        using (Stream responseStream = response.GetResponseStream()) {
            MemoryStream workaround = new MemoryStream();
            responseStream.CopyTo(workaround);

            Bitmap bitmap = Android.Graphics.BitmapFactory.DecodeByteArray (
                    workaround.GetBuffer (), 0, (int) workaround.Length);
            Drawable image = new BitmapDrawable(bitmap);
            return image;
        }
    }
    catch (Exception e) {
        Log.Error("DrawableTest", "Exception: " + e.Message);
        return null;
    }
}

Note the using blocks to ensure that the resources are disposed.

jonp
  • 13,512
  • 5
  • 45
  • 60
  • Awesome! I'll try that tomorrow and accept this answer if it works. Thanks! – profexorgeek Sep 29 '11 at 03:41
  • Unfortunately the workaround isn't working for me. Still the same fail spot. I updated [DrawableTest.zip](http://yolabs.com/stuff/DrawableTest.zip) with a workaround if you want to test. Either way, thanks and I'll watch for the update. – profexorgeek Sep 29 '11 at 17:49
  • I really appreciate you taking the time to check this out. I won't be back to work until Monday but if it works in the test (assuming you tested with Droid X2) it should work in my main project. (I have using blocks in my actual project. I removed them in the test to present it as simply as possible). – profexorgeek Sep 30 '11 at 15:52
  • I confirmed that your updated workaround solves the problem. Thanks again for your responsiveness and assistance solving this. Everything now works correctly on the Droid X2. – profexorgeek Oct 03 '11 at 15:07
1

Try running without the debugger (Ctrl-F5), and then checking the Android Debug Log for the exception:

http://android.xamarin.com/Documentation/Guides/Android_Debug_Log

jpobst
  • 9,982
  • 1
  • 29
  • 33
  • I was unaware of this tool so thanks for the suggestion. FWIW the Debug Log caused VS to force-quit a few times. I did get output and extracted the relevant bits. The main error is: `ERROR: Unable to detach current thread from the Java VM!` My first reaction is that it might have to do with the fact that the Droid X2 is a dual-core device and I'm inexperienced at multi-threading. I have more research to do but here's the relevant bits of the log if you're interested. I'll post here if I find an answer. http://pastebin.com/mugayGuv – profexorgeek Sep 26 '11 at 19:45
  • 1
    @dubj Is this a Release or Debug build? If this is a Release build, and you're running on a SMP machine (which you say you are), then you must also include the armeabi-v7a runtime. The default armeabi runtime is not SMP safe (as ARMv5 has no SMP support at all). – jonp Sep 26 '11 at 21:19
  • This is a debug build but I'm confused about your comment. When I deploy to market I need one app to run on multiple machines. It sounds like you're saying I need a specific build for SMP devices? Additionally, why would something like that vary between release and debug? Shouldn't it break both? I just repro'd the problem in a tiny project that I will be posting for reference. – profexorgeek Sep 27 '11 at 14:42