I'm trying to avoid updating non-visible nested fragments.
My app has three pages of nested Fragments in a FragmentPagerAdapter. There's a TabLayout too, if that matters. It is a network client, with a communication thread updating a database, and periodically sending updates to the UI.
To accommodate the fact that there are many fragments, each caring about different aspect(s) of the data model, each fragment implements an interface along the lines of IWantUpdatesForDataType, and registers itself with the comm thread, thus:
class CommThread
public HashSet<IWantStatus> statusWanters = new HashSet<IWantStatus>();
interface IWantStatus {
public void updateStatus();
}
public void notifyStatusChange() {
for( IWantStatus wanter : statusWanters ) {
wanter.updateStatus();
}
}
class StatusFragment implements CommThread.IWantStatus {
#Override
onCreate() {
commThread.statusWanters.add(this);
}
#Override
updateSales() {
if( isVisible() ) {
// Update my cursor adapter, etc.
}
}
}
This is my first paged, fragmented app, so I might not have a good grasp of how the nesting works. That said, implementing StatusFragment.isVisible() was not difficult for fragments that I know will be root views in the FragmentPagerAdapter. This answer works best of the ones I've tried.
The problem is when the StatusFragment might be a child fragment. In that case, nothing simple seems to work. Given that fragments are supposed to be self-contained and re-usable, it seems wrong to need to care about the fragment's (hypothetical) parent visibility, along the lines of this answer (which always returns true in my pager in any case).
How can the fragment determine its own visibility, while not caring whether it is a child or root fragment?
Related
That's it, I'll step on my pride!
I'm using MRTK v2 and working fine except that at some point I want to turn off the line extending from the Motion Controller to the object and that provides input. After looking around and trying to find it in the MRTK documentation (it's gotta be easy, right?), I'm still banging my head on the wall and it's starting to hurt....
The MRTK documentation explains quite well how to configure it here:
https://github.com/microsoft/MixedRealityToolkit-Unity/blob/mrtk_release/Documentation/Input/Pointers.md
But I'm looking to do this in script, enabling and disabling it as I need it in my application.
Any clue how to do this?
Many thanks!
Answered my own question. Simple:
PointerUtils.SetMotionControllerRayPointerBehavior(PointerBehavior.AlwaysOff);
See documentation here: https://github.com/microsoft/MixedRealityToolkit-Unity/blob/mrtk_release/Documentation/Input/Pointers.md
Great question! Here's one way to do this that has worked for me. You can see my solution at this repository: https://github.com/julenka/MixedRealityToolkit-Unity/tree/so/linepointer_off. Open the scene Assets/TurnOffLinePointerTest.unity and then use hand simulation to press the buttons. The code to turn the pointers on/off is in Assets/PointerConfigurationExample.cs.
Note: the reason you need to use this approach of modifying the mediator instead of directly setting myPointer.IsActive = false is because the default mediator overwrites these values every frame. Luckily, you can customize this behavior.
Step 1: Update MRTK a bit so that PointerMediator can be accessed
Apply the changes from this commit to your MRTK clone. This change updates the FocusProvider in MRTK to make the PointerMediator publicly accessible, and makes the DefaultPointerMediator extensible by updating fields to be protected instead of private, and making methods virtual. See this pull request that implements this change directly into MRTK.
Step 2: Create a custom PointerMediator that will turn off far pointers
Create a custom Pointer Mediator like the one from this commit.
using System.Collections.Generic;
using Microsoft.MixedReality.Toolkit.Input;
public class CustomPointerMediator : DefaultPointerMediator
{
public bool FarPointersDisabled {get; set;}
public override void UpdatePointers()
{
base.UpdatePointers();
if (FarPointersDisabled)
{
foreach(var pointer in farInteractPointers)
{
pointer.IsActive = false;
}
}
}
}
Note that this mediator extends DefaultPointerMediator so it adapts almost all the default mediator logic. Make sure you have fully applied the changes from the first commit otherwise you will not be able to extend DefaultPointerMediator.
Step 3: Tell MRTK to use your custom pointer mediator
In your pointer profile, configure MRTK to use the custom pointer mediator instead of the default pointer mediator. Notice in the picture that I've created a custom pointer profile as part of a custom input system (don't modify the default profile otherwise your changes might get overwritten when you update MRTK).
Step 4: Component that uses custom mediator to turn line pointers on / off
You can now write your component which will use your custom mediator to turn the line pointers on and off.
public class PointerConfigurationExample : MonoBehaviour
{
/* Turns off all far interaction pointers */
public void TurnOffFarPointers()
{
Debug.Log("Line pointers off");
SetFarPointersDisabled(true);
}
public void TurnOnFarPointers()
{
Debug.Log("Line pointers on");
SetFarPointersDisabled(false);
}
private void SetFarPointersDisabled(bool isDisabled)
{
FocusProvider focusProvider = (FocusProvider) MixedRealityToolkit.InputSystem.FocusProvider;
if (focusProvider != null)
{
foreach(var mediator in focusProvider.PointerMediators)
{
// Note: you could check here to make sure you only disable pointers for hands
CustomPointerMediator myMediator = (CustomPointerMediator) (mediator.Value);
if (myMediator != null)
{
myMediator.FarPointersDisabled = isDisabled;
}
}
}
}
}
We are evaluating Grid Gain 6.5.5 at the moment as a potential solution for distribution of compute jobs over a grid.
The problem we are facing at the moment is a lack of a suitable asynchronous notification mechanism that will notify the sender asynchronously upon job completion (or future completion).
The prototype architecture is relatively simple and the core issue is presented in the pseudo code below (the full code cannot be published due to an NDA). *** Important - the code represents only the "problem", the possible solution in question is described in the text at the bottom together with the question.
//will be used as an entry point to the grid for each client that will submit jobs to the grid
public class GridClient{
//client node for submission that will be reused
private static Grid gNode = GridGain.start("config xml file goes here");
//provides the functionality of submitting multiple jobs to the grid for calculation
public int sendJobs2Grid(GridJob[] jobs){
Collection<GridCallable<GridJobOutput>> calls = new ArrayList<>();
for (final GridJob job : jobs) {
calls.add(new GridCallable<GridJobOutput>() {
#Override public GridJobOutput call() throws Exception {
GridJobOutput result = job.process();
return result;
}
});
}
GridFuture<Collection<GridJobOutput>> fut = this.gNode.compute().call(calls);
fut.listenAsync(new GridInClosure<GridFuture<Collection<GridJobOutput>>>(){
#Override public void apply(GridFuture<Collection<GridJobOutput>> jobsOutputCollection) {
Collection<GridJobOutput> jobsOutput;
try {
jobsOutput = jobsOutputCollection.get();
for(GridJobOutput currResult: jobsOutput){
//do something with the current job output BUT CANNOT call jobFinished(GridJobOutput out) method
//of sendJobs2Grid class here
}
} catch (GridException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
return calls.size();
}
//This function should be invoked asynchronously when the GridFuture is
//will invoke some processing/aggregation of the result for each submitted job
public void jobFinished(GridJobOutput out) {}
}
}
//represents a job type that is to be submitted to the grid
public class GridJob{
public GridJobOutput process(){}
}
Description:
The idea is that a GridClient instance will be used to in order to submit a list/array of jobs to the grid, notify the sender how many jobs were submitted and when the jobs are finished (asynchronously) is will perform some processing of the results. For the results processing part the "GridClient.jobFinished(GridJobOutput out)" method should be invoked.
Now getting to question at hand, we are aware of the GridInClosure interface that can be used with "GridFuture.listenAsync(GridInClosure> lsnr)"
in order to register a future listener.
The problem (if my understanding is correct) is that it is a good and pretty straightforward solution in case the result of the future is to be "processed" by code that is within the scope of the given GridInClosure. In our case we need to use the "GridClient.jobFinished(GridJobOutput out)" which is out of the scope.
Due to the fact that GridInClosure has a single argument R and it has to be of the same type as of GridFuture result it seems impossible to use this approach in a straightforward manner.
If I got it right till now then in order to use "GridFuture.listenAsync(..)" aproach the following has to be done:
GridClient will have to implement an interface granting access to the "jobFinished(..)" method let's name it GridJobFinishedListener.
GridJob will have to be "wrapped" in new class in order to have an additional property of GridJobFinishedListener type.
GridJobOutput will have to be "wrapped" in new class in order to have an addtional property of GridJobFinishedListener type.
When the GridJob will be done in addition to the "standard" result GridJobOutput will contain the corresponding GridJobFinishedListener reference.
Given the above modifications now GridInClosure can be used now and in the apply(GridJobOutput) method it will be possible to call the GridClient.jobFinished(GridJobOutput out) method through the GridJobFinishedListener interface.
So if till now I got it all right it seems a bit clumsy work around so I hope I have missed something and there is a much better way to handle this relatively simple case of asynchronous call back.
Looking forward to any helpful feedback, thanks a lot in advance.
Your code looks correct and I don't see any problems in calling jobFinished method from the future listener closure. You declared it as an anonymous class which always has a reference to the external class (GridClient in your case), therefore you have access to all variables and methods of GridClient instance.
So, I'm trying to use a ViewPager from Android's support v4 library, but there's some serious issues with how it (or FragmentPagerAdapter) deals with Fragments. For instance, I subclassed FragmentPagerAdapter to do the following:
public class MyPagerAdapter extends FragmentPagerAdapter
{
private ArrayList<Fragment> fragments = null;
private ArrayList<Data> data = null;
public MyPagerAdapter(FragmentManager fragmentManager, ArrayList<Data> data)
{
super(fragmentManager);
this.data = data;
fragments = new ArrayList<Fragment>();
for(Data datum : data)
{
MyDataFragment fragment = new MyDataFragment();
fragment.setData(datum);
fragments.add(fragment);
}
}
#Override
public Fragment getItem(int i)
{
return fragments.get(i);
}
#Override
public int getCount()
{
return fragments.size();
}
}
Now, I thought this would be sufficient, and that I could go on and implement MyDataFragment using the onCreateView method that Fragments typically implement. But I ran into an interesting problem. When I would navigate away from the Activity, and then back to it, the ViewPager would appear blank. Somehow, it was reusing Fragments by calling findFragmentByTag, then simply not even calling getItem, etc. What's worse, the Fragment would get no onCreateView event. So I figured I could utilize the ViewPager's Fragment caching by moving my onCreateView code, which primarily grabs references to the various Views the fragment inflates, to onAttach. The only problem is, that during onAttach, MyDataFragment's getView method always returns null. All of the examples for Fragments online describe that onCreateView should have all of your view setup code. Ok, fine. But then, when I create a method like MyDataFragment.setSomeField(String value), I need to use a reference to a TextView. Since onCreateView doesn't always get called (like, when Fragments are magically recycled by FragmentPagerAdapter, for instance), it's better to grab that reference in onAttach. However, during onAttach, the root view for the Fragment is still null (probably because onCreateView wasn't called in the first place)! No additional events happen after that (with the exception of onActivityCreated, which has nothing to do with the Fragment itself), so there's no place to do setup code. How is this supposed to work? Am I missing something important here, or was the Fragment system designed by a monkey?
I'm not sure that this is the right use case for a FragmentPagerAdapter (it sounds more like something you'd want to do with a ListAdapter).
From the FragmentPagerAdapter docs:
Implementation of PagerAdapter that represents each page as a Fragment
that is persistently kept in the fragment manager as long as the user
can return to the page.
This version of the pager is best for use when there are a handful of
typically more static fragments to be paged through, such as a set of
tabs. The fragment of each page the user visits will be kept in
memory, though its view hierarchy may be destroyed when not visible.
This can result in using a significant amount of memory since fragment
instances can hold on to an arbitrary amount of state. For larger sets
of pages, consider FragmentStatePagerAdapter.
I'd consider switching to the FragmentStatePagerAdapter or perhaps a ListAdapter.
If you want the createView to be called it will have to be recreated each time (destroy the old fragment and create new ones), but again I don't think that's quite what you want.
I'm trying to follow the examples provided in this post, to create a dynamic list constraint in Alfresco 3.3.
So, I've created my own class extending ListOfValuesConstraint:
public class MyConstraint extends ListOfValuesConstraint {
private static ServiceRegistry registry;
#Override
public void initialize() {
loadData();
}
#Override
public List getAllowedValues() {
//loadData();
return super.getAllowedValues();
}
#Override
public void setAllowedValues(List allowedValues) {
}
protected void loadData() {
List<String> values = new LinkedList<String>();
String query = "+TYPE:\"cm:category\" +#cm\\:description:\"" + tipo + "\"";
StoreRef storeRef = new StoreRef("workspace://SpacesStore");
ResultSet resultSet = registry.getSearchService().query(storeRef, SearchService.LANGUAGE_LUCENE, query);
// ... values.add(data obtained using searchService and nodeService) ...
if (values.isEmpty()) {
values.add("-");
}
super.setAllowedValues(values);
}
}
ServiceRegistry reference is injected by Spring, and it's working fine. If I only call loadData() from initialize(), it executes the Lucene query, gets the data, and the dropdown displays it correctly. Only that it's not dynamic: data doesn't get refreshed unless I restart the Alfresco server.
getAllowedValues() is called each time the UI has to display a property having this constraint. The idea on the referred post is to call loadData() from getAllowedValues() too, so the values will be actually dynamic. But when I do this, I don't get any data. The Lucene query is the same, but returns 0 results, so my dropdown only displays -.
BTW, the query I'm doing is: +TYPE:"cm:category" +#cm\:description:"something here", and it's the same on each case. It works from initialize, but doesn't from getAllowedValues.
Any ideas on why is this happening, or how can I solve it?
Thanks
Edit: we upgraded to Alfresco 3.3.0g Community yesterday, but we're still having the same issues.
This dynamic-list-of-values-constraint is a bad idea and I tell you why:
The Alfresco repository should be in a valid state all the time. Your (dynamic) list of constraints will change (that's why you want it to be dynamic). Adding items would not be a problem, but editing and removing items are. If you would remove an item from your option-list, the nodes in the repository with this property value will be invalid.
You will not be able to fix this easily. The standard UI will fail on invalid-state-nodes. Simply editing this value and setting it to something valid will not work. You have been warned.
Because the default UI widget for a ListConstraint is a dropdown, not every dropdown should be a ListConstraint. ListConstraints are designed for something like a Status property: { Draft, Waiting Approval, Approved }. Not for a list of customer-names.
I have seen this same topic come up again and again over the last few years. What you actually want is let the user choose a value from a dynamic list of options (combo box). This is a UI problem, not a dictionary-model-issue. You should setup something like this with the web-config-context.xml (Alfresco web UI) or in Alfresco Share. The last one is more flexible and I would recommend taking that path.
I have a simple page with a Grid that I'm binding a collection of objects to. I also have some simple functionality on the grid to edit and save rows. I would like to write unit tests for this page, but it's not really making sense to me.
For example:
Private Sub LoadGrid()
'Populate Collection
grid.datasource = MyCollection
grid.databind()
end sub
I guess a Sub really doesn't need a unit test, but what if this were a function that returned true when the grid had been loaded. How do you write a unit test for this? What other test should be done on a simple web page like this?
As always, thanks to everyone who give any sort of input.
How do you write a unit test for this?
The first step is actually making your form testable. Have a look at this page for separating UI and BL layers, there are about a bajillion different ways to implement MVC, MVP, and all of its variants, and there's no One True Way™ to do it. So long as your code is sane and consistent, other people will be able to work on your code.
I personally find the following pattern works in most cases for testing UIs:
Create an interface representing your Model.
Create a class for your controller which handles all the updates to the model.
Your view should listen to changes to the model.
So in the end, you end up with something like this (sorry, my VB-fu is rusty, writing this in C# instead):
interface IProductPageModel
{
int CurrentPage { get; set; }
int ItemsPerPage { get; set; }
DataSet ProductDataSet { get; set; }
}
class ProductPageController
{
public readonly IProductPageModel Model;
public ProductPageController(IProductPageModel model)
{
this.Model = model;
}
public void NavigateTo(int page)
{
if (page <= 0)
throw new ArgumentOutOfRangeException("page should be greater than 0");
Model.CurrentPage = page;
Model.ProductDataSet = // some call to retrieve next page of data
}
// ...
}
This is concept code, of course, but you can see how its very easy to unit test. In principle, you could re-use the same controller code in for desktop apps, silverlight, etc since your controller doesn't depend directly on any particular view implementation.
And finally on your form side, you'd implement your page similar to:
public class ProductPage : Page, IProductPageModel
{
ProductPageController controller;
public ProductPage()
{
controller = new ProductPageController(this);
}
public DataSet ProductDataSet
{
get { return (DataSet)myGrid.DataSource; }
set { myGrid.DataSource = value; myGrid.DataBind(); }
}
protected void NavigateButton_OnCommand(object sender, CommandEventArgs e)
{
controller.NavigateTo(Convert.ToInt32(e.CommandArgument));
}
}
Here there's no real distinction between view and model -- they're the same entity. The idea is to make your code-behind as "stupid" as possible, so that as much testable business logic is contained in the controller as possible.
What other test should be done on a
simple webpage like this?
You'd want tests for any sort of form validation, you want to make sure you're throwing exceptions in exceptional cases, ensuring that your controller methods update your model in an expected way, and so on.
Juliet is right.
The line of code where you said
'Populate Collection
that is the testable part. You can do assertions on if the collection is null, if it has items, if it has exactly 42 items. But that would be an integration test.
If you can isolate all the calls to the database (the part that returns a datareader), then return a empty, fake DbDataReader, then you can test everything inbetween the UI and the database.
Tests that spin up a browser and verify that a table is render, similarly is a integration test that will depend on having IIS up and working (and a DB up and working, unless you have a repository you can fake)
If you are just getting started, I would look for all the easy to test code first, such as methods that do have dependencies on the database, then move on the tricker tests that require mocking/stubbing/faking database servers, etc.