Давайте рассмотрим некоторые простые примеры методов магии __getattr__
и __getattribute__
.
__getattr__
Python будет вызывать метод __getattr__
всякий раз, когда вы запрашиваете атрибут, еще не определена. В следующем примере мой класс Count не имеет метода __getattr__
. Теперь, когда я пытаюсь получить доступ к атрибутам obj1.mymin
и obj1.mymax
, все работает нормально. Но когда я пытаюсь получить доступ к атрибуту obj1.mycurrent
- Python дает мне AttributeError: 'Count' object has no attribute 'mycurrent'
class Count():
def __init__(self,mymin,mymax):
self.mymin=mymin
self.mymax=mymax
obj1 = Count(1,10)
print(obj1.mymin)
print(obj1.mymax)
print(obj1.mycurrent) --> AttributeError: 'Count' object has no attribute 'mycurrent'
Теперь мой класс Count имеет метод __getattr__
. Теперь, когда я пытаюсь получить доступ к атрибуту obj1.mycurrent
, python возвращает мне все, что я реализовал в моем методе __getattr__
. В моем примере, когда я пытаюсь вызвать атрибут, который не существует, python создает этот атрибут и устанавливает его в целочисленное значение 0.
class Count:
def __init__(self,mymin,mymax):
self.mymin=mymin
self.mymax=mymax
def __getattr__(self, item):
self.__dict__[item]=0
return 0
obj1 = Count(1,10)
print(obj1.mymin)
print(obj1.mymax)
print(obj1.mycurrent1)
__getattribute__
Теперь давайте см. метод __getattribute__
. Если у вас есть метод __getattribute__
в вашем классе, python вызывает этот метод для каждого атрибута независимо от того, существует он или нет. Итак, почему нам нужен метод __getattribute__
? Одна из веских причин заключается в том, что вы можете запретить доступ к атрибутам и сделать их более безопасными, как показано в следующем примере.
Всякий раз, когда кто-то пытается получить доступ к моим атрибутам, которые начинаются с подстановки «cur» python вызывает AttributeError
исключение , В противном случае он возвращает этот атрибут.
class Count:
def __init__(self,mymin,mymax):
self.mymin=mymin
self.mymax=mymax
self.current=None
def __getattribute__(self, item):
if item.startswith('cur'):
raise AttributeError
return object.__getattribute__(self,item)
# or you can use ---return super().__getattribute__(item)
obj1 = Count(1,10)
print(obj1.mymin)
print(obj1.mymax)
print(obj1.current)
Важно: чтобы избежать бесконечной рекурсии в методе __getattribute__
, ее реализация всегда должна вызывать метод базового класса с тем же именем для доступа к любым атрибутам, которые ему нужны. Например: object.__getattribute__(self, name)
или super().__getattribute__(item)
, а не self.__dict__[item]
Если ваш класс содержит как методы getattr, так и getattribute magic, тогда __getattribute__
вызывается первым. Но если __getattribute__
вызывает исключение AttributeError
, исключение будет проигнорировано, и будет вызван метод __getattr__
. См. Следующий пример:
class Count(object):
def __init__(self,mymin,mymax):
self.mymin=mymin
self.mymax=mymax
self.current=None
def __getattr__(self, item):
self.__dict__[item]=0
return 0
def __getattribute__(self, item):
if item.startswith('cur'):
raise AttributeError
return object.__getattribute__(self,item)
# or you can use ---return super().__getattribute__(item)
# note this class subclass object
obj1 = Count(1,10)
print(obj1.mymin)
print(obj1.mymax)
print(obj1.current)
Посмотрите здесь и прокрутите до подзаголовка. Добавление поведения к отдельным элементам.
Вам нужно убедиться, что вы вызываете оба setPendingIntentTemplate()
из вашего AppWidgetProvider
и setOnClickFillInIntent()
из вашей реализации RemoteViewsService.RemoteViewsFactory
.
Например:
public class Widget extends AppWidgetProvider {
// ...
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
for(int i = 0; i < appWidgetIds.length; i++){
RemoteViews widget = new RemoteViews(context.getPackageName(), R.layout.widget);
Intent startActivityIntent = new Intent(context, myActivity.class);
PendingIntent startActivityPendingIntent = PendingIntent.getActivity(context, 0, startActivityIntent, PendingIntent.FLAG_UPDATE_CURRENT);
widget.setPendingIntentTemplate(R.id.list_view, startActivityPendingIntent);
appWidgetManager.updateAppWidget(appWidgetIds[i], widget);
// ...
}
}
public class WidgetAdapter implements RemoteViewsService.RemoteViewsFactory {
// ...
@Override
public RemoteViews getViewAt(int position) {
RemoteViews widgetRow = new RemoteViews(context.getPackageName(), R.layout.widget_row);
Intent fillInIntent = new Intent();
fillInIntent.putExtra(Widget.EXTRA_LIST_VIEW_ROW_NUMBER, position);
widgetRow.setOnClickFillInIntent(R.id.list_view_row, fillInIntent);
// ...
return widgetRow;
}
}
В примере StackWidget есть более убедительный пример, который находится в SDK , хотя мне было трудно найти (см. здесь для направлений). Он создает намерение показывать сообщение Toast, но использует тот же код.
Чтобы запустить любое действие, вы создаете намерение, а затем вызываете startActivity по этому намерению. Проверьте намерение и startActivity, и я уверен, что вы сможете сделать это сами.