07/09/2018, 15:39

ANDROID APP WIDGET WITH LISTVIEW

Thân bài Để làm một widget với một listview bao gồm các thành phần: 1: AppWidgetProvider Được extend từ BroadcastReceiver được dùng đến như một controlled . Bao gồm 3 method +Widget Update :được gọi khi update widget +Widget Delete :được gọi khi xóa một widget +Widget enabled/disabled ...

Thân bài

Để làm một widget với một listview bao gồm các thành phần:

1: AppWidgetProvider

Được extend từ BroadcastReceiver được dùng đến như một controlled .
Bao gồm 3 method
+Widget Update :được gọi khi update widget
+Widget Delete :được gọi khi xóa một widget
+Widget enabled/disabled :được gọi khi tất cả widget bị xóa hay mở
Tiếp theo cần một file config xml
Mỗi một widget cần phải có một file widgetinfo.xml được đặt trong res/xml

widgetinfo.xml
<?xml version="1.0" encoding="utf-8"?>
 
android:configure="com.tienbm.ConfigActivity"

 
android:initialLayout="@layout/widget_layout"

 
android:minHeight="110dip"
android:minWidth="250dip"

 
android:previewImage="@drawable/widget_preview"

 
android:resizeMode="vertical|horizontal"

 
 
android:updatePeriodMillis="1800000"/>

Tiếp theo cần thêm một khai báo trên AndroidManifest.xml

<receiver android:name=".WidgetProvider" >
   <intent-filter>
 
     <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
   </intent-filter>
 
     <meta-data
          android:name="android.appwidget.provider"
           android:resource="@xml/widgetinfo" />
</receiver>

Tao layout cho widget

widget_layout.xml
    <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_awidth="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:background="@android:color/black" >

     
    <ListView
        android:id="@+id/listViewWidget"
        android:layout_awidth="match_parent"
        android:layout_height="match_parent" />

     
    <TextView
        android:id="@+id/empty_view"
        android:layout_awidth="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:text="@string/empty_string"
        android:textColor="#ffffff"
        android:textSize="20sp"
        android:visibility="gone" />

</LinearLayout>

Ngay bây giờ để listview có thể hoạt động thì phải cần data và adapter

2:RemoteViewsService:

Để gọi một adapter bắt buộc phải thông qua một service.Ở đây bạn cũng có thể get data từ một nguồn nào đó rồi truyền vào adapter

public class WidgetService extends RemoteViewsService {
/*
* So pretty simple just defining the Adapter of the listview
* here Adapter is ListProvider
* */

@Override
public RemoteViewsFactory onGetViewFactory(Intent intent) {
      int appWidgetId = intent.getIntExtra(
      AppWidgetManager.EXTRA_APPWIDGET_ID,
      AppWidgetManager.INVALID_APPWIDGET_ID);
       return (new ListProvider(this.getApplicationContext(), intent));
   }

}

Tạo xog service mở file AndroidManifest.xml và thêm khai báo

 <service
   android:name=".WidgetService"
   android:permission="android.permission.BIND_REMOTEVIEWS" /

3:RemoteViewsFactory:

Cũng giống như adapter của listview

/**
* If you are familiar with Adapter of ListView,this is the same as adapter
* with few changes
*
*/
public class ListProvider implements RemoteViewsFactory {
private ArrayList listItemList = new ArrayList();
private Context context = null;
private int appWidgetId;

public ListProvider(Context context, Intent intent) {
this.context = context;
appWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
AppWidgetManager.INVALID_APPWIDGET_ID);

populateListItem();
}

private void populateListItem() {
for (int i = 0; i &lt; 10; i++) {
        ListItem listItem = new ListItem();
        listItem.heading = "Heading" + i;
        listItem.content = i
        + " This is the content of the app widget listview.";
        listItemList.add(listItem);
    }

}

@Override
public int getCount() {
return listItemList.size();
}

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

/*
*Similar to getView of Adapter where instead of View
*we return RemoteViews
*
*/
@Override
public RemoteViews getViewAt(int position) {
    final RemoteViews remoteView = new RemoteViews(
    context.getPackageName(), R.layout.list_row);
    ListItem listItem = listItemList.get(position);
    remoteView.setTextViewText(R.id.heading, listItem.heading);
    remoteView.setTextViewText(R.id.content, listItem.content);
    return remoteView;
 }
}

Cuối cùng là AppWidgetProvider

WidgetProvider.java
public class WidgetProvider extends AppWidgetProvider {

/**
* this method is called every 30 mins as specified on widgetinfo.xml
* this method is also called on every phone reboot
**/

@Override
public void onUpdate(Context context, AppWidgetManager 
                appWidgetManager,int[] appWidgetIds) {

/*int[] appWidgetIds holds ids of multiple instance 
 * of your widget
 * meaning you are placing more than one widgets on 
 * your homescreen*/
 for (int i = 0; i <appWidgetIds.length; ++i) {
     RemoteViews remoteViews = updateWidgetListView(context,
                                           appWidgetIds[i]);
     appWidgetManager.updateAppWidget(appWidgetIds[i], 
                                           remoteViews);
    }
 super.onUpdate(context, appWidgetManager, appWidgetIds);
}

private RemoteViews updateWidgetListView(Context context,
                                     int appWidgetId) {

   //which layout to show on widget
   RemoteViews remoteViews = new RemoteViews(
         context.getPackageName(),R.layout.widget_layout);

  //RemoteViews Service needed to provide adapter for ListView
  Intent svcIntent = new Intent(context, WidgetService.class);
  //passing app widget id to that RemoteViews Service
  svcIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
  //setting a unique Uri to the intent
  //don't know its purpose to me right now
  svcIntent.setData(Uri.parse(
                    svcIntent.toUri(Intent.URI_INTENT_SCHEME)));
  //setting adapter to listview of the widget
  remoteViews.setRemoteAdapter(appWidgetId, R.id.listViewWidget,
                                svcIntent);
  //setting an empty view in case of no data
  remoteViews.setEmptyView(R.id.listViewWidget, R.id.empty_view);
  return remoteViews;
 }

}

Tiếp theo để refesh từ một button widget ta sử dụng một intent được thêm vào updateWidgetListView như sau

 Intent intent = new Intent(context, WidgetProvider .class);
 intent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
 intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds);
 PendingIntent pendingIntent = PendingIntent.getBroadcast(context,0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
 //R.id.actionButton:id của button
 remoteViews.setOnClickPendingIntent(R.id.actionButton, pendingIntent);

Chú ý

Dùng để update cho toàn bộ widget
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds)
Chỉ update widget hiện tại
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, widgetId);

Refesh từ một activity

Intent intent = new Intent(this, WidgetProvider.class);
intent.setAction("android.appwidget.action.APPWIDGET_UPDATE");
int ids[] = AppWidgetManager.getInstance(getApplication()).getAppWidgetIds(new ComponentName(getApplication(), WidgetProvider.class));
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS,ids);
sendBroadcast(intent);

Kết bài

Vậy là đã hoàn thành một widget.

0