Android:使用ListView和Service从应用程序小部件开始活动 [英] Android: Start activity from app widget with ListView and Service

查看:66
本文介绍了Android:使用ListView和Service从应用程序小部件开始活动的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在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从应用程序小部件开始活动的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆