问题描述
我在App Widget中使用ListView来显示RSS源中的某些项目.如果我单击ListView中的某个项目,我想进入我的应用程序的活动.
I am using a ListView in a App Widget to show some items from a RSS feed. I want to go to a activity of my app if I click on a item in the ListView.
我现在可以按一下位置显示吐司了.我想去.但是我不知道如何开始活动.
I am at the point that I can show a Toast with the clicked position. I want to go to. But I do not know how to start the activity.
我需要将RSSFeed和位置放置在启动活动的意图内.
I need to put my RSSFeed and the position inside the intent which starts the activity.
我有一个WidgetProvider.java,它在onUpdate()方法中调用RemoteFetchService.java.在此服务的OnStartCommand()中,我启动一个AsyncTask并解析我的RSS feed.在OnPostExecute()中,我向WidgetProvider.java广播了成功获取数据的信息.然后,在WidgetProvider.java中,我通过ListProvider.java类设置了一个远程适配器,该适配器可实现RemoteViewsFactory.那我在哪里以及如何开始活动?
I have a WidgetProvider.java which calls a RemoteFetchService.java in the onUpdate() method. In the OnStartCommand() of this Service I start a AsyncTask and parse my RSS feed. In the OnPostExecute() I broadcast to the WidgetProvider.java that I successfully fetched the data. Then in the WidgetProvider.java I set a remote adapter via my ListProvider.java class that implents RemoteViewsFactory. So where and how can I start my activity?
WidgetProvider.java
public class WidgetProvider extends AppWidgetProvider {
// String to be sent on Broadcast as soon as Data is Fetched
// should be included on WidgetProvider manifest intent action
// to be recognized by this WidgetProvider to receive broadcast
public static final String DATA_FETCHED = "mypackage.RSS.DATA_FETCHED";
public static final String EXTRA_LIST_VIEW_ROW_NUMBER = "mypackage.EXTRA_LIST_VIEW_ROW_NUMBER";
/*
* this method is called every 30 mins as specified on widgetinfo.xml this
* method is also called on every phone reboot from this method nothing is
* updated right now but instead RetmoteFetchService class is called this
* service will fetch data,and send broadcast to WidgetProvider this
* broadcast will be received by WidgetProvider onReceive which in turn
* updates the widget
*/
@Override
public void onUpdate(Context ctxt, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
Log.d("Widget", "Hello WidgetProvider onUpdate");
/*
* 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) {
Intent serviceIntent = new Intent(ctxt, RemoteFetchService.class);
serviceIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
appWidgetIds[i]);
ctxt.startService(serviceIntent);
}
super.onUpdate(ctxt, appWidgetManager, appWidgetIds);
}
/*
* It receives the broadcast as per the action set on intent filters on
* Manifest.xml once data is fetched from RemoteFetchService,it sends
* broadcast and WidgetProvider notifies to change the data the data change
* right now happens on ListProvider as it takes RemoteFetchService
* listItemList as data
*/
@SuppressWarnings("deprecation")
@Override
public void onReceive(Context context, Intent intent) {
super.onReceive(context, intent);
Log.d("Widget", "Hello WidgetProvider onReceive");
//if RSS Feed was parsed in RemoteFetchService.java
if (intent.getAction().equals(DATA_FETCHED)) {
Log.d("Widget", "Data fetched in Widget Provider");
int appWidgetId = intent.getIntExtra(
AppWidgetManager.EXTRA_APPWIDGET_ID,
AppWidgetManager.INVALID_APPWIDGET_ID);
AppWidgetManager appWidgetManager = AppWidgetManager
.getInstance(context);
// 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
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);
// onclick item listview
// This section makes it possible for items to have individualized
// behavior.
// It does this by setting up a pending intent template. Individuals
// items of a collection
// cannot set up their own pending intents. Instead, the collection
// as a whole sets
// up a pending intent template, and the individual items set a
// fillInIntent
// to create unique behavior on an item-by-item basis.
Intent toastIntent = new Intent(context, WidgetProvider.class);
// Set the action for the intent.
// When the user touches a particular view, it will have the effect
// of
// broadcasting TOAST_ACTION.
toastIntent.setAction(WidgetProvider.EXTRA_LIST_VIEW_ROW_NUMBER);
toastIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
appWidgetId);
intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME)));
PendingIntent toastPendingIntent = PendingIntent.getBroadcast(
context, 0, toastIntent, PendingIntent.FLAG_UPDATE_CURRENT);
remoteViews.setPendingIntentTemplate(R.id.listViewWidget,
toastPendingIntent);
appWidgetManager.updateAppWidget(appWidgetId, remoteViews);
}
//if item on list was clicked
if (intent.getAction().equals(EXTRA_LIST_VIEW_ROW_NUMBER)) {
int appWidgetId = intent.getIntExtra(
AppWidgetManager.EXTRA_APPWIDGET_ID,
AppWidgetManager.INVALID_APPWIDGET_ID);
AppWidgetManager appWidgetManager = AppWidgetManager
.getInstance(context);
//get position on listview which was clicked
int viewIndex = intent.getIntExtra(EXTRA_LIST_VIEW_ROW_NUMBER, 0);
//get RSSFeed
RSSFeed feed = ListItem.Feed;
Toast.makeText(context, "Clicked on position :" + viewIndex,
Toast.LENGTH_SHORT).show();
} else {
Log.d("Widget", "No Data fetched in Widget Provider");
}
}
}
RemoteFetchService.java
public class RemoteFetchService extends Service {
private int appWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID;
RSSFeed feed;
public Date pDate;
public static ArrayList<ListItem> listItemList;
@Override
public IBinder onBind(Intent arg0) {
return null;
}
/*
* Retrieve appwidget id from intent it is needed to update widget later
* start Async Task
*/
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d("Widget", "Hello RemoteFetchService onStartCommand");
if (intent.hasExtra(AppWidgetManager.EXTRA_APPWIDGET_ID))
appWidgetId = intent.getIntExtra(
AppWidgetManager.EXTRA_APPWIDGET_ID,
AppWidgetManager.INVALID_APPWIDGET_ID);
//fetchDataFromWeb();
new AsyncLoadXMLFeed().execute();
return super.onStartCommand(intent, flags, startId);
}
/**
* AsyncTask which parses the xml and post it
**/
public class AsyncLoadXMLFeed extends AsyncTask<Void, Void, RSSFeed> {
protected RSSFeed doInBackground(Void... params) {
try {
Log.d("Widget", "Starte Parsing von URL in Widget");
// Obtain feed
DOMParser myParser = new DOMParser();
feed = myParser.parseXml("http://www.test.de/feed");
Log.d("Widget","ItemCount Parser in Widget: "+feed.getItemCount());
return feed;
} catch (Exception e) {
Log.d("Widget","Exception beim Parsen: "+e.toString());
return null;
}
}
@Override
protected void onPostExecute(RSSFeed parsed_feed) {
// super.onPostExecute(result);
Log.d("Widget", "Async Parse fertig");
listItemList = new ArrayList<ListItem>();
if(feed!=null){
try {
int length = feed.getItemCount();
for (int i = 0; i < length; i++) {
String date = calc_date_difference(feed, i);
ListItem listItem = new ListItem();
listItem.Feed = feed;
listItem.heading = feed.getItem(i).getTitle();
listItem.pubDate = date;
listItem.linkUrl = feed.getItem(i).getLink();
Log.d("Widget Heading", feed.getItem(i).getTitle());
Log.d("Widget PubDate", date);
Log.d("Widget linkUrl", feed.getItem(i).getLink());
listItemList.add(listItem);
}
} catch (Exception e) {
Log.d("Widget","Exception onPostExecute: "+e.toString());
}
}else{
Log.d("Widget", "Feed in onPostExecute ist null");
}
//start intent and broadcast WidgetProvider, that data is fetched
Intent widgetUpdateIntent = new Intent();
widgetUpdateIntent.setAction(WidgetProvider.DATA_FETCHED);
widgetUpdateIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
appWidgetId);
sendBroadcast(widgetUpdateIntent);
//stop service
stopSelf();
}
}
/**
* Method to calculate the time difference
**/
public String calc_date_difference (RSSFeed feed, int pos){
// calculate the time difference to the actual system time
String pubDate = feed.getItem(pos).getDate();
SimpleDateFormat df = new SimpleDateFormat(
"EEE, dd MMM yyyy HH:mm:ss",Locale.ENGLISH);
try {
try {
pDate = df.parse(pubDate);
} catch (java.text.ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
pubDate = "Vor "
+ DateUtils.getDateDifference(pDate);
return pubDate;
} catch (ParseException e) {
Log.e("DATE PARSING", "Error parsing date..");
return null;
}
}
}
WidgetService.java
/**
*
* Just consider this class as the class which tells the ListView of appwidget
* to take what type of data. By data meaning what ListViewsFactory. To make it
* more simple,if you have done ListView population,this class defines the
* Adapter for the ListView. Let us name ListViewsService as WidgetService.java
*
**/
public class WidgetService extends RemoteViewsService {
/*
* So pretty simple just defining the Adapter of the listview here Adapter
* is ListViewsFactory
*/
@Override
public RemoteViewsFactory onGetViewFactory(Intent intent) {
int appWidgetId = intent.getIntExtra(
AppWidgetManager.EXTRA_APPWIDGET_ID,
AppWidgetManager.INVALID_APPWIDGET_ID);
return (new ListProvider(this.getApplicationContext(), intent));
}
}
ListItem.java
public class ListItem {
public String heading,pubDate,linkUrl;
public static RSSFeed Feed;
}
ListProvider.java
/**
* If you are familiar with Adapter of ListView,this is the same as adapter with
* few changes
*
*/
public class ListProvider implements RemoteViewsFactory {
private RemoteViews views;
private Context ctxt = null;
private int appWidgetId;
private ArrayList<ListItem> listItemList = new ArrayList<ListItem>();
public ListProvider(Context ctxt, Intent intent) {
this.ctxt = ctxt;
appWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
AppWidgetManager.INVALID_APPWIDGET_ID);
if (RemoteFetchService.listItemList != null)
listItemList = (ArrayList<ListItem>) RemoteFetchService.listItemList
.clone();
else
listItemList = new ArrayList<ListItem>();
}
@Override
public void onCreate() {
// no-op
Log.d("Widget", "Hello ListProvider onCreate");
}
@Override
public void onDestroy() {
// no-op
}
@Override
public int getCount() {
return listItemList.size();
}
/*
* Similar to getView of Adapter where instead of Viewwe return RemoteViews
*/
@Override
public RemoteViews getViewAt(int position) {
final RemoteViews remoteView = new RemoteViews(ctxt.getPackageName(),
R.layout.row);
ListItem listItem = listItemList.get(position);
remoteView.setTextViewText(R.id.heading, listItem.heading);
remoteView.setTextViewText(R.id.pubDate, listItem.pubDate);
//onclick item listview
Intent fillInIntent = new Intent();
fillInIntent.putExtra(WidgetProvider.EXTRA_LIST_VIEW_ROW_NUMBER, position);
remoteView.setOnClickFillInIntent(R.id.heading, fillInIntent);
return remoteView;
}
@Override
public RemoteViews getLoadingView() {
return (null);
}
@Override
public int getViewTypeCount() {
return (1);
}
@Override
public long getItemId(int position) {
return (position);
}
@Override
public boolean hasStableIds() {
return (true);
}
@Override
public void onDataSetChanged() {
// no-op
}
}
推荐答案
如果您可以正确获取Feed和位置
If you can get the feed and position properly for
Toast.makeText(context, "Clicked on position :" + viewIndex, Toast.LENGTH_SHORT).show();
您应该能够添加一行
context.startActivity(INTENT HERE);
您可能想以字符串形式传递RSS Feed,或者实现Parcelable.
You may want to pass your RSS Feed as a String, or perhaps implement Parcelable.
这篇关于Android:使用ListView和Service从应用程序小部件开始活动的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!