Retrieve text from a RemoteViews Object

前端 未结 4 2210
北荒
北荒 2021-02-09 22:25

I need to retrieve some text from a RemoteViews object. It is possible for me to get the LayoutId, but I have no idea how to retrieve text from a TextView

相关标签:
4条回答
  • 2021-02-09 22:55

    I proposed a similar solution here that also uses reflection to solve the problem, but in a more approachable fashion. This is my solution. In this context, the RemoteViews came from a Notification, so the first three lines can probably be ignored if you already have access to the RemoteViews object. The link on the page provides a much more detailed explanation of what is actually going on. I hope this will help anyone with a similar problem.

    public static List<String> getText(Notification notification)
    {
        // We have to extract the information from the view
        RemoteViews        views = notification.bigContentView;
        if (views == null) views = notification.contentView;
        if (views == null) return null;
    
        // Use reflection to examine the m_actions member of the given RemoteViews object.
        // It's not pretty, but it works.
        List<String> text = new ArrayList<String>();
        try
        {
            Field field = views.getClass().getDeclaredField("mActions");
            field.setAccessible(true);
    
            @SuppressWarnings("unchecked")
            ArrayList<Parcelable> actions = (ArrayList<Parcelable>) field.get(views);
    
            // Find the setText() and setTime() reflection actions
            for (Parcelable p : actions)
            {
                Parcel parcel = Parcel.obtain();
                p.writeToParcel(parcel, 0);
                parcel.setDataPosition(0);
    
                // The tag tells which type of action it is (2 is ReflectionAction, from the source)
                int tag = parcel.readInt();
                if (tag != 2) continue;
    
                // View ID
                parcel.readInt();
    
                String methodName = parcel.readString();
                if (methodName == null) continue;
    
                // Save strings
                else if (methodName.equals("setText"))
                {
                    // Parameter type (10 = Character Sequence)
                    parcel.readInt();
    
                    // Store the actual string
                    String t = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel).toString().trim();
                    text.add(t);
                }
    
                // Save times. Comment this section out if the notification time isn't important
                else if (methodName.equals("setTime"))
                {
                    // Parameter type (5 = Long)
                    parcel.readInt();
    
                    String t = new SimpleDateFormat("h:mm a").format(new Date(parcel.readLong()));
                    text.add(t);
                }
    
                parcel.recycle();
            }
        }
    
        // It's not usually good style to do this, but then again, neither is the use of reflection...
        catch (Exception e)
        {
            Log.e("NotificationClassifier", e.toString());
        }
    
        return text;
    }
    
    0 讨论(0)
  • 2021-02-09 23:00

    CommonsWare in this question says:

    ... App widgets are write-only: you can push data to them, but you cannot read them. Instead, when you update your app widget with new text, you will need to store that text somewhere, perhaps in a file.

    His answer seems to be logical.

    0 讨论(0)
  • 2021-02-09 23:06

    If you are targeting on Android 19+, you can use the following code for getting title/text from a Notification object without using any private APIs.

    Notification noty = ...;
    Bundle extras = noty.extras;
    if (extras != null) {
      String title = extras.getString(Notification.EXTRA_TITLE);
      String text = extras.getString(Notification.EXTRA_TEXT);
    }
    
    0 讨论(0)
  • 2021-02-09 23:13

    Taken from Extract notification text from parcelable, contentView or contentIntent :

    Notification notification = (Notification) event.getParcelableData();
    RemoteViews views = notification.contentView;
    Class secretClass = views.getClass();
    
    try {
        Map<Integer, String> text = new HashMap<Integer, String>();
    
        Field outerFields[] = secretClass.getDeclaredFields();
        for (int i = 0; i < outerFields.length; i++) {
            if (!outerFields[i].getName().equals("mActions")) continue;
    
            outerFields[i].setAccessible(true);
    
            ArrayList<Object> actions = (ArrayList<Object>) outerFields[i]
            .get(views);
            for (Object action : actions) {
                Field innerFields[] = action.getClass().getDeclaredFields();
    
                Object value = null;
                Integer type = null;
                Integer viewId = null;
                for (Field field : innerFields) {
                    field.setAccessible(true);
                    if (field.getName().equals("value")) {
                        value = field.get(action);
                    } else if (field.getName().equals("type")) {
                        type = field.getInt(action);
                    } else if (field.getName().equals("viewId")) {
                        viewId = field.getInt(action);
                    }
                }
    
                if (type == 9 || type == 10) {
                    text.put(viewId, value.toString());
                }
            }
    
            System.out.println("title is: " + text.get(16908310));
            System.out.println("info is: " + text.get(16909082));
            System.out.println("text is: " + text.get(16908358));
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
    
    0 讨论(0)
提交回复
热议问题