Custom Toast

Screen Shot 2013-05-04 at 3.48.48 PM

Did you ever feel like the Android Toast as simple and awesome it might be, just lacks some elegance? Well, beautifying it is also simple and we can even use the new Toast with just one like of code in the Android project.

All we have to do is to extend the Toast and use our own custom layout.

Here is what I used for my Toast layout.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/toast"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="@drawable/bg_toast"
    android:orientation="vertical" >

    <TextView
        android:id="@+id/tv_message"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:drawableLeft="@drawable/ic_toast"
        android:textColor="@color/toast_text"
        android:drawablePadding="6dp"
        android:gravity="left|center_vertical" />

</LinearLayout>

Most of the beautifying part is done by our simple background bg_toast.xml. Pick your own colors for background and border.

<?xml version="1.0" encoding="utf-8"?>
<shape
	xmlns:android="http://schemas.android.com/apk/res/android"
	android:shape="rectangle" >
    <corners android:radius="1dp"/>
    <solid android:color="@color/toast_background" />
    <padding
        android:left="8dp"
        android:top="8dp"
        android:right="8dp"
        android:bottom="8dp" />
    <stroke
        android:width="1dp"
        android:color="@color/toast_border" />
</shape>

Here is our class which extends the Toast.

public class MyToast extends Toast {

	public MyToast(Context activityContext, String message, int duration) {
		super(activityContext);
		this.setDuration(duration);
		LayoutInflater inflater = (LayoutInflater) activityContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
		View view = inflater.inflate(R.layout.toast, (ViewGroup) ((Activity) activityContext).findViewById(R.id.toast));
		this.setView(view);
		TextView tv = (TextView) view.findViewById(R.id.tv_message);
		tv.setText(message);
	}
}

With all those in place all we have to do is instantiate it from our activity and display it.

MyToast toast = new MyToast(MyActivity.this, message, Toast.LENGTH_LONG);
toast.show();

This can be made even better by throwing this in a utility class in a static method and calling the method.

public class MyViewUtil {
	
	public static void showToast(Context activityContext, String message) {
		MyToast toast = new MyToast(activityContext, message, Toast.LENGTH_LONG);
		toast.show(); 
	}
}

All we need to do from now is to call this method from any activity we want the Toast to be displayed.

MyViewUtil.showToast(MyActivity.this, "Message to display in Toast");

You might have noticed that I have a image drawable in the TextView in our Toast. You may put other stuff but for a Toast anything more than that might be too much. We may have to use a custom Dialog for such stuff. Finally this is how the final Toast looks from the code above.

Screen Shot 2013-05-04 at 3.49.17 PM

Posted in Android, View | Tagged , , | Leave a comment

Configuring ContentProvider in a library project to access Authority from the child project.

I was working on my library project for our company and did a mistake of implementing a ContentProvider in the library itself. Now this is not a bad thing until you need to use the same library across multiple applications. That’s one of the main reasons for creating a library.. right?

The rule is that the ContentProvider class[name] and Authority should be unique for each ContentProvider. However, when we implement it in a library that is used across multiple apps, each one of them is trying to privately create and access the ContentProvider using the same name and Authority.

So the old ContentProvider implementation looked something like this. [I am including only the relevant snippets]

public class LibraryContentProvider extends ContentProvider {
	
	
	public static final String AUTHORITY = "authority.from.library"; 
	
	public static final Uri URI_DATA = Uri.parse("content://" + AUTHORITY + "/my_data");
	public static final int ALL_ROWS = 1;
	private static final UriMatcher uriMatcher;

	static {
		uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
		uriMatcher.addURI(AUTHORITY, "my_data", ALL_ROWS);
	}

// Rest of the content provider implementation

}

And then from all the classes in the library where we need to access data we just call the content resolver on the public static final Uri from the ContentProvider like this.


context.getContentResolver().query(LibraryContentProvider.URI_DATA, null, selection, selectionArgs, null);

One way of solving this is to let the child application extend the ContentProvider so that each app has its own unique ContentProvider name and provide its own unique Authority string. This approach would mean that I cannot use the static final variables in ContentProvider for the Uri, Authority and UriMatcher.

The refactored ContentProvider in the library looks like this.


public abstract class LibraryContentProvider extends ContentProvider {

	public String AUTHORITY = getAuthority(); 

	public static final String URI_PREFIX = "content://";
	public static final String URI_DATA_POSTFIX = "/my_data";
	
	public Uri URI_DATA_USING_CLIENT_ID = Uri.parse(URI_PREFIX + AUTHORITY + URI_DATA_POSTFIX);
	public static final int ALL_ROWS = 1;

	private UriMatcher uriMatcher;
	{
		uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
		uriMatcher.addURI(AUTHORITY, "my_data", ALL_ROWS);
	}

	// define an abstract method that has to be implemented in the child class.
	public abstract String getAuthority();

//Rest of content provider implementation
}

Now in the actual project using the library create a ContentProvider that extends the ContentProvider from the library project. All it would have is this.

public class ClientContentProvider extends LibraryContentProvider {

	public static final String MY_AUTHORITY = "com.achie.unique.authority.provider";
	
	@Override
	public String getAuthority() {
		return MY_AUTHORITY;
	}

}

Note that the provider tag has to be set in the manifest of the child app with the correct ContentProvider and Authority.
In this case it would be


        <provider
            android:name="my.provider.class.path.ClientContentProvider"
            android:authorities="com.achie.unique.authority.provider" />

This would enable us to use the ContentProvider in the child application since it knows the Authority and the Provider class. But what about accessing the Uri [by using the Authority from child] in the library project. It is not possible for other classes in the Library project to access the Authority from Library’s ContentProvider since it is an abstract class that requires them to know the authority to implement it. This problem can be solved by passing it through another initializer that has to be initialized before any of the classes are called. This method saves the authority string in the preferences and from then on, all we have to do is to read the file to get the preferences.

I have an initializer class in the library which takes in the authority string and saves it in preferences.

public class LibraryInitializer {
	public static void initialize(Context context, String authority) {
		SharedPreferences sp = context.getSharedPreferences("library_preferences", Context.MODE_PRIVATE);
		SharedPreferences.Editor editor = sp.edit();
		editor.putString("data_authority", authority);
		editor.commit();
	}
}

Now, if we are initializing it using this Initializer class, why don’t we just also use this in the ContentProvider? That is because Android initializes the ContentProvider even before the Application is initialized [before the Application class's onCreate method is called]. So ContentProvider requires the Authority String even before we have access to a context.

That finally would enable us to access the ContentResolver for the child Authority from both the library and the child application by accessing the Context. Now how do we access Context from everywhere? Use a singleton Application class as many other developers posted in their blogs and Stackoverflow. Is this the perfect solution? It is a decent one but I still don’t like that the Authority is being passed from a constant instead of being in a String. I currently also need an initialization process even though the ContentProvider itself has access to it through its subclass. I hope to resolve this later but feel free to comment if you have any other suggestions on improving this.

Posted in Android | Tagged , , | Leave a comment