Wednesday, May 9, 2012
Gmail Attachment Issues
Android will allow a user to put more than one app on it that does something, for example send email So you have your email account app out of box, your gmail account and let's say a third party super duper email app that you can't live without installed on your phone. When you click the email link, it will launch a picker that lists these three apps. You select the one that you want to process the message and it does it. All fine and dandy. Once that picker comes up, you're out of your app and in the picker app. In other words, you don't have much control over error handling. Here's the problem: Gmail can't process attachments. It throws an exception that can't be caught and I can't control what gets processed by the app. For example, having gmail handle a link to an web site instead of putting the attachment right into the message. The only workaround that I have is a link in the message (the images I'm trying to send are on a web server anyway) to the image which should make it work on every app.
Android bug report
http://code.google.com/p/android/issues/detail?id=27269&q=gmail%20attachments&colspec=ID%20Type%20Status%20Owner%20Summary%20Stars
Google
http://groups.google.com/a/googleproductforums.com/forum/#!category-topic/gmail/android/PsZ68HiLc_o
http://thenextweb.com/mobile/2010/11/10/google-acknowledges-android-gmail-attachment-issues-invites-users-to-help-debug/
Tuesday, May 8, 2012
Debugging HTTP Connections
Most of my Android apps have multiple and sometimes a dozen or so of backend Get, POST and other http api calls. Part of debugging them is figuring out http header request and response data. This code snippet below is a useful utility method that allows you to log out http headers:
public static void logHttpHeaders(Header[] headers)
{
Log.d(TAG,"Logging http headers: " + headers.length );
for (int i = 0; i < headers.length; i++)
{
Header h = headers[i];
Log.d(TAG,"Header: " + h.getName() + " " + h.getValue());
}
}
public static void logHttpHeaders(Header[] headers)
{
Log.d(TAG,"Logging http headers: " + headers.length );
for (int i = 0; i < headers.length; i++)
{
Header h = headers[i];
Log.d(TAG,"Header: " + h.getName() + " " + h.getValue());
}
}
Friday, May 4, 2012
Creating an iPhone like PickerWheel
One of the most useful interfaces that iPhone has is the picker wheel which I like to call roulette wheel. Android date pickers and out of box select boxes are very html-like and not very slick looking. Designing and implementing one that is like the iPhone picker wheel is actually pretty complex/ About two years ago, I put one together for a customer but I was never quite happy with it and it never really felt exactly right. Luckily the Android open source community has lots of really smart folk, doing some great work and if you're looking for a nice interface to extend in your project, this open source wheel project is what you're looking for.
Android Wheel Control. https://code.google.com/p/android-wheel/
I've used it on a couple of projects and it works great. It's relatively easy to customize and has some great sample code that pretty much will do what you need to do out of box. It's one of my favorite Android projects and worth a look to see if it jazzes up your app.
Android Wheel Control. https://code.google.com/p/android-wheel/
I've used it on a couple of projects and it works great. It's relatively easy to customize and has some great sample code that pretty much will do what you need to do out of box. It's one of my favorite Android projects and worth a look to see if it jazzes up your app.
Monday, April 30, 2012
Prevent autolaunch of soft keyboard
Android will want to give focus to an edittext when an activity loads which will automatically popup the soft keyboard. You may not want the keyboard to display until the user taps an edittext field. To prevent Android from launching the keyboard, simply request focus to some other (non-editable) field like a textview like in the code below.
TextView textViewTV = (TextView) findViewById(R.id.mytextview);
textViewTV.setFocusable(true);
textViewTV.setFocusableInTouchMode(true);
textViewTV.requestFocus();
Friday, April 27, 2012
Limiting Debug Trace to your App
I tend to debug on a device rather than an emulater and depending on which device I'm using., there might be tons of logging which basically makes trace statements unusable. Luckily in Eclipse, it's easy to create a log filter to get rid of the messages I don't want to see.
In debug mode, you'll see the logcat trace down at the bottom and probably a saved filter list to the left of the logging. Click the green cross icon and a dialog will popup with a few edit fields. The two that I use the most are Filter name (which gives your saved filter a name :-) ) and by Application Name which will limit trace to whatever application you want. The application name is basically the package name in your android manifest
manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.appulearn.coolapp.android"
So I would paste in com.appulearn.coolapp.android
You can also filter out by TAG, and depending on what I have running (like for example a bunch of services) I might create a tag filter which would match the tag name you use in your log.d(TAG, "whoops! error"); statement.
In debug mode, you'll see the logcat trace down at the bottom and probably a saved filter list to the left of the logging. Click the green cross icon and a dialog will popup with a few edit fields. The two that I use the most are Filter name (which gives your saved filter a name :-) ) and by Application Name which will limit trace to whatever application you want. The application name is basically the package name in your android manifest
manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.appulearn.coolapp.android"
So I would paste in com.appulearn.coolapp.android
You can also filter out by TAG, and depending on what I have running (like for example a bunch of services) I might create a tag filter which would match the tag name you use in your log.d(TAG, "whoops! error"); statement.
Tuesday, April 24, 2012
Message and Handlers
Message and Handlers
Handlers are a useful too for doing a task within a class in response to a change in a variable state or to an action. A common use for a handler is to update the UI once a thread is done processing (if you choose to do it this way versus asynctask.) I often use a handler when I want an activity to do something in response to the completion of a service or to button clicks or to form validation and other things that might generate UI changes. For example, let's say that the app starts up and kicks off a service. When the service completes, it fires an Intent that the activity is listening for which triggers the handler to redirect off a splash screen either to a login screen or a main screen based on what the service returns.
Now how does the activity know what to do? By opening up the intent and getting the bundle. The example below uses a handler to receive a broadcast from a service category download. If the service has processed successfully, the icon will update itself to a success icon, otherwise the error message from the service will be displayed. The service generates an intent with a bundle, and broadcasts it. The activity listens for that broadcast and processes it (code below is basically logging the intent and builds a message out of it to pass to the handler.The trigger to update the UI is a message that I create through a utility method.
private BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { Bundle data= intent.getExtras(); mHaveCategoryError = data.getBoolean(GlobalConstants.EXTRA_ERROR_STATUS, false); mDoRedirect = data.getBoolean(GlobalConstants.EXTRA_DO_REDIRECT, true); String error= data.getString(GlobalConstants.EXTRA_ERROR_MESSAGE); HashMap<String, String> dataList = new HashMap<String, String>(); dataList.put(GlobalConstants.EXTRA_ERROR_MESSAGE, error); Message message = Utils.createMessage(1, dataList); handler.dispatchMessage(message); } }; private Handler handler = new Handler() { @Override public void handleMessage(Message msg) { Bundle b = msg.getData(); String message = b.getString(GlobalConstants.EXTRA_ERROR_MESSAGE); String messageType = b.getString(GlobalConstants.EXTRA_MESSAGE_TYPE); if (messageType!=null && messageType.equals(GlobalConstants.SERVICE_CATEGORIES_DOWNLOAD)){ ImageView iv1 = (ImageView) findViewById(R.id.categorySpinnerView); TextView statusMessageE = (TextView) findViewById(R.id.categoryStatusMessage); Drawable d= getResources().getDrawable(R.drawable.iconsuccess); if (message!=null) { d= getResources().getDrawable(R.drawable.iconalert48); statusMessageE.setText(message); } else { statusMessageE.setText(getResources().getString(R.string.categoriesDownloaded)); } iv1.clearAnimation(); iv1.setImageDrawable(d); } } } public static Message createMessage(int messageId, HashMap<String, String> dataList) { Message msg = new Message(); msg.what=messageId; Bundle data = new Bundle(); if (dataList == null) { dataList= new HashMap<String, String>(); } Set<Entry<String, String>> entries = dataList.entrySet(); Iterator<Entry<String, String>> it = entries.iterator(); while (it.hasNext()) { Entry<String, String> entry = (Entry<String, String>) it.next(); data.putString(entry.getKey(), entry.getValue()); } msg.setData(data); return msg; }
Sunday, April 22, 2012
Showing Progress in a Long Running Process
One of the great things about Android is that there often is several different ways you can implement a specific programming task. Let's say that you want to have some sort of indication that a background process is occurring, for example downloading bootstrap data or posting data to an api or simply displaying a splash screen when the app launches for a few seconds.
Iphone apps use a little spinner icon to denote this.
You could do this as out of box progress bar and there is a DownloadManager api that looks pretty interesting and I'm going to be trying it on my next project. The disadvantage of the progress bar is that phone manufacturers can change the default image associated with it which makes your GUI look different to different users.
Now another approach would be to use an imageview and Android's animation framework to spin an icon. Code is below and it's simple. This allows you to customize the spinning icon to your heart's content. On a surf report app I wrote, I spun a surfboard. On a ski report app, I spun a snowflake. On another Find Your Friend app, I actually spun to two little man images one doing a cartwheel to the left of a "LOADING...." textview and one doing a cartwheel to the right of that textview. You'll see that I'm controlling the visibility of the image view which you set and unset in your asynctask or thread handler.
<ImageView
android:id="@+id/spinnerView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="12dp" android:visibility="invisible" android:layout_centerHorizontal="true" android:layout_below="@id/logo" android:src="@drawable/loadingimagewhite" /> protected void startSpinner() { ImageView iv = (ImageView) findViewById(R.id.spinnerView); iv.setVisibility(View.VISIBLE); Drawable d = getResources().getDrawable(R.drawable.loadingimagewhite); iv.setImageDrawable(d); float width = d.getMinimumWidth() / 2; float height = d.getMinimumHeight() / 2; RotateAnimation a = new RotateAnimation(0, 360, width, height); a.setDuration(3000); a.setRepeatCount(RotateAnimation.INFINITE); a.setInterpolator(new LinearInterpolator()); a.setRepeatMode(RotateAnimation.RESTART); iv.startAnimation(a); } protected void stopSpinner() { ImageView iv = (ImageView) findViewById(R.id.spinnerView); iv.setVisibility(View.INVISIBLE); iv.clearAnimation(); }
Subscribe to:
Posts (Atom)