Initializing a Fragment - android-fragments

I am new to Android and having an issue in initializing Fragment
I am looking at two lines of code and cannot figure out the actual difference between these two approaches and which one to opt. Kindly suggest
1) SignUpFragment fragment = new SignUpFragment();
2) SignUpFragment fragment = SignUpFragment.newInstance();

I personally use the first one as it will make a new object of signupFragment ,while the second option will make a new instance of that class.The difference between both is defined in the below link.
https://stackoverflow.com/questions/3323330/difference-between-object-and-instance

If you have no arguments to pass to fragment you can use first one.
SignUpFragment fragment = new SignUpFragment();
But if you have arguments you can use factory methods such as second one to hide creating bundle and putting the arguments' boilerplate codes.
ProfileFragment fragment = ProfileFragment.newInstance(userId);
public class ProfileFragment extends Fragment {
public static ProfileFragment newInstance(int userId) {
Bundle args = new Bundle();
args.putInt("userId", userId);
ProfileFragment fragment = new ProfileFragment();
fragment.setArguements(args);
return fragment;
}
}

1) SignUpFragment fragment = new SignUpFragment();
You should only use in case you do NOT need to create SignUpFragment instance more frequently.
2) SignUpFragment fragment = SignUpFragment.newInstance();
This is more recommended approach. In which, you would going to follow Singleton pattern for creating Instance of your class and more generic methods can be created in future if needed.

Related

Unity to DryIoC conversion ParameterOverride

We are transitioning from Xamarin.Forms to .Net MAUI but our project uses Prism.Unity.Forms. We have a lot of code that basically uses the IContainer.Resolve() passing in a collection of ParameterOverrides with some primitives but some are interfaces/objects. The T we are resolving is usually a registered View which may or may not be the correct way of doing this but it's what I'm working with and we are doing it in backend code (sometimes a service). What is the correct way of doing this Unity thing in DryIoC? Note these parameters are being set at runtime and may only be part of the parameters a constructor takes in (some may be from already registered dependencies).
Example of the scenario:
//Called from service into custom resolver method
var parameterOverrides = new[]
{
new ParameterOverride("productID", 8675309),
new ParameterOverride("objectWithData", IObjectWithData)
};
//Custom resolver method example
var resolverOverrides = new List<ResolverOverride>();
foreach(var parameterOverride in parameterOverrides)
{
resolverOverrides.Add(parameterOverride);
}
return _container.Resolve<T>(resolverOverrides.ToArray());
You've found out why you don't use the container outside of the resolution root. I recommend not trying to replicate this error with another container but rather fixing it - use handcoded factories:
internal class SomeFactory : IProductViewFactory
{
public SomeFactory( IService dependency )
{
_dependency = dependency ?? throw new ArgumentNullException( nameof(dependency) );
}
#region IProductViewFactory
public IProductView Create( int productID, IObjectWithData objectWithData ) => new SomeProduct( productID, objectWithData, _dependency );
#endregion
#region private
private readonly IService _dependency;
#endregion
}
See this, too:
For dependencies that are independent of the instance you're creating, inject them into the factory and store them until needed.
For dependencies that are independent of the context of creation but need to be recreated for each created instance, inject factories into the factory and store them.
For dependencies that are dependent on the context of creation, pass them into the Create method of the factory.
Also, be aware of potential subtle differences in container behaviours: Unity's ResolverOverride works for the whole call to resolve, i.e. they override parameters of dependencies, too, whatever happens to match by name. This could very well be handled very differently by DryIOC.
First, I would agree with the #haukinger answer to rethink how do you pass the runtime information into the services. The most transparent and simple way in my opinion is by passing it via parameters into the consuming methods.
Second, here is a complete example in DryIoc to solve it head-on + the live code to play with.
using System;
using DryIoc;
public class Program
{
record ParameterOverride(string Name, object Value);
record Product(int productID);
public static void Main()
{
// get container somehow,
// if you don't have an access to it directly then you may resolve it from your service provider
IContainer c = new Container();
c.Register<Product>();
var parameterOverrides = new[]
{
new ParameterOverride("productID", 8675309),
new ParameterOverride("objectWithData", "blah"),
};
var parameterRules = Parameters.Of;
foreach (var po in parameterOverrides)
{
parameterRules = parameterRules.Details((_, x) => x.Name.Equals(po.Name) ? ServiceDetails.Of(po.Value) : null);
}
c = c.With(rules => rules.With(parameters: parameterRules));
var s = c.Resolve<Product>();
Console.WriteLine(s.productID);
}
}

Can you programmatically switch between existing Session Contexts

I have multiple existing Stateful Session Beans. I want to use a new library/framework that instantiates objects (outside the container manager). This framework does not conceptually have 'sessions'. I'm trying to develop a proof of concept to route calling of beans in different session contexts based on a map of session identifiers to session contexts.
Below are 2 handlers that are instantiated by the library. The first handler creates new BoundSessionContexts and maps them to generated keys. The second handler is suppose to be passed the key and based on it propagate to the appropriate corresponding sessionContext, lookup the beans in that context, and call those beans.
public class Handler1 implements Handler1Interface{
//**1**
WeldManager weldManager = (WeldManager) CDI.current().getBeanManager();
BoundSessionContext boundSessionCtx;
//**2**
Map<String, Object> sessionMap = new HashMap<>();
public Handler1(){
}
//**3**
#Override
public long start(){
long sessionId = new Random().nextLong();
//**4**
boundSessionCtx = weldManager.instance().select(BoundSessionContext.class, BoundLiteral.INSTANCE).get();
//**5**
//boundSessionCtx.associate(sessionMap);
//Make certain the sessionId isn't already in use.
while(SessionMapper.get(sessionId)!=null){
sessionId = new Random().nextLong();
}
//**6**
SessionMapper.put(sessionId, boundSessionCtx);
return sessionId;
}
//**7**
#Override
public void stop(long sessionId){
SessionMapper.remove(sessionId);
}
}
public class Handler2 implements Handler1Interface{
//**8**
#Inject
EJB1 ejb1;
//**9**
#Inject
EJB2 ejb2;
BeanManager beanManager;
BoundSessionContext boundSessionCxt;
//**10**
Map<String, Object> sessionMap = new HashMap<>();
public Handler2(){
}
#Override
public Object process(long sessionId, Object input){
lookupEJBs(sessionId);
//**11**
ejb1.method();
Object result = ejb2.method();
return result;
}
//**12**
private void lookupEJBs(long sessionId) {
boundSessionCxt = SessionMapper.get(sessionId);
boundSessionCxt.associate(sessionMap);
boundSessionCxt.activate();
beanManager = CDI.current().getBeanManager();
//**13**
TypeLiteral<EJB1> typeLiteral = new TypeLiteral<EJB1>() {};
Set<Bean<?>> beans = beanManager.getBeans(typeLiteral.getType());
Bean<?> bean = beanManager.resolve(beans);
ejb1 = bean.create(boundSessionCxt);
//**14**
TypeLiteral<EJB2> typeLiteral2 = new TypeLiteral<EJB2>() {};
beans = beanManager.getBeans(typeLiteral2.getType());
bean = beanManager.resolve(beans);
ejb2 = bean.create(boundSessionCxt);
}
I've never been able to call ejb2.method(). While I have used EJBs for many years this is my first attempt at manipulating contexts. I am definitively feeling lost. It's one thing to use the magic, it's another to warp that magic to your whim.
Questions (In no particular order):
A) Is what I'm trying to do 'reasonably' acheivable? Or is this a pipe dream? NOTE: I am currently using WELD-API 3.0.SP4, but I am not married to it.
B) I have never truly understood the reason for the map(10) that is associated with a context(12).
B1) What is it's purpose?
B2) How does it's use affect what I'm trying to do here?
B3) Am I correct in that I would want to associate and activate the context inside the object where I want to use the context beans?
C) Am I correct that #Inject (8 and 9) is pointless as the handler2 object is not instantiated/Injected by the bean manager.
Many thanks to anyone who can help me understand EJB/CDI session contexts better. :)

How to reuse a Fragment and ViewModel with different Repository Implementation injected by Dagger2.2

I'm kinda new to Android development and I have been stuck finding a way to do this pattern using some android libraries like Dagger2, Fragments, and ViewModel.
I hope some of you can help me with this or stating what's the common way to do this on android.
I'm looking for something like this:
class FragmentPager: Fragment() {
#Inject
#Named("FullListFragment")
lateinit var listFragment: ListFragment
#Inject
#Named("FilteredListFragment")
lateinit var filteredListFragment: ListFragment
//Use fragments in the viewPager.
}
What I am trying to do:
I have a Fragment that shows a list of elements. It also has a ViewModel responsible for updating the list among other things. The ViewModel gets the list from a Repository that queries a database. Pretty straightforward so far.
My use case is that my app shows the list of elements in a lot of different areas within the application but with different data. For example full list, filtered list...
My idea was to create the repository as an interface with a single method: fun getItems(): List<Item> and different instances for each data source. As a result, I have:
ListFragment (class inheriting from Fragment)
ListViewModel (class inheriting from ViewModel)
ListRepository (interface)
FullListRepository (class implementing ListRepository) --> Gets all items from DB
FilterListRepository (class implementing ListRepository) --> Gets filter items from DB
JoinedListRepository (class implementing ListRepository) --> Gets items from DB but from joining different tables
These elements will work together in an ideal world like this:
fun buildListFragment(repository: ListRepository) {
val viewModel = ListViewModel(repository)
val fragment = ListFragment(viewModel)
return fragment
}
val fullListFragment = buildListFragment(FullListRepository())
val filteredListFragment = buildListFragment(FilterListRepository())
val joinedListFragment = buildListFragment(JoinedListRepository())
How can I do something like these using Dagger2 to inject dependencies, ViewModelFactory to create ViewModels, and Fragments.
Limitations I encounter:
My ViewModel has params so only can be created via ViewModelFactory.
ViewModel cannot be injected by the constructor to the Fragment and need to be created inside using viewModelFactory in onCreate. At this point is it impossible to tell Dagger2 which ListRepository implementation should use to create ViewModelFactory.
class ListFragment: Fragment() {
#Inject
lateinit var viewModelFactory: ViewModelProvider.Factory
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
viewModel = ViewModelProvider(this, viewModelFactory).get(CardListViewModel::class.java)
}
}
I know that you can use #Named annotation to request injection of the different repository implementations but when the factory is created inside Fragment body it is too late to request the #Named repository cause you know which repository you need before creating the fragment not after.
Questions:
Is this solution possible using Dagger2 and ViewModels?
How Can I achieve it? Any advice?
Do you usually use another pattern that could fit in the same use case?
I'm typically testing my answers before posting them but with mr. dagger that would be too much. That said, this is my educated guesswork:
Having single fragment that knows how to pull 3 different data sets (full, filtered, joined) means it needs to be parametrized somehow. I guess it can be done with named injection but I'd simply use MyFragment.newInstanceA(), MyFragment.newInstanceB() etc when needed.
Inside the fragment, likely using android injection as I think you're doing already, single free form factory is constructor-injected with all 3 repositories that implement single interface. That factory would wrap your implementation of ViewModelProvider.Factory and have a method, say create, with parameter the fragment was instantiated with.
Based on parameter value, factory would create and return properly parametrized implementation of ViewModelProvider.Factory. View model provider would then be able to get properly parametrized view model. I know this is not a lot of dagger but in theory it should just work :)
PS.: I'd not create 3 different repos if data is essentially coming from single storage apparently. May be this calling of different repo methods needs to be done under view model.
I would start off with redesigning the repository like this:
interface ListRepository {
fun getFullList(): LiveData<List<Product>>
fun getFilteredList(): LiveData<List<Product>>
fun getJoinedList(): LiveData<List<Product>>
}
LiveData is used here assuming you'd be using room.
Then design my ViewModel to be able to get the desired list given the listType input.
class ListViewModel #Inject constructor(
private val listRepository: ListRepository
) : ViewModel() {
private val listType = MutableLiveData<String>()
val productList = Transformations.switchMap(listType) {
getList(it)
}
// call from fragment
fun fetchList(listType: String) {
this.listType.value = listType
}
private fun getList(listType: String): LiveData<List<Product>> {
return when (listType) {
"full" -> listRepository.getFullList()
"filter" -> listRepository.getFilteredList()
"joined" -> listRepository.getJoinedList()
else -> throw IllegalArgumentException("Unknown List Type")
}
}
}
switchMap is used here to prevent the repository from returning a new LiveData instance every time we fetch the list from fragment. Then comes the fragment to wrap things up.
class ListFragment : Fragment() {
lateinit var listType: String
#Inject
lateinit var viewModelFactory: ViewModelProvider.Factory
private val viewModel: ListViewModel by viewModels { viewModelFactory }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
listType = arguments?.getString("listType")
?: throw java.lang.IllegalArgumentException("No listType args found")
viewModel.fetchList(listType)
viewModel.productList.observe(viewLifecycleOwner) { products ->
TODO("render products on recycler view")
}
}
}
Only one fragment is used for the whole three list types cause I'm assuming those fragments are more or less identical in terms of Ui. List will be fetched and displayed according to the listType argument passing in.
fragmentManager.beginTransaction()
.add(R.id.content,ListFragment().apply {
arguments = Bundle().apply {
putString("listType","full")
}
})
.commitNow()

How to pass object to an ArrayList in different Controllers(java FX)

In JAVA FX have an application with one window that creates a customer with insurances and another window with a tableView where I want to show information about the customers. In the tableView window, I also have an ArrayList. When I close the registration window the application sends the customer object to the ArrayList. This works fine, but when I do register another customers insurance, the ArrayList seems to go empty before taking in the new object. Summarized it seems that my ArrayList only will hold one object at a time.
//In the registration controller, this code is called when I close the window and pass the customer object
FXMLDocumentController controller = loader.getController();
controller.initForsikredeKunder(passedCustomer);
//---------- In the view tableclass
private ArrayList = null;
public void initForsikredeKunder (Kunde customer) {
if(kundeListe == null) {
kundeListe = new ArrayList<Kunde>();
}
this.kundeListe.add(customer);
}
Why does the ArrayList just hold one customer? seems to me that this code only makes one ArrayList, and then just should just add customers
as they get passed to the method. However, that is not happening
You do appear to have a typo, so I assume private ArrayList = null is really:
private ArrayList kundeListe = null;
The code looks fine (I'm guessing at some of the context), although there are some things I would improve. It only creates a new list when "kundeListe" is null - so the list isn't getting wiped out. So if you call initForsikredeKunder() a second time, all it'll do is add a second "customer".
Basically, you can just call initForsikredeKunder() repeatedly and it'll work fine.
I would rename initForsikredeKunder to say "add" instead of init. It's really an add operation which also handles lazy initialization of a backing list.
Going further, you could do this:
private List<Kunde> kundeListe = new ArrayList<>();
and remove the lazy init:
public void addKunder (Kunde customer) {
kundeListe.add(customer);
}
Note: I'm not 100% I understood your narrative above, so I could be misunderstanding what's going on. If this "dialog/window" only ever works with a single customer, you don't even need to use the List!
Edits after additional info provided:
Based on your code it looks like the original dialog isn't being re-used. The "new FXMLLoader()" part is fine.
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("FXMLDocument.fxml"));
Parent tableViewParent = loader.load();
Scene tableViewScene = new Scene(tableViewParent); //Access the controller and call the method
FXMLDocumentController controller = loader.getController();
controller.initForsikredeKunder(valgtKunde); // having trouble finding what it should say instead of = new FXMLLoader();
So probably the easiest thing to do, if your dialog requires multiple customers, is to just pass in more than one with the initForsikredKunder() call.
How about this?
public void initForsikredeKunder (Kunde... customer) {
if(kundeListe == null) {
kundeListe = new ArrayList<Kunde>();
}
for (Kunde cust : customer) {
this.kundeListe.add(cust);
}
}
Then change the initForsikredeKunder() call to this:
controller.initForsikredeKunder(valgtKunde1, valgtKunde2, valgtKunde3);//Add as many as you need
If you already have a long list of "valgtKunde":
public void initForsikredeKunder (List<Kunde> customers) {
if(kundeListe == null) {
kundeListe = new ArrayList<Kunde>();
}
this.kundeListe.addAll(customers);
}
... and pass the list to initForsikredeKunder(customerList);
This is the kind of thing where the larger context matters, unfortunately it's hard to convey all of that here I guess, so there could be some adjustments required depending on broader context. (i.e. what data you're starting with and what the dialog functionality supports)

Unit test controller that uses application scoped variables

I'm building an ASP.NET MVC4 app. I'm not using any mocking framework and, if possible, would prefer not to at this point. My question is 2 parts.
I have a controller that uses a variable created in Global.asax. In the controller I access the variable like this.
HttpContext.Application["MyVar"]
1) Is this a best-practice for application wide variable usage? If not, what's the best way?
In an attempt to unit test this controller I added the following code (from here) to my test method.
MyController target = new MyController();
var request = new HttpRequest("", "http://example.com/", "");
var response = new HttpResponse(System.IO.TextWriter.Null);
var httpContext = new HttpContextWrapper(new HttpContext(request, response));
target.ControllerContext = new ControllerContext(httpContext, new RouteData(), target);
target.ControllerContext.HttpContext.Application["MyVar"] = new MyVar();
The problem is I can't add anything to Application. The last line of code doesn't seem to do anything and the collection remains empty. I've also tried this in VS's Immediate Window without success.
2) In the unit test, how can I add the application level variables the controller needs?
In general globals aren't good for testing. There are at least two approaches you could take.
Use a mocking framework like Pex/Moles, NMock, etc.
Use an inversion-of-control approach (NInject is my favorite). If class like a controller has an external dependency, it asks for the interface, typically in its constructor.
private readonly IApplicationSettings _settings;
public MyController(IApplicationSettings settings)
{
_settings = settings;
}
void someMethod()
{
_settings.Get("MyVar");
}
This way you can write real and test implementations.
public LiveAppSettings : IApplicationSettings
{
public string Get(string key)
{
return HttpContext.Current.Application[key];
}
}
With Ninject, you can bind either implementation at application startup:
var kernel = new StandardKernel();
kernel.Bind<IApplicationSettings>().To<LiveAppSettings>();
Is this a best-practice for application wide variable usage?
Best practice is a bit of a subjective notion and without fully explaining your scenario and what precisely are you trying to achieve I prefer not to discuss it.
We cannot discuss whether this is best practice but from what I can see it is not wrong either. It is not wrong because you are using the abstractions allowing the code to be unit tested.
In the unit test, how can I add the application level variables the controller needs?
You could use a mocking framework such as Rhino Mocks to mock the abstractions that the controller needs. Let's take as an example the following controller:
public class HomeController : Controller
{
public ActionResult Index()
{
var myVar = (MyVar)HttpContext.Application["MyVar"];
return Content(myVar.Foo);
}
}
and we would like to unit test the Index action. Here's a sample unit test:
[TestMethod]
public void Index_Action_Should_Retrieve_MyVal_From_AppState()
{
// arrange
var target = new HomeController();
var httpContext = MockRepository.GeneratePartialMock<HttpContextBase>();
var application = MockRepository.GeneratePartialMock<HttpApplicationStateBase>();
application.Expect(x => x["MyVar"]).Return(new MyVar { Foo = "bar" });
httpContext.Expect(x => x.Application).Return(application);
target.ControllerContext = new ControllerContext(httpContext, new RouteData(), target);
// act
var actual = target.Index() as ContentResult;
// assert
Assert.AreEqual("bar", actual.Content);
}

Resources