Wednesday, December 21, 2011

'Tis the season for sharing (via your Android code)


Come Facebook, come Twitter, come Tumblr and Flickr!

No app is an island, we often want to be able to share the cool things we create with our apps with the world, whether it's the latest social network to on-sell our personal details, or just plain old email to your gran.



.. And here's how.

Lets say we have an image file located here:
String fileLocation = "/mnt/sdcard/SomeMediaFiles/aMediaFile10.jpg"

We can share this easily by passing the reference to our file location into the below method:
 
    public void shareFile(String newFilePath) {
      {Intent share = new Intent(Intent.ACTION_SEND);
      share.setType("image/jpeg"); 
 
//declare the MIME type of the file. .. What you pass into share.setType determines what apps appears in your Sharing list.

      Uri imageUri = Uri.fromFile(new File(newImagePath));
      share.putExtra(Intent.EXTRA_STREAM, imageUri);
   
      startActivity(Intent.createChooser(share, "Share"));
 }
}
And this is basically what is the result (actual apps listed will depend on what is installed on your users device):


... Easy.


Saturday, December 10, 2011

OutOfMemory errors when populating a Gallery


I've just spent the last couple of hours wrestling with OutOfMemory errors when populating a Gallery widget with photos, and as fun as it's been, I think I've sorted it out and thought I'd share my solution with you.

For starters, the reason we're getting OutOfMemory errors in the first place is that the heap size on Android devices is limited to something like 16 MB on a G1 and 24 MB on a Nexus one.

As soon as you start to work with media files you quickly start to learn that you need to work to manage your memory usage with Android as a result of this limitation.

I would also like to thank direct to device debugging, I couldn't have done this without utilizing it, I would go as far as saying that it is essential in situations like this.

Here is the full code of one of my imageAdapters,  I'm using this to provide the images to my Gallery widget like this:

galleryTop.setAdapter(new ImageAdapterTop(this));


The Adapter class :

public class ImageAdapterTop extends BaseAdapter {
   int mGalleryItemBackground;
   private Context mContext;


    File[] allTopSlices = Utils.getAllTopSlices();  
    String[] fullPathAllTopSlices = new String[allTopSlices.length];
    Uri[] uriAllTopSlices = new Uri[fullPathAllTopSlices.length];


   public ImageAdapterTop(Context c) {
       mContext = c;
       TypedArray a = obtainStyledAttributes(R.styleable.HelloGallery);
       mGalleryItemBackground = a.getResourceId(
               R.styleable.HelloGallery_android_galleryItemBackground, 0);
       a.recycle();
   }


   public int getCount() {
       return uriAllTopSlices.length;
   }


   public Object getItem(int position) {
       return position;
   }


   public long getItemId(int position) {
       return position;
   }


   public View getView(int position, View convertView, ViewGroup parent) {
    int screenHeightPx = Utils.GetScreenHeight(getWindowManager().getDefaultDisplay());
   
    for(int i = 0; i < allTopSlices.length; i++){
    fullPathAllTopSlices[i] = allTopSlices[i].getAbsolutePath();
    }
   
    for(int j=0; j < fullPathAllTopSlices.length; j++){
    uriAllTopSlices[j] = Uri.parse(fullPathAllTopSlices[j]);
    }
   
       ImageView i = new ImageView(mContext);
     
       recycleDrawable(i);


       i.setImageBitmap(Utils.readBitmap(uriAllTopSlices[position].toString()));
     
       i.setLayoutParams(new Gallery.LayoutParams(400, (screenHeightPx-50) /3));
       i.setScaleType(ImageView.ScaleType.FIT_XY);      
       i.setBackgroundResource(mGalleryItemBackground);


       System.gc();
       return i;
     
   }
}



and the referenced recycleDrawable :

private void recycleDrawable(ImageView i) {
BitmapDrawable currentBitmapDrawable = (BitmapDrawable)i.getDrawable();

if(currentBitmapDrawable != null){
currentBitmapDrawable.getBitmap().recycle();        
}
        System.gc();
}



and readBitmap methods:

public static Bitmap readBitmap(String selectedImage) {
Bitmap bm = null;
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 8;


try {
bm = BitmapFactory.decodeFile(selectedImage, options);
}
catch (OutOfMemoryError e) {
e.printStackTrace();
}

return bm;
}

Probably worth mentioning that the 'options.inSampleSize' reference, which is downsizing the image is pretty much essential when working with large files with the memory constraints associated with current Android devices.

Hope that helps someone out there.


Sunday, November 20, 2011

'An error has occurred' when working with Bitmaps



On a recent project I needed to rotate and slice images taken from the camera, and I found that I was getting regular, but annoying to track down 'an error has occurred' messages.

I couldn't see anything in particular that was wrong with my code, and what made it worse was that I wasn't receiving any errors at all in the emulator, only when I deployed the app to my phone for testing.

It took a few hours to figure out what was going on, so I thought I'd share it here and maybe save somebody else some time.

Like a lot of errors, it seemed painfully obvious after the fact, but the cause was I was basically running out of memory when creating the bitmap objects below. From my experience, you can only create one or two bitmap objects before you will encounter issues like this, because the heap size on Android devices is limited to something like 16 MB on a G1 and 24 MB on a Nexus one.
.. That's not a lot of 6 MB photos.

Luckily, it's super easy to fix.
All you need to do is recycle the bitmaps once you've finished with them, as per below code, and as pointed out by Romain Guy here,

"..The problem is that it can take a couple of GC cycles for a Bitmap to be properly released on Android before Android 3.x. Even if you call recycle() I believe the bitmap counts against your heap usage until at least the next GC. This is one of the very few situations where I would advise you to force a GC by calling System.gc()."

Matrix mat = new Matrix();
mat.postRotate(90);

Bitmap photoRotated = Bitmap.createBitmap(bitmapToSave, 0, 0, bitmapToSave.getWidth(), bitmapToSave.getHeight(), mat, false);

Bitmap photoCut1 = Bitmap.createBitmap(photoRotated, 0, 0, photoRotated.getWidth(), heightOfSlice);

photoRotated.recycle();

//save photoCut1 bitmap here

photoCut1.recycle();
System.gc();


So don't forget to recycle and call System.gc() a couple of times when working with large files like images and hopefully, like me, your errors messages will disappear.

Monday, June 13, 2011

How to get the size and orientation of your device screen



Found this great snippet over at http://www.androidsnippets.com/ that allows you to find the size and orientation of the device screen at runtime, and thought I'd share it:

/* First, get the Display from the WindowManager */
Display display = ((WindowManager) getSystemService(WINDOW_SERVICE)).getDefaultDisplay();

/* Now we can retrieve all display-related infos */
int width = display.getWidth();
int height = display.getHeight();
int orientation = display.getOrientation();
// see http://androidsnippets.com/get-size-and-orientation-of-the-screen

Saturday, May 28, 2011

How do you make money with your Android app?

Free?
Obviously not the best way to make money, but a good way to get your name out there, and earn some good karma points while you're at it.

Advantages: maximum exposure to users, everyone who might possible have a use for it considers a free app and will probably install your app even temporarily. You get an opportunity to impress them and build a trusted name with them. The Android Market also lists other apps by the same developer, so viewers of your free apps on the market will be exposed to anything else you publish, driving traffic towards any other apps you might have.

Disadvantages: Without charging for the app itself, you have to use advertising or in-app purchases or other tie-ins in order to make money (see next).


Free with Ads?

Advantages: Ad providers such as admob support house ads, which is advertising for your own products. This opens another opportunity to use your free apps to drive traffic towards any paid apps you might have, or other free offerings too.

Disadvantages:

Advertising sdk's usually add an additional weight to your app size, and there's the obvious loss of screen real-estate also. Additionally, people have to actually use your app in order to see and hopefully click on the ads, so unless your app involves a decent amount of user interaction this might not be for you. To make the most of advertising you want to have an app that keeps users coming back to the screen. Something like a countdown timer for instance might not be so suitable for an advertising-based revenue model as the concept involves minimum user face time, users typically set the timer and turn off the screen.

Advertising platforms:


Free with in-app purchases?
Advantages: You get users in the door and using your app, now you can ply them with the ability to purchase additional related goods in-app. Micro-payment systems mean that your users have the option of adding custom content for mere cents, all within the bounds of your free app, and an app that might not generate much interest even at the lowest price point (usually 99c), is able to still generate income. You get the user mass by distributing your core app for free, and then can utilise novelty-driven or premium-functionality requirements towards generating income. Can also be combined with Advertising, but be mindful of how this can adversely affect user perception of your app.

Disadvantages: more complex to implement that advertising, and obviously requires actual additional content which not all apps are suited to. Micropayment systems not available in all countries.

In-app billing/virtual goods/virtual currencies:

Free cut-down or trial version and paid 'pro' version?
Advantages: Similar to in-app purchases and other 'freemium' techniques, you introduce the users to the concept of your app in the free version, then hope that some of these users are willing to pay for additional content once your free version has earned their respect.

Disadvantages: Unlike in-app purchases and the micro-payment model, the paid 'pro' version is restricted by the minimum price point of the market through which you're distributing your app which in the case of the Android Market is 99c. If you don't have the additional content to warrant meeting that initial price threshold, you're flat out of luck.


Paid?

Advantages: You make profit upfront, regardless of how much someone uses your app, and regardless of even if they keep it installed. Once they've past that initial 15 minutes to refund, you profit.

Disadvantages: Android users are a notoriously stingy bunch, although as more Android users could be considered the mainstream demographic rather than the tech-head early adopters, this may change. Piracy can also be an issue, so make use of the licensing validation library provided by Google. Paid apps also run the risk of being undersold by a competing free product that relies on one of the other methods above to generate income. Also, as strange as it might seem, many users balk when confronted with the option of paying 99c for an app for their $500 device.






Wednesday, March 23, 2011

Creating a simple border with rounded corners for a layout or view

not the border in question..


Hi all, just thought I'd post this simple snippet that I've just found.
This allows you to simply add a border ( even with rounded corners!) to a layout or view.

All you need to do is create a new xml file somewhere in /res/drawable called 'the_border.xml'
with this or similar as the contents:

<shape xmlns:android="http://schemas.android.com/apk/res/android"> 
    <stroke android:width="1dp" android:color="#FFFFFF" /> 
    <padding android:left="7dp" android:top="13dp" 
            android:right="7dp" android:bottom="17dp" /> 
    <corners android:radius="4dp" /> 
</shape> 

You can then reference this as the background of an item in your layout like this (in xml)

android:background="@drawable/the_border"

or like this in code:

llErrorMessage.setBackgroundResource(R.drawable.the_border);

Nice eh?

Wednesday, March 16, 2011

My new Android app, 'Herbert the Herb & Spice Helper' now available on the Android Market



My new Android app, 'Herbert the Herb & Spice Helper' is now available on the Android Market.


Here's the blurb: "With over 70 herbs and spices, 50+ ingredients and 19 different meal styles, you'll never be lost in your kitchen again.
Herbert the Herb & Spice Helper allows you to mix and match ingredients and meal styles to see what combinations are best.
Each herb and spice comes with a list of compatible herb and spices, and also what you can use instead, so you don't have to run to the supermarket at the last moment."


Oh what? You want screenshots?
Ok, here you go:








A veritable bargain at only 99c AU
Get it here.

Wednesday, February 23, 2011

Android 3.0 ‘Honeycomb’ SDK now available


Google’s Android developer team has announced the first Android 3.0 (API Level: 11) software developer kit is available to developers to create apps and widgets for tablet devices.

Android 3.0 is a new version of the Android platform that is specifically optimised for devices with larger screen sizes, particularly tablets. It introduces a brand new 'holographic' UI design, as well as an elegant, content-focused interaction model.


New features include:

· UI Builder improvements in the ADT Plugin, including a new Palette tool with categories and rendering previews, more accurate rendering of layouts to more faithfully reflect how the layout will look on devices, including rendering status and title bars to more accurately reflect screen space actually available to applications.

Selection-sensitive action bars to manipulate View properties.

Zoom improvements (fit to view, persistent scale, keyboard access)

Improved support for layouts, as well as layouts with gesture overlays.

Traceview integration for easier profiling from ADT.

Tools for using the Renderscript graphics engine: the SDK tools now compiles .rs files into Java Programming Language files and native bytecode.


Fragments

A fragment is a new framework component that allows you to separate distinct elements of an activity into self-contained modules that define their own UI and lifecycle. To create a fragment, you must extend the Fragment class and implement several lifecycle callback methods, similar to an Activity. You can then combine multiple fragments in a single activity to build a multi-pane UI in which each pane manages its own lifecycle and user inputs.

You can also use a fragment without providing a UI and instead use the fragment as a worker for the activity, such as to manage the progress of a download that occurs only while the activity is running.

Fragments are self-contained and you can reuse them in multiple activities.

You can add, remove, replace and animate fragments inside the activity
You can add fragments to a back stack managed by the activity, preserving the state of fragments as they are changed and allowing the user to navigate backward through the different states
By providing alternative layouts, you can mix and match fragments, based on the screen size and orientation
Fragments have direct access to their container activity and can contribute items to the activity's Action Bar.


New animation framework

The platform includes a flexible new animation framework that lets developers easily animate the properties of UI elements such as Views, Widgets, Fragments, Drawables, or any arbitrary object. Animations can create fades or movement between states, loop an animated image or an existing animation, change colors, and much more. Adding animation to UI elements can add visual interest to an application and refine the user experience, to keep users engaged.


Hardware-accelerated 2D graphics

Android 3.0 offers a new hardware-accelerated OpenGL renderer that gives a performance boost to many common graphics operations for applications running in the Android framework. When the renderer is enabled, most operations in Canvas, Paint, Xfermode, ColorFilter, Shader, and Camera are accelerated. Developers can control how hardware-acceleration is applied at every level, from enabling it globally in an application to enabling it in specific Activities and Views inside the application.


Renderscript 3D graphics engine

Renderscript is a runtime 3D framework that provides both an API for building 3D scenes as well as a special, platform-independent shader language for maximum performance. Using Renderscript, you can accelerate graphics operations and data processing. Renderscript is an ideal way to create high-performance 3D effects for applications, wallpapers, carousels, and more.


Support for multicore processor architectures

Android 3.0 is the first version of the platform designed to run on either single or multicore processor architectures. A variety of changes in the Dalvik VM, Bionic library, and elsewhere add support for symmetric multiprocessing in multicore environments. These optimizations can benefit all applications, even those that are single-threaded. For example, with two active cores, a single-threaded application might still see a performance boost if the Dalvik garbage collector runs on the second core. The system will arrange for this automatically.


System clipboard

Applications can now copy and paste data (beyond mere text) to and from the system-wide clipboard. Clipped data can be plain text, a URI, or an intent.

By providing the system access to the data you want the user to copy, through a content provider, the user can copy complex content (such as an image or data structure) from your application and paste it into another application that supports that type of content.

.. and more!

Sunday, February 13, 2011

TextView background is black when setting colour from xml?


I had a colour defined in a 'colours.xml' file in my project's 'values' folder like so:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="tvBackground">#337700</color>
</resources>

Which, for those of you who cannot transpose directly from hex, looks like this:

My code looked like this:

   TextView tv = new TextView(getApplicationContext());
       
   tv.setBackgroundColor(R.color.tvBackground);

Seems reasonable doesn't it?

But when I ran my code, my shiny new little TextView came out with the background colour of this:


(that's #000000 in hex, or 'black' btw)

What was going on here?
Turns out, I wasn't using the correct method to set the background colour so that it comes out correctly, what I should have used was either of these:

   tv.setBackgroundResource(R.color.tvBackground);
- or -
   tv.setBackgroundColor(getResources().getColor(R.color.tvBackground));


.. Not especially well documented, but easily fixed.


Anyhow, now my TextView shows with the background colour of:


.. So all is now well with the world. Thought I'd just post this in case it helps someone out there (or myself when I forget next time)


until that next time, bye bye.


Monday, February 7, 2011

Wino the Wine Advisor now updated, new features & grrraphics


I've recently released an update for my Wino the Wine Advisor app,
The new version now allows you to combine tastes and also has some great new wine bottle graphics (even if I do say so myself).

Here are some screenshots:





.. And I have to say, those wine bottle images were an absolute pain to create.

I use Gimp and Inkscape to create all my graphics, in case you were wondering.




Sunday, January 23, 2011

How to get images dynamically


Lets say you're storing items in a slqite db for your new, soon-to-be-award-winning application, and one of the columns you're storing is the name of the image to associate with that item.

How on earth do you reference it from within your app so you can display it?
Good question! Here's how:


//first get a reference to the ImageView in our XML layout file we want to display the image in..

ImageView imgVw = (ImageView) customView.findViewById(R.id.imgVwInXML);

//Next check that there is actually an image file name in the db column:

if (OurDBCursor.getString(OurDBCursor.getColumnIndex("imageName")) != null) 
{
 
//if there is a name for the image, get that name..

  myImageName  = OurDBCursor.getString(OurDBCursor.getColumnIndex("imageName"));  
 

//get a reference to the image (located in our drawable folder in our project):
          
  int resID = getResources().getIdentifier("com.BlueMongo.Test:drawable/" + myImageName, null, null);  
 

//assign the resouce with that ID to our ImageView:
               
  imgVw.setImageResource(resID);
}

.. And that's it.

Hope that helps. Have a great day.