Using listview in home screen widget in Android


Hi Android developer. I am Android beginner. In my application, i have to provide home screen widget to display meeting schedules in a listview. The meeting data will be taken from a web service every time there is meeting added into my database. I can make a notification to android devices using GCM when the meeting is added .I have searched the web about using listview in widget but i did not get any good anwser. Please guide me step by step to accomplish my goal.
home screen widget listview

By Mike.Jo asked on 2015-09-21
answer to this question

yuk.dara
By yuk.dara

I hope the following steps will hep you setup home screen widget in your applicaiton.
1. In the res/layout directory, you create widget_layout.xml file to make layout of your widget. In the layout file, you add a listview and a textview. The listview shows your meeting data from the web and the textview is used to display a message when there is no data to show. Here is an example:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#f8f8f8"
>
<ListView
android:id="@+id/list_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:loopViews="true" />
<TextView
android:id="@+id/empty_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
style="@android:style/TextAppearance.Medium"
android:layout_gravity="center"
android:layout_margin="4dp"
android:text="No meeting"
/>
</LinearLayout>

2. In the res/xml directory, you create widget_info.xml file that defines properties of your widget. Content of the file must start with the appwidget-provider tag.
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:minWidth="250dp"
android:minHeight="200dp"
android:updatePeriodMillis="0"
android:initialLayout="@layout/widget_layout"
android:resizeMode="horizontal|vertical"
android:widgetCategory="home_screen">
</appwidget-provider>

3. You create widget_item.xml file in the res/layout directory. It defines row template of the listview.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/item"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>

4. You create MyWidgetProvider class to be a sub-class of AppWidgetProvider. The AppWidgetProvider is a broadcast receiver class. onReceive() method is called when there is a broadcast intent to update the listview. This intent will be sent from GCM service class. When it receives the intent the onUpdate method will be called to refresh data in the listview.

import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.util.Log;
import android.widget.RemoteViews;
public class MyWidgetProvider extends AppWidgetProvider {
public static final String UPDATE_MEETING_ACTION = "android.appwidget.action.APPWIDGET_UPDATE";
public static final String EXTRA_ITEM = "com.example.edockh.EXTRA_ITEM";

public void onReceive(Context context, Intent intent) {
AppWidgetManager mgr = AppWidgetManager.getInstance(context);
if (intent.getAction().equals(UPDATE_MEETING_ACTION)) {
int appWidgetIds[] = mgr.getAppWidgetIds(new ComponentName(context,MyWidgetProvider.class));
Log.e("received", intent.getAction());
mgr.notifyAppWidgetViewDataChanged(appWidgetIds, R.id.list_view);

}
super.onReceive(context, intent);
}
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {

// update each of the app widgets with the remote adapter
for (int i = 0; i < appWidgetIds.length; ++i) {

// Set up the intent that starts the ListViewService, which will
// provide the views for this collection.
Intent intent = new Intent(context, ListViewWidgetService.class);
// Add the app widget ID to the intent extras.
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetIds[i]);
intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME)));
// Instantiate the RemoteViews object for the app widget layout.
RemoteViews rv = new RemoteViews(context.getPackageName(), R.layout.widget_layout);
// Set up the RemoteViews object to use a RemoteViews adapter.
// This adapter connects
// to a RemoteViewsService through the specified intent.
// This is how you populate the data.
rv.setRemoteAdapter(appWidgetIds[i], R.id.list_view, intent);
// Trigger listview item click
Intent startActivityIntent = new Intent(context,MainActivity.class);
PendingIntent startActivityPendingIntent = PendingIntent.getActivity(context, 0, startActivityIntent, PendingIntent.FLAG_UPDATE_CURRENT);
rv.setPendingIntentTemplate(R.id.list_view, startActivityPendingIntent);
// The empty view is displayed when the collection has no items.
// It should be in the same layout used to instantiate the RemoteViews object above.
rv.setEmptyView(R.id.list_view, R.id.empty_view);
//
// Do additional processing specific to this app widget...
//
appWidgetManager.updateAppWidget(appWidgetIds[i], rv);
}
super.onUpdate(context, appWidgetManager, appWidgetIds);
}
}

5. You declare MyWidgetProvider class in androidmanifest file. The action name must be android.appwidget.action.APPWIDGET_UPDATE.
<receiver android:name=".MyWidgetProvider" >
<intent-filter >
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/widget_info" />
</receiver>

6. A widget that uses a listview (collection view) needs a RemoteViewSerice to provide data service to the listview. The RemoteViewService uses RemoteViewsFactory to bind data to the listview. In the onDataSetChanged() method of the RemoteViewsFactory, you run a task to fetch data from the web and add them to an arraylist.
Here is an example of RemoteViewService and RemoteViewsFactory.

public class ListViewWidgetService extends RemoteViewsService {

public RemoteViewsService.RemoteViewsFactory onGetViewFactory(Intent intent) {
return new ListviewRemoteViewsFactory(this.getApplicationContext(), intent);
}
}
class ListViewRemoteViewsFactory implements RemoteViewsService.RemoteViewsFactory {
private Context mContext;
private ArrayList<String> records;

public ListViewRemoteViewsFactory(Context context, Intent intent) {
mContext = context;
}
// Initialize the data set.
public void onCreate() {
// In onCreate() you set up any connections / cursors to your data source. Heavy lifting,
// for example downloading or creating content etc, should be deferred to onDataSetChanged()
// or getViewAt(). Taking more than 20 seconds in this call will result in an ANR.
records=new ArrayList<String>();
}
// Given the position (index) of a WidgetItem in the array, use the item's text value in
// combination with the app widget item XML file to construct a RemoteViews object.
public RemoteViews getViewAt(int position) {
// position will always range from 0 to getCount() - 1.
// Construct a RemoteViews item based on the app widget item XML file, and set the
// text based on the position.
RemoteViews rv = new RemoteViews(mContext.getPackageName(), R.layout.widget_item);
// feed row
String data=records.get(position);
rv.setTextViewText(R.id.item, data);
// end feed row
// Next, set a fill-intent, which will be used to fill in the pending intent template
// that is set on the collection view in ListViewWidgetProvider.
Bundle extras = new Bundle();
extras.putInt(MyWidgetProvider.EXTRA_ITEM, position);
Intent fillInIntent = new Intent();
fillInIntent.putExtra("homescreen_meeting",data);
fillInIntent.putExtras(extras);
// Make it possible to distinguish the individual on-click
// action of a given item
rv.setOnClickFillInIntent(R.id.item_layout, fillInIntent);
// Return the RemoteViews object.
return rv;
}
public int getCount(){
Log.e("size=",records.size()+"");
return records.size();
}
public void onDataSetChanged(){
// Fetching JSON data from server and add them to records arraylist

}
public int getViewTypeCount(){
return 1;
}
public long getItemId(int position) {
return position;
}
public void onDestroy(){
records.clear();
}
public boolean hasStableIds() {
return true;
}
public RemoteViews getLoadingView() {
return null;
}
}

7. In the androidmanifest file, you declare the ListViewWidgetService.
<service android:name=". ListViewWidgetService"
android:permission="android.permission.BIND_REMOTEVIEWS" />

8. Finally in the onMessage() method of GCMBaseIntentService, you broadcast an intent to update the listview when there is a meeting added to you database as below.
protected void onMessage(Context context, Intent data) {

Intent intent_meeting_update=new Intent(context,MyWidgetProvider.class); intent_meeting_update.setAction(MyWidgetProvider.UPDATE_MEETING_ACTION);
sendBroadcast(intent_meeting_update);

}


2015-09-21 Reply





This website intents to provide free and high quality tutorials, examples, exercises and solutions, questions and answers of programming and scripting languages:
C, C++, C#, Java, VB.NET, Python, VBA,PHP & Mysql, SQL, JSP, ASP.NET,HTML, CSS, JQuery, JavaScript and other applications such as MS Excel, MS Access, and MS Word. However, we don't guarantee all things of the web are accurate. If you find any error, please report it then we will take actions to correct it as soon as possible.