CoderzHeaven

July 5, 2013

Handling Multiple Instances of a Widget in Android and Identifying each instance with it’s own ID.

Hey everyone…….Hope all are well…..

This post is about Android Widgets.
This is going to be one of the bigger posts in Coderzheaven.

This posts helps you to handle multiple instances of a Widget.
Many of our problem is to identify different instances of the same widget.

But there is a solution to this problem.

Please check out my other posts in Coderzheaven to get an Idea of Android Widgets and it’s working.

Create new Widget


http://www.coderzheaven.com/2012/06/15/placing-controls-widget-android-listening-events-them/

How to get Notified when a widget is deleted?

Here is how we start.

First of all you need to keep these things about the Widget in Mind.

    1. Every instance of Same Widget is associated with a Unique ID.
    2. Widgets ID’s are sent through in the activities that has the “android.appwidget.action.APPWIDGET_CONFIGURE” intent-filter.
    3. RESULT_OK should sent back to the widget

Now we will start.

First we will look at the layouts.

This is the Widget Layout.
widget_main.xml

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:id="@+id/widget_root"android:layout_width="fill_parent"android:layout_height="wrap_content"android:layout_gravity="center"android:baselineAligned="false"android:orientation="vertical"android:background="@drawable/theme0" ><TextViewandroid:id="@+id/textView1"android:layout_width="fill_parent"android:layout_height="wrap_content"android:text="Widget Text"android:gravity="center"android:textAppearance="?android:attr/textAppearanceLarge" /></LinearLayout>

Now the widgetprovider XML.

<?xml version="1.0" encoding="utf-8"?><appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"android:minWidth="250dip"android:minHeight="72dip"android:updatePeriodMillis="100000"android:configure="com.coderzheaven.multiplewidgetinstance.SettingsPage"android:initialLayout="@layout/widget_main"/>

Please note that you have to use the exact package name with the class named you used as Configure Intent-filter in the “android:configure” property.

Now the XML for the settings Page.

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:padding="20dp"tools:context=".MainActivity"android:background="@drawable/theme0"><TextViewandroid:id="@+id/id_tv"android:paddingBottom="20dp"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_centerHorizontal="true"android:textStyle="bold"android:textSize="18dp"android:text="@string/hello_world" /><EditTextandroid:id="@+id/editText1"android:layout_width="fill_parent"android:layout_height="wrap_content"android:layout_below="@+id/id_tv"android:ems="10" ><requestFocus /></EditText><Buttonandroid:id="@+id/button1"android:layout_width="fill_parent"android:layout_height="wrap_content"android:layout_below="@+id/editText1"android:textStyle="bold"android:text="Save" /></RelativeLayout>

Please check the above screenshot how it looks like when clicking on the widget.
It is having an edittext in which we will enter the value for the widget.

Our all layout xml are now complete.
Now we will go to the java classes.

We will write the MyAppWidgetProvider class

MyAppWidgetProvider.java

package com.coderzheaven.multiplewidgetinstance;import android.appwidget.AppWidgetManager;import android.appwidget.AppWidgetProvider;import android.content.Context;import android.content.Intent;public class MyAppWidgetProvider extends AppWidgetProvider {@Overridepublic void onUpdate(Context context, AppWidgetManager appWidgetManager,int[] appWidgetIds) {}/** This is called when an instance the App Widget is created for the first* time.*/@Overridepublic void onEnabled(Context context) {super.onEnabled(context);}/** This is called for every broadcast and before each of the above callback* methods.*/@Overridepublic void onReceive(Context context, Intent intent) {super.onReceive(context, intent);}/** This is called When all instances of App Widget is deleted from the App* Widget host.*/@Overridepublic void onDisabled(Context context) {// Unschedule any timers and taskssuper.onDisabled(context);}/** This is called every time an App Widget is deleted from the App Widget* host.*/@Overridepublic void onDeleted(Context context, int[] appWidgetIds) {// Unschedule any timers and taskssuper.onDeleted(context, appWidgetIds);}}

Please make sure you read the comments in this java, so I am providing any description for that.

Now the SettingsPage that edit the widget.

package com.coderzheaven.multiplewidgetinstance;import android.app.Activity;import android.app.PendingIntent;import android.appwidget.AppWidgetManager;import android.content.Intent;import android.content.SharedPreferences;import android.os.Bundle;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.EditText;import android.widget.RemoteViews;import android.widget.TextView;public class SettingsPage extends Activity {int thisWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID;public static String ACTION_WIDGET_CONFIGURE = "WIDGET_CONFIGURED";SharedPreferences customSharedPreference;EditText ed = null;Button save = null;TextView widgetId = null;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);ed = (EditText) findViewById(R.id.editText1);save = (Button) findViewById(R.id.button1);widgetId = (TextView) findViewById(R.id.id_tv);save.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View arg0) {updateWidget();if (ed.getText().toString().trim().length() > 0) {saveToPreferences("Widget" + thisWidgetId, ed.getText().toString().trim());setResultDataToWidget(RESULT_OK);} elsesetResultDataToWidget(RESULT_CANCELED);}});getIdOfCurrentWidget(savedInstanceState);}/** Get the Id of Current Widget from the intent of the Widget **/void getIdOfCurrentWidget(Bundle savedInstanceState) {setResult(RESULT_CANCELED);Bundle extras = getIntent().getExtras();if (extras != null) {thisWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID,AppWidgetManager.INVALID_APPWIDGET_ID);if (getWidgetData("Widget" + thisWidgetId) != null) {save.setText("Update");ed.append(getWidgetData("Widget" + thisWidgetId));}widgetId.setText("Widget ID = " + thisWidgetId);}// If they gave us an intent without the widget id, just bail.if (thisWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID) {finish();}}/*** Update the Current Widget - This is very important to ensure the widget* is enabled**/void updateWidget() {AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(this);RemoteViews remoteViews = new RemoteViews(getPackageName(),R.layout.widget_main);Intent clickIntent = getIntent();clickIntent.setAction(ACTION_WIDGET_CONFIGURE);remoteViews.setTextViewText(R.id.textView1, ed.getText().toString().trim());clickIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, thisWidgetId);PendingIntent pendingIntent = PendingIntent.getActivity(this,thisWidgetId, clickIntent, 0);remoteViews.setOnClickPendingIntent(R.id.widget_root, pendingIntent);// update this widgetappWidgetManager.updateAppWidget(thisWidgetId, remoteViews);}void setResultDataToWidget(int result) {Intent resultValue = new Intent();resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, thisWidgetId);setResult(result, resultValue);finish();}public void saveToPreferences(String file_name, String data) {SharedPreferences myPrefs = getSharedPreferences("Data",MODE_WORLD_WRITEABLE);SharedPreferences.Editor prefsEditor = myPrefs.edit();prefsEditor.putString(file_name, data);prefsEditor.commit();}public String getWidgetData(String file_name) {SharedPreferences myPrefs = getSharedPreferences("Data",MODE_WORLD_READABLE);return (myPrefs.getString(file_name, null));}}

Now the AndroidManifest File.
Make sure you carefully read the Manifest files. Look at the intent filters in the activities and make sure that you have the correct package name in the provider xml file.

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android"package="com.coderzheaven.multiplewidgetinstance"android:versionCode="1"android:versionName="1.0" ><uses-sdkandroid:minSdkVersion="8"android:targetSdkVersion="17" /><applicationandroid:allowBackup="true"android:icon="@drawable/ic_launcher"android:label="@string/app_name"android:theme="@style/AppTheme" ><activityandroid:name="com.coderzheaven.multiplewidgetinstance.SettingsPage"android:configChanges="keyboardHidden|orientation"android:label="@string/app_name"android:theme="@android:style/Theme.Dialog"><intent-filter><action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" /></intent-filter></activity><!-- Broadcast Receiver that will process AppWidget Updates --><receiverandroid:name="com.coderzheaven.multiplewidgetinstance.MyAppWidgetProvider"android:label="@string/app_name" ><intent-filter><action android:name="android.appwidget.action.APPWIDGET_UPDATE" /></intent-filter><meta-dataandroid:name="android.appwidget.provider"android:resource="@layout/my_widget_provider" /></receiver></application></manifest>

Hooray you multiple instance code is complete.
Here we are saving data for each widget in the preferences with the widgetId as key with which we are reloading the data and editing it.

You can download the complete source code from here.

Comments are closed.

');isvalidName=false;}else{isvalidName=true;$n(element).html('');}}else{var element=$n("#yourname").next().next();$n(element).html('
This field is required.
');emailAdd=false;}if(emailAdd!=""){var element=$n("#youremail").next().next();if(emailAdd.toLowerCase()=='Email'.toLowerCase()){$n(element).html('
This field is required.
');isvalidEmail=false;}else{var JsRegExPatern = /^\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/if(JsRegExPatern.test(emailAdd)){isvalidEmail=true;$n(element).html('');}else{var element=$n("#youremail").next().next();$n(element).html('
Please enter valid email address.
');isvalidEmail=false;}}}else{var element=$n("#yourname").next().next();$n(element).html('
This field is required.
');isvalidEmail=false;}if(isvalidName==true && isvalidEmail==true){$n(".AjaxLoader").show();$n('#mysuccess_msg').html('');$n('#mysuccess_msg').hide();$n('#myerror_msg').html('');$n('#myerror_msg').hide();var nonce ='a24d10d1c1';var url = 'http://www.coderzheaven.com/wp-content/plugins/email-subscribe/';var email=$n("#youremail").val();var name =$n("#yourname").val();var str="action=store_email&email="+email+'&name='+name+'&sec_string='+nonce;$n.ajax({type: "POST",url: 'http://www.coderzheaven.com/wp-admin/admin-ajax.php',data:str,async:true,success: function(msg){if(msg!=''){var result=msg.split("|");if(result[0]=='success'){$n(".AjaxLoader").hide();$n('#mysuccess_msg').html(result[1]);$n('#mysuccess_msg').show();setTimeout(function(){$n.fancybox_ns.close();},2000);}else{$n(".AjaxLoader").hide();$n('#myerror_msg').html(result[1]);$n('#myerror_msg').show();}}}});}}