我已经使用Xamarin为Android创建了一个命令提示符小部件,并且我正在试图弄清楚如何设置我的ListViewFactory类和RemoteViewsService类,以便每个小部件都有单独的数据。
根据我的理解,RemoteViewsService类返回要显示给用户的ListViewFactory对象。问题是我的列表有用户输入,我不知道如何获取对从RemoteViewsService返回的ListViewFactory对象的引用。
WidgetProvider:
namespace CommAndroid
{
[BroadcastReceiver(Label = "CommAndroid", Exported = false, Enabled = true, Name = "com.company.CommAndroid.WidgetProvider",Icon ="@mipmap/terminalappicon")]
[IntentFilter(new string[] { "android.appwidget.action.APPWIDGET_UPDATE" })]
[MetaData("android.appwidget.provider", Resource = "@xml/my_widget")]
//Class to inflate and show the widget
public class WidgetProvider : AppWidgetProvider
{
//Initialize Global Vars for Class
public static ListViewFactory listViewFactory;
private Handler handler;
//Update method for a widget
public override void OnUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds)
{
base.OnUpdate(context, appWidgetManager, appWidgetIds);
foreach (int appwidgetId in appWidgetIds)
{
// Build the remote views for the widget
var widgetView = BuildRemoteViews(context);
// Update all instances of the widget with the new remote views
appWidgetManager.NotifyAppWidgetViewDataChanged(appwidgetId, Resource.Id.listView1);
appWidgetManager.UpdateAppWidget(appwidgetId, widgetView);
}
}
//Build the widget view, returns to the update method
public RemoteViews BuildRemoteViews(Context context)
{
//Initialize our widget view, basically pointing to our main widget layout xml
var widgetView = new RemoteViews(context.PackageName, Resource.Layout.widget_layout);
//Initializing an intent of our WidgetRemoteViewService, to handle the creation of our list view factory
//Instructing Widget to use our WidgetRemoteViewService with our ListView
Intent listViewIntent = new Intent(context, typeof(WidgetRemoteViewService));
widgetView.SetRemoteAdapter(Resource.Id.listView1, listViewIntent);
//Initializing an intent for the main widget button click
var clickIntent = new Intent(context, typeof(WidgetProvider));
clickIntent.SetAction("com.company.CommAndroid.WIDGET_BUTTON_CLICK");
// Initializing a new Intent for the delete button click action
var deleteIntent = new Intent(context, typeof(WidgetProvider));
deleteIntent.SetAction("com.company.CommAndroid.DELETE_BUTTON_CLICK");
// Initializing pending intents for the button click actions
var pendingIntent = PendingIntent.GetBroadcast(context, 5555533, clickIntent, PendingIntentFlags.Mutable);
var pendingDeleteIntent = PendingIntent.GetBroadcast(context, 55522111, deleteIntent, PendingIntentFlags.Mutable);
// Associating the pending intents with the respective buttons in the widget layout
widgetView.SetOnClickPendingIntent(Resource.Id.delete_button, pendingDeleteIntent);
widgetView.SetOnClickPendingIntent(Resource.Id.widget_button, pendingIntent);
Intent itemClickIntent = new Intent(context, typeof(WidgetProvider));
itemClickIntent.SetAction("com.company.CommAndroid.LIST_ITEM_CLICK");
PendingIntent itemClickPendingIntent = PendingIntent.GetBroadcast(context, 3434514, itemClickIntent, PendingIntentFlags.Mutable);
widgetView.SetPendingIntentTemplate(Resource.Id.listView1, itemClickPendingIntent);
// ...
return widgetView;
}
//On Deleted
public override void OnDeleted(Context context, int[] appWidgetIds)
{
base.OnDeleted(context, appWidgetIds);
}
//Method to update the listview in widget
private async void updateListView(Context context, RemoteViews views, bool isDelete, string command)
{
//Create a new list factory and view for our widget
//Create an AppWidgetManager, reference component name, and get appWidgetIds
listViewFactory = new ListViewFactory(context);
var widgetView = views;
AppWidgetManager appWidgetManager = AppWidgetManager.GetInstance(context);
ComponentName componentName = new ComponentName(context, Java.Lang.Class.FromType(typeof(WidgetProvider)).Name);
int[] appWidgetIds = appWidgetManager.GetAppWidgetIds(componentName);
//Checks bool parameter to see if user wants to clear list
if (isDelete != true)
{
//Initialize string result that is returned from querying the command through class TerminalCommands
//Add the command itself, and the results to the list
string result = await TerminalCommands.queryCommand(command, context, appWidgetManager, appWidgetIds, widgetView);
listViewFactory.addCommand("CMD: " + command, result);
//Create Handler to facilitate Self Scrolling of Listview
//Set Scroll position, partially update app widget
//Don't know why this works instead of just setting scroll position, but hey it's android development
handler = new Handler(Looper.MainLooper);
handler.PostDelayed(async() =>
{
widgetView.SetScrollPosition(Resource.Id.listView1, ListViewFactory.items.Count - 1);
appWidgetManager.PartiallyUpdateAppWidget(appWidgetIds, widgetView);
}, 500);
}
//Bool parameter for user clearing list
else
{
listViewFactory.clearList();
widgetView.SetEmptyView(Resource.Id.listView1, Resource.Id.empty_view);
}
//Update the widget view
appWidgetManager.NotifyAppWidgetViewDataChanged(appWidgetIds, Resource.Id.listView1);
appWidgetManager.UpdateAppWidget(componentName, views);
}
//Method for receiving broadcasts from broadcast receiver
public override void OnReceive(Context context, Intent intent)
{
//Initialize view for our widget layout
base.OnReceive(context, intent);
//Rebuild the view, re-setting the intents ---> Goal is to fix bug where widget stops working after some time
//Either this or settings flags to mutable
var widgetView = BuildRemoteViews(context);
//Command Click
if (intent.Action == "com.company.CommAndroid.WIDGET_BUTTON_CLICK")
{
//Create a new intent of activity InputProvider
//Start the input provider activity
Intent inputIntent = new Intent(Application.Context, typeof(InputProvider));
inputIntent.AddFlags(ActivityFlags.NewTask);
context.StartActivity(inputIntent);
}
//Clear Click
else if (intent.Action == "com.company.CommAndroid.DELETE_BUTTON_CLICK")
{
updateListView(context, widgetView, true, "");
}
//User input
else if (intent.Action == "com.company.CommAndroid.USER_INPUT_SUBMITTED")
{
string command = intent.GetStringExtra("user_input");
updateListView(context, widgetView, false, command);
}
else if(intent.Action == "com.company.CommAndroid.LIST_ITEM_CLICK")
{
Log.Debug("hi", "we got here");
string commandText = intent.GetStringExtra("command_text");
}
}
}
}
ListViewFactory:
namespace CommAndroid
{
public class ListViewFactory : Java.Lang.Object, RemoteViewsService.IRemoteViewsFactory
{
//Globals
private Context context;
public static List<string> items;
public static List<string> results;
//Constructor to create list view factory
public ListViewFactory(Context context)
{
this.context = context;
if (items == null)
items = new List<string>();
if (results == null)
results = new List<string>();
if(items.Count == 0 && results.Count == 0)
{
items.Add("CMD: ");
results.Add("");
}
}
public void OnCreate()
{
// Initialize your data source
}
public void removeLast()
{
items.RemoveAt(items.Count - 1);
results.RemoveAt(results.Count - 1);
}
//Add's a command to the listview, removes the prior placeholder CMD text
public void addCommand(string command,string result)
{
if (items == null || items.Count < 0)
{
items = new List<string>();
}
removeLast();
items.Add(command);
results.Add(result);
items.Add("CMD: ");
results.Add("");
}
//Clear the lists
public void clearList()
{
items.Clear();
results.Clear();
items.Add("CMD: ");
results.Add("");
}
public void OnDestroy()
{
// Cleanup resources if needed
}
public int Count => items.Count;
//Method to create and set the listview view
public RemoteViews GetViewAt(int position)
{
// Create a RemoteViews object for each item in the data source, Referencing our Layout for our List View
RemoteViews remoteViews = new RemoteViews(context.PackageName, Resource.Layout.listview_layout);
//Check's if there is items, iterates until there is none
if (items != null && items.Count > position)
{
//Sets text in listview to command items and result items
//Also checks the commands text to determine what color to output
remoteViews.SetTextViewText(Resource.Id.command_text, items[position]);
if (results[position].ToLower().Split(' ')[0] == "invalid")
remoteViews.SetTextColor(Resource.Id.results_text, Color.Red);
else
remoteViews.SetTextColor(Resource.Id.results_text, Color.ParseColor("#52db02"));
if (items[position].ToLower().Split(' ')[1] == "help" || items[position].ToLower().Split(' ')[1] == "dir" || results[position].ToLower().Split(' ')[0] == "flipping")
{
if(results[position].ToLower().Split(' ')[0] != "invalid")
remoteViews.SetTextColor(Resource.Id.results_text, Color.White);
}
remoteViews.SetTextViewText(Resource.Id.results_text, results[position]);
}
//If statement checking whether the position in the list is the last one
//Sets blinking animation to visible
if (position == items.Count - 1)
{
remoteViews.SetViewVisibility(Resource.Id.blinking_dot, ViewStates.Visible);
}
else
{
remoteViews.SetViewVisibility(Resource.Id.blinking_dot, ViewStates.Gone);
}
Intent fillInIntent = new Intent();
fillInIntent.PutExtra("command_text", items[position]);
remoteViews.SetOnClickFillInIntent(Resource.Id.listviewlayout, fillInIntent);
return remoteViews;
}
public RemoteViews LoadingView => null;
public int ViewTypeCount => 1;
public long GetItemId(int position)
{
return position;
}
public bool HasStableIds => true;
public void OnDataSetChanged()
{
// Update your data source if needed
}
}
}
RemoteViewsService.cs:
namespace CommAndroid
{
//Handles the creation of the List View Factory Class --> Function to return our ListViewFactory
//Declare as service in android manifest, name is pointer for location
[Service(Enabled = true, Exported = false, Permission = "android.permission.BIND_REMOTEVIEWS")]
public class WidgetRemoteViewService : RemoteViewsService
{
public override IRemoteViewsFactory OnGetViewFactory(Intent intent)
{
return new ListViewFactory(this);
}
}
}
我的代码被上传到github repo。https://github.com/chrisz99/CommAndroid
1条答案
按热度按时间xdyibdwo1#
对不起,我从来没有做过小部件。所以这还不是一个完整的答案。
一些问题:
1.将用户输入存储在类中:
1.更改ListViewFactory构造函数以将其作为参数:
1.更改WidgetRemoteViewService.OnGetViewFactory以传入该数据:
1.* * TODO**在创建每个widget之前设置
NextData
。NextData
。我的问题(在这个答案的开头)希望能揭示在代码中需要做的地方。
WidgetRemoteViewService
的示例,那么它可以在正确的时刻设置NextData
。xamarin MessagingCenter
,并阅读有关发布/订阅的信息。试着安排一下。