我正在为应用程序开发Android Widget,问题是我无法在onClickPendingIntent()的按钮上设置RemoteViewsFactory

我向您解释:我创建了一个AppWidgetProvider,它调用了RemoteViewsService的扩展,并调用了RemoteViewsFactory的扩展以在我的小部件中完成一个ListViewRemoteViewsFactory必须返回所有项目以进行更新或创建它们并显示在小部件上。但是对于列表视图的每个项目,我有2种类型的按钮:

  • 打开gmaps / dialer / sms的按钮(有效)。
  • 一个按钮,它调用我的应用程序中的 Activity 并将其ID作为参数发送给参数。

  • 问题是第二个按钮,我的解决方案不起作用。

    这是问题所在:

    因此,这是无效的代码:
    row.setOnClickPendingIntent(R.id.taskButton, onClickPendingIntent);
    
    // Creating an onclick event for the done button
    Intent doneIntent = new Intent(mContext, WidgetProvider.class);
    doneIntent.putExtra("DONE_TASK", "DOOOOM");
    
    PendingIntent onDoneIntent = PendingIntent.getActivity(mContext, 0, doneIntent, 0);
    row.setOnClickPendingIntent(R.id.doneButton, onDoneIntent);
    

    这是完整的WidgetFactory类:
    import java.util.Collections;
    import java.util.Comparator;
    import java.util.GregorianCalendar;
    import java.util.Vector;
    
    import android.app.PendingIntent;
    import android.content.Context;
    import android.content.Intent;
    import android.graphics.Color;
    import android.net.Uri;
    import android.view.View;
    import android.widget.RemoteViews;
    import android.widget.RemoteViewsService;
    
    public class WidgetFactory implements RemoteViewsService.RemoteViewsFactory {
    
        private Vector<EventInfo> mAllEvents;
        private Context mContext;
    
        public WidgetFactory(Context ctxt, Intent intent) {
            // Creating member vars
            mContext = ctxt;
    
            updateAllEventsVector();
        }
    
    
        private void updateAllEventsVector() {
            SharedInstances sharedInstances = SharedInstances.get();
            mAllEvents = new Vector<EventInfo>();
    
            if (sharedInstances != null) {
                TaskRequestManager taskManager = sharedInstances
                        .getTaskRequestManager();
                CalendarRequestManager calManager = sharedInstances
                        .getCalendarRequestManager();
    
                Vector<TaskEvent> tasks = null;
                Vector<CalendarEvent> events = null;
    
                if (taskManager != null)
                    tasks = taskManager.readTasksToday(mContext);
    
                if (calManager != null)
                    events = calManager.readCalendarEventsToday(mContext);
    
                if (!tasks.isEmpty())
                    mAllEvents.addAll(tasks);
    
    
                if (!events.isEmpty())
                    mAllEvents.addAll(events);
    
                mAllEvents = sortByDate(mAllEvents);
            }
        }
    
        @SuppressWarnings({ "unchecked", "rawtypes" })
        public Vector<EventInfo> sortByDate(Vector<EventInfo> events)
        {
    
            Vector<EventInfo> sortedEvents = new Vector<EventInfo>();
    
            for(EventInfo event : events)
            {
                if ((event.getStartTime()+event.getEventDuration()) > GregorianCalendar.getInstance().getTimeInMillis())
                    sortedEvents.add(event);
            }
    
            Collections.sort(events, new Comparator() {
                public int compare(Object arg0, Object arg1)
                {
                    EventInfo event0 = (EventInfo)arg0;
                    EventInfo event1 = (EventInfo)arg1;
    
                    if (event0.getStartTime()+event0.getEventDuration() > event1.getStartTime()+event1.getEventDuration())
                        return 1;
                    else if (event0.getStartTime()+event0.getEventDuration() == event1.getStartTime()+event1.getEventDuration())
                        return 0;
                    else if (event0.getStartTime()+event0.getEventDuration() < event1.getStartTime()+event1.getEventDuration())
                        return -1;
    
                    return 0;
                }
            });
    
            return sortedEvents;
        }
    
        @Override
        public int getCount() {
            return mAllEvents.size();
        }
    
        @Override
        public long getItemId(int arg0) {
            return (arg0);
        }
    
        @Override
        public RemoteViews getLoadingView() {
            return null;
        }
    
        @Override
        public RemoteViews getViewAt(int position) {
    
            // Getting item view
            RemoteViews row = new RemoteViews(mContext.getPackageName(),
                    R.layout.done_task_item);
    
            EventInfo eventInfo = mAllEvents.get(position);
    
    
    
            row.setInt(R.id.item_event, "setBackgroundColor", Color.argb(60, Color.red(eventInfo.getColor()), Color.green(eventInfo.getColor()), Color.blue(eventInfo.getColor())));
    
            // Converts startTime and endTime in string
            String startTime = TimeCursor.getAdaptativeTime(eventInfo.getStartTime());
            String endTime = TimeCursor.getAdaptativeTime((eventInfo
                    .getEventDuration() + eventInfo.getStartTime()));
    
            //Get title
            String title = eventInfo.getTitle();
    
            // Setting data in the view
            row.setTextViewText(R.id.titleTask, title);
            row.setTextViewText(R.id.periodTask, startTime + " to " + endTime);
    
            //Check type of event
            if (eventInfo.isTask()) {
                //endDate > GregorianCalendar.getInstance().getTimeInMillis() ) {
    
                //Check if action exists
                if (eventInfo.getAction() != null) {
    
                    //Get the action title
                    String action = eventInfo.getAction()
                            .getTitleText();
    
                    //Create a onClickPendingIntent for taskButton
                    PendingIntent onClickPendingIntent = null;
    
                    //Add related button
                    if (action.equals("Call"))
                    {
                        //Set call icon to taskButton
                        row.setImageViewResource(R.id.taskButton, R.drawable.ic_call_white );
    
                        //Get numbers from the contact
                        Vector<TelOrEmailItem> tel = eventInfo.getContact().getAllPhoneNumbers(mContext.getResources() , mContext, eventInfo.getAction());
    
                        // Creating an onclick event for call somebody
                        Intent callIntent = new Intent(Intent.ACTION_CALL, Uri.parse("tel:"+tel.get(0).getMainText()));
                        onClickPendingIntent = PendingIntent.getActivity(
                                mContext, 0, callIntent, 0);
    
                    }
                    else if (action.equals("SMS"))
                    {
                        //Set sms icon to taskButton
                        row.setImageViewResource(R.id.taskButton, R.drawable.ic_sms_white);
                        //Get numbers from the contact
                        Vector<TelOrEmailItem> tel = eventInfo.getContact().getAllPhoneNumbers(mContext.getResources() , mContext, eventInfo.getAction());
    
                        // Creating an onclick event for call somebody
                        Intent smsIntent = new Intent(Intent.ACTION_SENDTO, Uri.parse("smsto:"+tel.get(0).getMainText()));
                        onClickPendingIntent = PendingIntent.getActivity(
                                mContext, 0, smsIntent, 0);
                    }
                    /*else if (action.equals("Chat with"))
                        row.setImageViewResource(R.id.taskButton, R.drawable.ic_chat_white);*/
                    else if (action.equals("eMail") || action.equals("Mail") || action.equals("Write to"))
                    {
                        //Set email icon to taskButton
                        row.setImageViewResource(R.id.taskButton, R.drawable.ic_email_white);
    
                        //Get numbers from the contact
                        Vector<TelOrEmailItem> tel = eventInfo.getContact().getAllEMails(mContext, eventInfo.getAction());
    
                        //Creating an onclick event for email somebody
                        Intent emailIntent = new Intent(Intent.ACTION_SEND);
                        emailIntent.setType("plain/text");
    
                        emailIntent.putExtra(Intent.EXTRA_EMAIL,
                                        new String[]{tel.get(0).getMainText()});
    
                        onClickPendingIntent = PendingIntent.getActivity(
                                mContext, 0, emailIntent, 0);
                    }
                    /*else if (action.equals("Skype"))
                        row.setImageViewResource(R.id.taskButton, R.drawable.ic_skype_white);*/
    
                    //Assign the intent to the taskButton
                    row.setOnClickPendingIntent(R.id.taskButton, onClickPendingIntent);
    
                    // Creating an onclick event for the done button
                    Intent doneIntent = new Intent(mContext, WidgetProvider.class);
    
                    doneIntent.putExtra("DONE_TASK", "DOOOOM");
    
                    PendingIntent onDoneIntent = PendingIntent.getActivity(mContext, 0, doneIntent, 0);
    
                    row.setOnClickPendingIntent(R.id.doneButton, onDoneIntent);
    
                }
                else
                    row.setViewVisibility(R.id.taskButton, View.GONE); //hidde the taskButton
    
                return row;
    
            }
            //Check if it's an event
            else if(eventInfo.isEvent()) {
    
                //hidde task button (Done)
                row.setViewVisibility(R.id.doneButton, View.GONE);
    
                CalendarEvent ev = eventInfo.getCalendarEvent();
                String location = ev.getEventLocation();
                if (location != null && !location.isEmpty())
                {
                    //Set the locate icon on the taskButton
                    row.setImageViewResource(R.id.taskButton, R.drawable.ic_locate_white);
    
                    //Define the place to open the map
                    Intent mapIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("geo:0,0?q="+location));
                    PendingIntent onMapIntent = PendingIntent.getActivity(
                            mContext, 0, mapIntent, 0);
                    row.setOnClickPendingIntent(R.id.taskButton, onMapIntent);
                }
                else
                    row.setViewVisibility(R.id.taskButton, View.GONE);
    
                return row;
            }
    
    
            return null;
        }
    
        @Override
        public int getViewTypeCount() {
            return 1;
        }
    
        @Override
        public boolean hasStableIds() {
            return (true);
        }
    
        @Override
        public void onCreate() {
        }
    
        @Override
        public void onDataSetChanged() {
            // On data changes, update mTasks
            updateAllEventsVector();
        }
    
        @Override
        public void onDestroy() {
            mAllEvents = null;
        }
    
    }
    

    谢谢你:)

    编辑:
    耶!
    问题是否解决...

    方法onClickPendingIntent()现在可以使用,下面是代码:
    // Creating an onclick event for the done button
    Intent onClickDone = new Intent(mContext, DoneTaskActivity.class);
    onClickDone.putExtra("TASK_ID", eventInfo.getTaskEvent().getTaskId());
    PendingIntent onClickPendingDone = PendingIntent.getActivity(mContext, 0, onClickDone, 0);
    row.setOnClickPendingIntent(R.id.doneButton, onClickPendingDone);
    

    但是存在另一个问题:DoneTaskActivity没有收到额外的声明为TASK_ID的消息。在onCreate()DoneTaskActivity方法中,参数Bundle var保留为null

    救命 :(

    最佳答案

    在小部件中使用列表视图时,您需要使用setOnClickFillInIntent侦听器。来自官方文档;

    在小部件中使用集合(例如ListView,StackView等)时,它会
    在各个项目上设置PendingIntents的成本很高,并且
    因此不允许。相反,可以将一个PendingIntent模板
    集合上

    在RemoteViewsFactory内部,您可以像这样使用它;

    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);
        rv.setTextViewText(R.id.widget_item, mWidgetItems.get(position).text);
    
        // Next, set a fill-intent, which will be used to fill in the pending intent template
        // that is set on the collection view in StackWidgetProvider.
        Bundle extras = new Bundle();
        extras.putInt(StackWidgetProvider.EXTRA_ITEM, position);
        Intent fillInIntent = new Intent();
        fillInIntent.putExtras(extras);
        // Make it possible to distinguish the individual on-click
        // action of a given item
        rv.setOnClickFillInIntent(R.id.widget_item, fillInIntent);
    
        ...
    
        // Return the RemoteViews object.
        return rv;
    }
    

    您还需要使用标准的PendingIntent,因为单个列表项无法设置PendingIntent,请参阅AppWidgets上的文档。

    07-28 12:28