我将小部件与具有 3 种类型的项目的 ListView 一起使用。对于每种类型的项目,我应该使用不同的待定 Intent 。目前我正在使用以下代码:
public class MyWidgetProvider extends AppWidgetProvider {
@Override
public void onUpdate(Context context, AppWidgetManager widgetManager, int[] widgetIds) {
for (int widgetId : widgetIds) {
RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget_view);
bindEmptyView(remoteViews);
bindRemoteAdapter(context, widgetId, remoteViews);
bindIntentTemplate(context, widgetId, remoteViews);
widgetManager.updateAppWidget(widgetId, remoteViews);
}
}
private void bindEmptyView(RemoteViews remoteViews) {
remoteViews.setEmptyView(android.R.id.list, android.R.id.empty);
}
private void bindRemoteAdapter(Context context, int widgetId, RemoteViews remoteViews) {
Intent intent = new Intent(context, MyViewService.class);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, widgetId);
intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME)));
remoteViews.setRemoteAdapter(android.R.id.list, intent);
}
private void bindIntentTemplate(Context context, int widgetId, RemoteViews remoteViews) {
Intent intent = new Intent(context, MyActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, widgetId);
intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME)));
PendingIntent template = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
remoteViews.setPendingIntentTemplate(android.R.id.list, template);
}
}
从这一点来看,我不明白如何为不同的列表项调用特定的 Intent 。
最佳答案
希望我能很好地理解您的问题,所以我会尝试详细解释发生了什么以及如何处理对小部件上列表项的点击。
我假设您已经知道您必须实现一个类:
extends BroadcastReceiver implements RemoteViewsService.RemoteViewsFactory
这将作为您的小部件的 ListView(我们称它为 MyListRemoteViewFactory)的“适配器”。 如果您想处理小部件的 listView 上的项目点击,您可以执行以下操作:
1) 在你的 AppWidgetProvider 类中设置一个 setPendingIntentTemplate
2) 在 MyListRemoteViewFactory 中设置一个 setOnClickFillInIntent 覆盖 getViewAt(int position) 方法
现在: 执行第 1 步)时,您可能想执行以下操作:
final Intent serviceIntent = new Intent(context, MyListRemoteViewFactory.class);
serviceIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, widgetId);
serviceIntent.setData(Uri.parse(serviceIntent.toUri(Intent.URI_INTENT_SCHEME)));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
views.setRemoteAdapter(R.id.widget_list_view, serviceIntent);
} else {
views.setRemoteAdapter(widgetId, R.id.widget_list_view, serviceIntent);
}
// 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 listItemClickIntent = new Intent(context, MyWidgetProvider.class); // This is the name of your AppWidgetProvider class
// Set the action for the intent. When the user touches a particular view, it will have the effect of broadcasting an action
listItemClickIntent.setAction(context.getString("com.example.list.item.click"));
listItemClickIntent.setData(Uri.parse(listItemClickIntent.toUri(Intent.URI_INTENT_SCHEME)));
PendingIntent clickPendingIntent = PendingIntent.getBroadcast(context, 0, listItemClickIntent, PendingIntent.FLAG_UPDATE_CURRENT);
views.setPendingIntentTemplate(R.id.widget_list_view, clickPendingIntent);
您可以将上述代码 fragment 放在初始化 RemoteViews 对象的任何位置之后:
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.layout_widget);)
现在您已经准备好 pendingIntentTemplate。另一件要做的事情是实现类的 onReceive 方法,这样您就可以决定在发生上述情况的操作时要做什么。所以你会做类似的事情:
@Override
public void onReceive(Context context, Intent intent) {
// Called on every broadcast and before each of the above callback methods.
super.onReceive(context, intent);
ComponentName name = new ComponentName(context, WidgetProvider.class);
int[] appWidgetIds = AppWidgetManager.getInstance(context).getAppWidgetIds(name);
if (appWidgetIds == null || appWidgetIds.length == 0) {
return;
}
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
if (intent.getAction().equals("com.example.list.item.click") {
// This is where you have to decide what you'll do depending on which list item was tapped. BUT this depends on the fill Intent set in the MyListRemoteViewFactory class's getViewAt() method
// I'll jump straight to the logic here, but once you're done reading this post, get back here to understand the logic because this is the key here. But simple as hell.
int simpleDecidingFactor = intent.getIntExtra("SELECTED_ITEM", 0)
if (simpleDecidingFactor != 0) {
if (simpleDecidingFactor == 1) {
// Do something for the first case. Probably open activity2
} else if (simpleDecidingFactor == 2) {
// Do something for the second case. Probably open activity2
} else if (simpleDecidingFactor == 3) {
// Do something for the second case. Probably open activity3
}
}
}
}
[该死的,这会很长]
执行第 2 步)(从现在开始我们讨论 MyListRemoteViewFactory 类中的实现)
如果您需要列表中的 3 个不同的项目,首先您必须将此方法添加到 MyListRemoteViewFactory(无论如何您都必须重写它,关键是返回您拥有的 View 数):
@Override
public int getViewTypeCount() {
return 3;
}
在 getViewAt() 方法中,您可以添加基于什么的逻辑,您可以根据您的位置决定显示什么。像这样的东西:
@Override
public RemoteViews getViewAt(int position) {
if (position >= mItems.size()) {
return null;
}
RemoteViews views;
if (mItems.get(position).getViewType() == 0) {
views = new RemoteViews(mContext.getPackageName(), R.layout.list_item_first);
setUpItem(views, mItems.get(position), 1); // !!!! the 3rd parameter is very important here, as you'll expect this number in the MyWidgetProvider class' onReceive method. See the simpleDecidingFactor variable there.
} else if (mItems.get(position).getViewType() == 1) {
views = new RemoteViews(mContext.getPackageName(), R.layout.list_item_second);
setUpItem(views, mItems.get(position), 2);
} else {
views = new RemoteViews(mContext.getPackageName(), R.layout.list_item_third);
setUpItem(views, mItems.get(position), 3);
} // Or add whatever logic you have. Here, I supposed I have a field inside my object telling me what type my item is
return views;
}
setUpItem 方法可能类似于:
private void setUpItem(RemoteViews views, MyObject object, int viewTypeKey) {
// This is where you set your clickFillInIntent. Without setting it, nothing'll be functional
Bundle extras = new Bundle();
extras.putInt("SELECTED_ITEM", viewTypeKey);
//extras.putParcelable("LIST_ITEM_OBJECT", object); // You may send your object as well if you need it
Intent fillInIntent = new Intent();
fillInIntent.putExtras(extras);
// You have your fillInIntent prepared, you only have to decide on what view to place it.
// I assume you have a Button on all 3 of your list item layouts with the id button_click. Let's place the Intent:
views.setOnClickFillInIntent(R.id.button_click, fillInIntent);
}
您可能想确保您也在 list 文件中声明了所有内容。您必须声明您的 widgetprovider、列表的接收者以及处理您的 Factoryclass 的服务。你应该有这样的东西:
<receiver
android:name=".MyWidgetProvider"
android:enabled="true"
android:label="My awesome widget">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_ENABLED" />
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="android.appwidget.action.APPWIDGET_DELETED" />
<action android:name="android.appwidget.action.APPWIDGET_DISABLED" />
<!-- You have to declare your used actions here, so the AppWidgetProvider knows what to listen for-->
<action android:name="com.example.list.item.click"/>
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/widget_provider_info"/>
</receiver>
<!-- The service serving the RemoteViews to the collection widget -->
<service
android:name=".WidgetRemoteViewsService"
android:exported="false"
android:permission="android.permission.BIND_REMOTEVIEWS"/>
<receiver
android:name=".ui.widget.MyListRemoteViewFactory"
android:enabled="true"
android:exported="false">
<intent-filter>
<category android:name="android.intent.category.DEFAULT"/>
<!-- You might want to use an action to notify the appwidget provider from the MyListRemoteViewFactory's onReceive method. This class extends a BroadcastReceiver, so you must implement it's onReceive(Context context, Intent intent) method. If you need help on this, let me know and I'll edit my answer with some example for that too -->
<action android:name="com.example.refresh.remote.views"/>
</intent-filter>
</receiver>
啊,顺便说一句,WidgetRemoteViewsService 类应该如下所示:
public class WidgetNewsRemoteViewsService extends RemoteViewsService {
@Override
public RemoteViewsFactory onGetViewFactory(Intent intent) {
return new MyListRemoteViewFactory();
}
}
我想大概就是这样了。我希望我没有跳过任何东西。
关于android - 具有多个待定 Intent 的 ListView 小部件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25441250/
Rails2.3可以选择随时使用RouteSet#add_configuration_file添加更多路由。是否可以在Rails3项目中做同样的事情? 最佳答案 在config/application.rb中:config.paths.config.routes在Rails3.2(也可能是Rails3.1)中,使用:config.paths["config/routes"] 关于ruby-on-rails-Rails3中的多个路由文件,我们在StackOverflow上找到一个类似的问题
我想安装一个带有一些身份验证的私有(private)Rubygem服务器。我希望能够使用公共(public)Ubuntu服务器托管内部gem。我读到了http://docs.rubygems.org/read/chapter/18.但是那个没有身份验证-如我所见。然后我读到了https://github.com/cwninja/geminabox.但是当我使用基本身份验证(他们在他们的Wiki中有)时,它会提示从我的服务器获取源。所以。如何制作带有身份验证的私有(private)Rubygem服务器?这是不可能的吗?谢谢。编辑:Geminabox问题。我尝试“捆绑”以安装新的gem..
我有多个ActiveRecord子类Item的实例数组,我需要根据最早的事件循环打印。在这种情况下,我需要打印付款和维护日期,如下所示:ItemAmaintenancerequiredin5daysItemBpaymentrequiredin6daysItemApaymentrequiredin7daysItemBmaintenancerequiredin8days我目前有两个查询,用于查找maintenance和payment项目(非排他性查询),并输出如下内容:paymentrequiredin...maintenancerequiredin...有什么方法可以改善上述(丑陋的)代
我需要从一个View访问多个模型。以前,我的links_controller仅用于提供以不同方式排序的链接资源。现在我想包括一个部分(我假设)显示按分数排序的顶级用户(@users=User.all.sort_by(&:score))我知道我可以将此代码插入每个链接操作并从View访问它,但这似乎不是“ruby方式”,我将需要在不久的将来访问更多模型。这可能会变得很脏,是否有针对这种情况的任何技术?注意事项:我认为我的应用程序正朝着单一格式和动态页面内容的方向发展,本质上是一个典型的网络应用程序。我知道before_filter但考虑到我希望应用程序进入的方向,这似乎很麻烦。最终从任何
我有一个具有一些属性的模型:attr1、attr2和attr3。我需要在不执行回调和验证的情况下更新此属性。我找到了update_column方法,但我想同时更新三个属性。我需要这样的东西:update_columns({attr1:val1,attr2:val2,attr3:val3})代替update_column(attr1,val1)update_column(attr2,val2)update_column(attr3,val3) 最佳答案 您可以使用update_columns(attr1:val1,attr2:val2
我正在尝试修改当前依赖于定义为activeresource的gem:s.add_dependency"activeresource","~>3.0"为了让gem与Rails4一起工作,我需要扩展依赖关系以与activeresource的版本3或4一起工作。我不想简单地添加以下内容,因为它可能会在以后引起问题:s.add_dependency"activeresource",">=3.0"有没有办法指定可接受版本的列表?~>3.0还是~>4.0? 最佳答案 根据thedocumentation,如果你想要3到4之间的所有版本,你可以这
我正在尝试按0-9和a-z的顺序创建数字和字母列表。我有一组值value_array=['0','1','2','3','4','5','6','7','8','9','a','b','光盘','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','','u','v','w','x','y','z']和一个组合列表的数组,按顺序,这些数字可以产生x个字符,比方说三个list_array=[]和一个当前字母和数字组合的数组(在将它插入列表数组之前我会把它变成一个字符串,]current_combo['0','0','0']
是否有可能:before_filter:authenticate_user!||:authenticate_admin! 最佳答案 before_filter:do_authenticationdefdo_authenticationauthenticate_user!||authenticate_admin!end 关于ruby-on-rails-before_filter运行多个方法,我们在StackOverflow上找到一个类似的问题: https://
我正在使用Rails3.1并在一个论坛上工作。我有一个名为Topic的模型,每个模型都有许多Post。当用户创建新主题时,他们也应该创建第一个Post。但是,我不确定如何以相同的形式执行此操作。这是我的代码:classTopic:destroyaccepts_nested_attributes_for:postsvalidates_presence_of:titleendclassPost...但这似乎不起作用。有什么想法吗?谢谢! 最佳答案 @Pablo的回答似乎有你需要的一切。但更具体地说...首先改变你View中的这一行对此#
我收到格式为的回复#我需要将其转换为哈希值(针对活跃商家)。目前我正在遍历变量并执行此操作:response.instance_variables.eachdo|r|my_hash.merge!(r.to_s.delete("@").intern=>response.instance_eval(r.to_s.delete("@")))end这有效,它将生成{:first="charlie",:last=>"kelly"},但它似乎有点hacky和不稳定。有更好的方法吗?编辑:我刚刚意识到我可以使用instance_variable_get作为该等式的第二部分,但这仍然是主要问题。