This is a continuation from the question I 1st asked here, Creating a new ArrayPagerAdapter with variety of Fragments. You were dead on about me using the wrong ArrayAdapter I just needed to use the one that has v4 support. I have posted the code for it below. One of the next blocks i'm getting stuck on right now is creating the PageDescriptor objects in the ArrayList passed into SimplePageAdapter. I've tried copying and pasting the SimplePageDescriptor class used in the Demo into my code but I am getting an error when trying to return from the Parceable.Creator method. It says SimplePageDescriptor has private access in com.commonsware.cwac.pager.SimplePageDescriptor. I guess the main thing i'm trying to grasp is how to use the SimplePageDescriptor from the demo in my own code. Do I just use the entire pager folder? I have posted my code for the SimplePagerAdapter and the SimplePageDescriptor below.
class SimplePagerAdapter extends ArrayPagerAdapter<android.support.v4.app.Fragment> {
public SimplePagerAdapter(FragmentManager fragmentManager,
ArrayList<PageDescriptor> descriptors) {
super(fragmentManager, descriptors);
}
#Override
protected Fragment createFragment(PageDescriptor desc) {
mMainFragment = JudgeMainFragment.newInstance();
mClassifyFragment = JudgeClassifyFragment.newInstance();
mSidebarFragment = JudgeSidebarFragment.newInstance((SidebarCall) mActivity);
mVerdictFragment = JudgeVerdictFragment.newInstance();
return (mMainFragment.newInstance());
}
}
public static final Parcelable.Creator<com.commonsware.cwac.pager.SimplePageDescriptor> CREATOR=
new Parcelable.Creator<com.commonsware.cwac.pager.SimplePageDescriptor>() {
public com.commonsware.cwac.pager.SimplePageDescriptor createFromParcel(Parcel in) {
//This is the line I get the error at
return new com.commonsware.cwac.pager.SimplePageDescriptor(in);
}
public com.commonsware.cwac.pager.SimplePageDescriptor[] newArray(int size) {
return new com.commonsware.cwac.pager.SimplePageDescriptor[size];
}
};
One of the next blocks i'm getting stuck on right now is creating the PageDescriptor objects in the ArrayList passed into SimplePageAdapter
PageDescriptor is an interface. Create your own class (e.g., BlainePageDescriptor) that implements the interface. This is covered in the documentation.
I've tried copying and pasting the SimplePageDescriptor class used in the Demo into my code
That will not solve your problem.
Your problem, as I understand it, is that you want your ArrayPagerAdapter to be able to handle N different types of pages (JudgeMainFragment, JudgeClassifyFragment, etc.). That requires you to return the proper fragment from createFragment(), given the supplied PageDescriptor. Hence, you need to create your own PageDescriptor implementation (e.g., BlainePageDescriptor). That class needs to hold onto sufficient information to both satisfy the PageDescriptor interface and be able to tell createFragment() what sort of fragment to create.
Related
Clean Architecture Question
I have many form activities that has 1 common data that must be appended during submission, my question is, where will the logic must be placed?
Domain or Presentation Layer?
For Presentation:
I'll create a BaseFormActivity that has a method of inserting the needed data on a form that is child of BaseForm which contains the needed data globally.
BaseForm: (to be extended by all forms)
public class BaseForm {
private String globalData;
//getter setters...
}
BaseFormPresenter:
public class BaseFormPresenter extends BaseFormMvpView {
private final GetGlobalDataInteractor mGetData; //to be injected, this is a use case
public void getGlobalData() {
mGetData.execute()
.subscribe(data -> {
getMvpView().showGlobalData(data);
}); //just for the sake of simplicity
}
}
BaseFormActivity: (which is extended by all activity that handles form)
public abstract class BaseFormActivity implements BaseFormMvpView {
#Inject
BaseFormPresenter mPresenter;
//onCreate(), etc
}
SpecificFormActivity: (extends BaseFormActivity)
public class SpecificFormActivity extends BaseFormActivity {
private SpecificForm mForm; //extends BaseForm
//onCreate(), etc
#Override
public void showGlobalData(String data) {
mForm.setGlobalData(data);
}
//then ill just call the presenter to get the global data before submitting
}
For Domain:
SubmitSpecificFormInteractor: (Sorry for the coding, it is just a representation on what I'm thinking to do)
public class SubmitSpecificFormInteractor extends SingleUseCase<Return, Param> {
//to be injected
GlobalRepository mGlobalRepository;
SpecificFormRepository mFormRepository;
//some initialization
public Single<SomeResponse> buildObservable(#NonNull String specificFormData, String anotherSpecificFormData) {
return mGlobalRepository.getGlobalData()
.map(globalData -> SpecificFormDto.create(
specificFormData, anotherSpecificFormData, globalData)) //create the dto then append global data
.flatMap(specificFormDto -> mFormRepository.submit(specificFormDto)) //then submit data
}
}
I'm thinking of placing it on the domain layer (you can see that it is much isolated, but I'll have to do it on all form submissions, which is redundancy), but still I just want to make my decision solid. Refactoring is time consuming. Hope you understand my point here, specially on my pseudocode-like coding. Feel free to comment if there's something hard to understand. Thank you.
In Clean Architecture all business rules go to use case interactors. The main goal is to keep the business rules independent from any details - from any framework - that includes android as well.
The Clean Architecture then uses "interface adapters" (in UI part called "controllers" and "presenters") to map between data most convenient for the inner circles and data convenient for the frameworks.
So in ur case u should go for ur second proposal - even if that means that u have to call the interactor from multiple places and have to map some data types. it is worth the benefits (business rules free from details).
For a more detailed discussion about use case interactors, controllers and presenters pls refer to my posts here: https://plainionist.github.io/Implementing-Clean-Architecture-UseCases/
and here https://plainionist.github.io/Implementing-Clean-Architecture-Controller-Presenter/
I have multiple fragments which does the same thing but presented in different way to the user. However, the functionality in all those fragments more like same as in delete, add etc. That said, I do not want to duplicate the code. Therefore created a manager class so that I could have the centralized code. But, the problem now is, when the user is performing an action say, when the user is deleting an item, the fragment does not get refreshed. So, I need to send the message to the fragment from the manager class to refresh the list. I have the following pseudo code to give an insight...
public class MyFragment extends Fragment{
ManagerClass mManagerClass;
private void onItemSelected() {
mManagerClass = new ManagerClass(itemId);
}
public void refreshItems() {
ItemDao.query();
}
}
public class ManagerClass {
public ManagerClass(int itemId) {
DeleteItem(itemId);
}
private void DeleteItem(int itemId) {
//when this task completes it should call the MrFragment.refreshItems();
//Keep in mind that I cannot pass the Fragment becuse this ManagerClass is designed to handle more than two fragments
//MAY BE I SHOULD DO CALLBACK BUT HOW?.... When i try to implement there several callbacks but not sure which one should I use and how...
}
}
Any help would be greatly appreciated...
I was so stupid and dumb at the time. There are multiple ways to achieve this but the quick resolutions are:
1. Have a ABSTRACT class and extend the fragment out of it or
2. Use the OBSERVER pattern
I went with the second option, Observer pattern and works like a charm!
I need a little help with my Interface. I think that i doesn't understand them at all.
So i created this interface to notify every classes that implements it when a certain event occurs.
public interface OnColorsChangeListener {
void onColorsChangeListener(ColorsProp colorsProp);
}
My class that hold the interface:
private OnColorsChangeListener mCallback;
... // other code
// the event occurs here so i call:
mCallback.onColorsChangeListener(mProps);
// but of course here i get an NPE becouse this is undefined in this class.. well, with some replies here i'll understand better how to use that for reach my point
The class that implements it:
public class ClassTest implements OnColorsChangeListener {
... // other code
#Override
public void onColorsChangeListener(ColorsProp colorsProp) {
Log.d(TAG, "Color changed! " + colorsProp.color);
}
i put this in 4/5 classes to be notified in the same time for the color change. I'm quite sure the reason is that I didn't understand very well how them works, so can anyone point me to the right direction? Thank you!
Explanation by example:
You have to instantiate your callback, & it has to be an instance of your class
private OnColorsChangeListener mCallback;
mCallback = new ClassTest();
mCallback.onColorsChangeListener(mProps);
However if you want multiple callbacks you will need to use the Observer pattern.
Simple example:
private List<OnColorsChangeListener> mCallbacks = new ArrayList<OnColorsChangeListener>();
mCallbacks.add(new ClassTest());
mCallbacks.add(new OtherClass());
for(OnColorsChangeListener listener : mCallbacks) {
listener.onColorsChangeListener(mProps);
}
Obviously if you have the class, somewhere else you would not new it up, you would use that reference:
mCallbacks.add(mClassTest);
Observer Pattern Wikipedia
An interface is just a way to group together a bunch of related methods. Implementing this interface then requires you to implement all the methods grouped together by the interface.
The Java Tutorials has a good read on the subject:
What is an interface?
Here's a Stackoverflow thread regarding listener interfaces in android:
How to create our own Listener interface in android?
In short, you don't use the interface directly since it only specifies which methods implementing classes are supposed to implement.
I am trying to test a Fragment I've created in Android. I have complete control of the code, so I can change it as I see fit. The issue is that I'm not sure what design pattern I'm missing to make it reasonable.
I am looking for a way to mock objects in Android that are not passed as parameters. This question suggests that anything you might want to mock should be written to be passed as a parameter.
This makes sense for some situations, but I can't figure out how to get it working on Android, where some of this isn't possible. With a Fragment, for example, you're forced to let much of the heavy lifting be done in callback methods. How can I get my mocked objects into the Fragment?
For example, in this ListFragment I need to retrieve an array of things to display to the user. The things I'm displaying need to be retrieved dynamically and added to a custom adapter. It currently looks as follows:
public class MyFragment extends ListFragment {
private List<ListItem> mList;
void setListValues(List<ListItem> values) {
this.mList = values;
}
List<ListItem> getListValues() {
return this.mList;
}
#Override
public void onCreateView(LayoutInflater i, ViewGroup vg, Bundle b) {
// blah blah blah
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
this.setListValues(ListFactory.getListOfDynamicValues());
CustomAdapter adapter = new CustomAdapter(
getActivity(),
R.layout.row_layout,
this.getListValues());
this.setListAdapter(adapter);
}
}
I'm trying to do this using Mockito and Robolectric.
This is the beginning of my robolectric test case:
public class MyFragmentTest {
private MyFragment fragment;
#Before
public void setup() {
ListItem item1 = mock(ListItem.class);
ListItem item2 = mock(ListItem.class);
when(item1.getValue()).thenReturn("known value 1");
when(item2.getValue()).thenReturn("known value 2");
List<ListItem> mockList = new ArrayList<ListItem>();
mockList.add(item1);
mockList.add(item2);
MyFragment real = new MyFragment();
this.fragment = spy(real);
when(this.fragment.getValueList()).thenReturn(mockList);
startFragment();
}
}
This feels so very wrong. This section from the mockito api points out that you shouldn't have to do partial mocks like this very frequently unless you're dealing with legacy code.
Further, I'm not actually able to mock out the CustomAdapter class using this approach.
What is the right way to do this sort of thing? Am I structuring things incorrectly in my Fragment classes? I suppose I might be able to add a bunch of package-private setters, but this still doesn't feel right.
Can someone shed some light on this? I'm happy to do rewrites, I just want to know some good patterns for dealing with the state in my Fragments and how I can make them testable.
I ended up creating my own solution to this. My approach was to add another level of indirection to each my calls that create or set an object.
First, let me point out that I couldn't actually get Mockito to work reliably with Fragment or Activity objects. It was somewhat hit or miss, but especially with trying to create Mockito Spy objects, some lifecycle methods appeared to not be called. I think this is related to gotcha number 2 shown here. Perhaps this is due to the ways that Android uses reflection to recreate and instantiate activities and fragments? Note that I was NOT incorrectly holding onto the reference, as it warns of, but interacting only with the Spy, as indicated.
So, I wasn't able to mock Android objects that required lifecycle methods be invoked by the framework.
My solution was to create to more types of methods in my Activity and Fragment methods. These methods are:
getters (getX()) that return the field named X.
retrievers (retrieveX()) that do some sort of work to get an object.
creators (createMyFragment()) that create objects by calling new. Similar to the retrievers.
Getters have whatever visibility you need. Mine are usually public or private.
Retrievers and creators are package private or protected, allowing you to override them in your test packages but not making them generally available. The idea behind these methods is that you can subclass your regular objects with stub objects and inject in known values during testing. You could also just mock out those methods if Mockito mocks/spies are working for you.
Taken in toto, the test would look something like the following.
Here is the fragment from my original question, modified to use the above approach. This is in the normal project:
package org.myexample.fragments
// imports
public class MyFragment extends ListFragment {
private List<ListItem> mList;
void setListValues(List<ListItem> values) {
this.mList = values;
}
List<ListItem> getListValues() {
return this.mList;
}
#Override
public void onCreateView(LayoutInflater i, ViewGroup vg, Bundle b) {
// blah blah blah
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
this.setListValues(this.retrieveListItems());
CustomAdapter adapter = this.createCustomAdapter();
this.setListAdapter(adapter);
}
List<ListItem> retrieveListItems() {
List<Item> result = ListFactory.getListOfDynamicValues();
return result;
}
CustomAdapter createCustomAdapter() {
CustomAdapter result = new CustomAdapter(
this.getActivity();
R.layout.row_layout,
this.getListValues());
return result;
}
}
When I test this object, I want to be able to control what gets passed around. My first thought was to use a Spy, replacing the return values of retrieveListItems() and createCustomAdapter() with my known values. However, like I said above, I wasn't able to get Mockito spies to behave when working with fragments. (Especially ListFragments--I had mixed success with other types, but don't trust it.) So, we are going to subclass this object. In the test project, I have the following. Note that your method visibility in your real class must allow subclasses to override, so it needs to be package private and in the same package or protected. Note that I am overriding the retriever and creator, returning instead static variables that my tests will set.
package org.myexample.fragments
// imports
public class MyFragmentStub extends MyFragment {
public static List<ListItem> LIST = null;
public static CustomAdapter ADAPTER = null;
/**
* Resets the state for the stub object. This should be called
* in the teardown methods of your test classes using this object.
*/
public static void resetState() {
LIST = null;
ADAPTER = null;
}
#Override
List<ListItem> retrieveListItems() {
return LIST_ITEMS;
}
#Override
CustomAdapter createCustomAdapter() {
return CUSTOM_ADAPTER;
}
}
In the same package in my test project I have the actual test of the fragment. Note that while I'm using Robolectric, this should work with whatever test framework you're using. The #Before annotation becomes less useful, as you need to update your static state for individual tests.
package org.myexample.fragments
// imports
#RunWith(RobolectricTestRunner.class)
public class MyFragmentTest {
public MyFragment fragment;
public Activity activity;
#After
public void after() {
// Very important to reset the state of the object under test,
// as otherwise your tests will affect each other.
MyFragmentStub.resetState();
}
private void setupState(List<ListItem> testList, CustomAdapter adapter) {
// Set the state you want the fragment to use.
MyFragmentStub.LIST = testList;
MyFragmentStub.ADAPTER = adapter;
MyFragmentStub stub = new MyFragmentStub();
// Start and attach the fragment using Robolectric.
// This method doesn't call visible() on the activity, though so
// you'll have to do that yourself.
FragmentTestUtil.startFragment(stub);
Robolectric.ActivityController.of(stub.getActivity()).visible();
this.fragment = stub;
this.activity = stub.getActivity();
}
#Test
public void dummyTestWithKnownValues() {
// This is a test that does nothing other than show you how to use
// the stub.
// Create whatever known values you want to test with.
List<ListItem> list = new ArrayList<ListItem>();
CustomAdapter adapter = mock(CustomAdapter.class);
this.setupState(list, adapter);
// android fest assertions
assertThat(this.fragment).isNotNull();
}
}
This is definitely more verbose than using a mocking framework. However, it works even with Android's life cycle. If I'm testing an Activity, I'll also often include a static boolean BUILD_FRAGMENTS variable. If true, I'll go call through to super in the appropriate methods or return a known fragment as appropriate. In this way I'm able to inject my test objects and play nice with the Android life cycle.
I am working on an Android class that contains an ArrayList of generic objects. I am looking to fire an event in this class whenever an element of said ArrayList is modified.
In an ideal world, the ArrayList itself should be a private member, and the class would contain the public methods to add/update/delete an element and everything would be all fine and dandy.
Unfortunately, the ArrayList is exposed as a public member, so it and its elements are being modified all over the place (application). Without rewriting a boat load of code and/or going on a wild goose chase in the code, I am hoping I can find way to trigger an event when ArrayList is modified in the class containing the list. Any ideas?
You can subclass ArrayList and trigger an action (call a callback for example) after some of it's methods were invoked.
Then replace the original ArrayList in your Android class with your implementation.
P.S. Example:
public class MyArrayList<E> extends ArrayList<E> {
#Override
public boolean add(E object) {
// Do some action here
return super.add(object);
};
#Override
public void add(int index, E object) {
super.add(index, object);
// Do some action here
};
#Override
public E remove(int index) {
// Do some action here
return super.remove(index);
}
// etc...
}
Since it subclasses ArrayList you won't get any errors in your code, and everything that worked before, will work without any changes.
With a little creativity the class can be made more elegant and efficient, but the general idea is there.
Edit: Yep. Sorry, was a little hasty with those returns. Fixed, and thanks Petar