I've been practising the MVP pattern in android.
My question is related to how to design the situation where you have a fragment with a custom layout.(see the below layout)
customlayout in fragment
There are 2 cardviews in the customlayout:
- if you click on the friends cardview, a dialogfragment will be displayed showing a customadapter whose data comes from fetching the local DB
- if you click on the others cardview, a dialogfragment will be displayed showing a customadapter whose data comes from a server.
You can check the people in this adapter and if you click OK, the images of the checked people will be displayed in the cardview
I have made the fragment a view as part of an MVP construct but I got stuck.
Is it a good idea to create the customlayout as an MVP construct as well? or not just the layout, but the cardviews, too?
And if yes, then these "nested" MVPs how would they send the data(the friends & the others) back to the host fragment/presenter when I click the Save Button?
Or am I overcomplicating this simple fragment-layout architecture?
Any suggestions are appreciated
The fragment implements the below View:
public interface CreateEventContract {
interface View extends BaseView<Presenter>{
void showStartDateDateDialog();
void showStartDateTimeDialog(LocalDate selectedDate);
void showPlaceMapActivity();
void saveButtonClicked();
boolean isActive();
}
interface Presenter extends BasePresenter {
void startDateDateDialog();
void startDateTimeDialog(LocalDate selectedDate);
void place();
void saveEvent();
}
}
and the CustomLayout:
customLayout gist
In that situation, I think one could be guided by the tablet MVP example on GitHub, the Android Architecture Blueprints.
Transferred to your case, your structure could be something like this
The views are reporting (e.g who's been checked) to a common Presenter, who is manipulating the views through their particular Presenter.
Related
I'm new to Android programming, and still teaching myself to code.
Currently I'm teaching myself about GridViews and still coding that project with tutorials so I have nothing to show right now, but the basic idea is the following...
If I have images of groceries in GridView in the first activity and when you click an image you will be able to open a new activity with a larger image and you could input the number how many you things you need, like 5 apples or whatever.
All of that is more or less clear to me how to do.
But how would I send the number and image to a new (third) activity with a ListView that would list all the items you need to buy at the grocery store? How would I be able to fill the list only with items after you enter the number on the previous activity with the large picture and click an "OK" or "Add" button or whatever and not list absolutely everything?
Thanks!
It's difficult at first, but you can use an SQLiteDatabase to store the data.
It's not a quick solution for you, but definitely worth learning about if you're serious to learn android. Here's a link to the official stuff:
https://developer.android.com/reference/android/database/sqlite/SQLiteDatabase.html
I personally used this tutorial:
http://www.androidwarriors.com/2016/02/android-sqlite-database-tutorial-sqlite.html?m=1
Sharing some data between multiple activities or fragments is a very common situation. One way around it is implementing a Singleton Pattern.
In your case you can design some kind of data structure for your purpose and manage it inside shared singleton class. For example something like this:
public class ShoppingListManager {
private static ShoppingListManager instance = new ShoppingListManager();
private List<ShoppingItem> shoppingList;
public static ShoppingListManager getInstance() {
return instance;
}
public List<ShoppingItem> getShoppingList() {
return shoppingList;
}
public void addShoppingItem(ShoppingItem item) {
this.shoppingList.add(item);
}
...
// Make the constructor private so that this class cannot be instantiated
private ShoppingListManager(){
shoppingList = new ArrayList<String>();
}
}
Then you can access your data anywhere in your code and manage shared data in any way you'd like.
ShoppingListManager.getInstance().getShoppingList();
// You can add items in any activity
ShoppingListManager.getInstance().addShoppingItem(item);
One point to remember never store context in singleton classes as it will lead to memory leaks.
I have been looking for this answer a while, and i haven't found any good solution which would help me getting started in creating this. This is what i would like to do. Like we have view types in lists and we can show different layouts on different position in lists using those view types, i would like to do that also with viewpager. I'm showing some images from server in viewpager, so user can swipe them, but i would like to show user between those images on every 5 image ad. How can i accomplish that?
This is how my viewpager adapter looks:
private class JokesImagesAdapter extends FragmentPagerAdapter {
public JokesImagesAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
JokePageFragment fragment = new JokePageFragment();
fragment.setArguments(jokes.get(position).toBundle());
return fragment;
}
#Override
public int getCount() {
return jokes.size();
}
}
And i guess that probably i need to create one more fragment and call it here with implementation of ads.
What kind of ads you want to show in your app - Interstitial or Native ad?
If you want to just show an interstitial ad on every 5 swipes - just attach an OnPageChangeListener to your ViewPager and count the swipes.
If you want to show a native ad, you have to create a new fragment (as you thought) which will be showing the ad. You have to count and return the ad fragment in the getItem() method of your adapter. Another way to handle this is to use one fragment which will be notified whether to show or not an ad view or a normal view.
What I believe is that you should modify your jokes model a little, which could accept objects instead of just images(and your custom parameters) and then cast the object to the required datatype and then while populating jokes, you should add the ad object every 5th position, that would do the work.
I want to implement the sticky gridview in my application but the problem is that my header of the gridview is also move when I scroll the gridview, So could you please help me to sort out from these problem
You can check out StickyGridHeaders is library that provides a GridView that shows items in sections with headers. By default the section headers stick to the top like the People app in Android 4.x but this can be turned off.
StickyGridHeaders also automatically sizes its rows to the largest item in the row.
Another is AStickyHeader for adding Sticky Headers to ListView or GridView.
Hope this will help you.
TonicArtos's repo is great, but I found it hard to integrate it with my app. Also, I couldn't get the example code to run so I decided to fork it and improve it a little bit.
The only thing that was added was 2 classes that makes the creation of the adapter a lot easier IMO.
The first of those classes is:
public abstract class UtilAdapter<T, VH extends BaseViewHolder> extends BaseAdapter {
//methods to add and remove elements & viewholder implementation
}
This class provides some methods to add and remove elements from an internal list it has (kind of what ArrayAdapter does). It also implements the viewholder pattern for you so you just have to implement a few abstract methods.
The second class is:
public abstract class StickyGridAdapter<T, VH extends BaseViewHolder, HVH extends BaseViewHolder> extends UtilAdapter<T, VH> implements StickyGridHeadersSimpleAdapter {
//viewholder imlpementation for the header view (also has abstract methods)
}
This class implements StickyGridHeadersSimpleAdapter (TonicArtos's interface). It also implements the viewholder pattern for the header views, so extending this class makes you implement a few methods that return ViewHolder classes and other methods that populate said viewholders.
To implement a sticky header grid you just have to extend StickyGridAdapter, use StickyGridHeadersGridView instead of GridView in your layout and set the adapter as usual.
Here is a link to the repo (which is a fork of TonicArto's):
https://github.com/OneCodeLabs/StickyGridHeaders
I also wrote some example code using my classes. I hope it can help you
Target MvvmCross, Android
Objective: A screen (ViewModel/View) where the user can select an animal group (Amphibians, Birds, Fish, Invertebrates, Mammals, Reptiles). When a group has been selected, a Fragment Views will will display information for that animal group. The fields and layout differ per animal group (e.g. fish don't have wings).
Although for this question I have chosen for animal group (which is pretty static), want the list animal groups to be flexible.
Simplified app structure:
MyApp.Core
ViewModels
MainViewModel
IAnimalGroupViewModel
AmphibiansViewModel
BirdsBViewModel
FishViewModel
MyApp.Droid
Layout
MainView
AmphibiansFragment
BirdsFragment
FishFragment
Views
MainView
AmphibiansFragment
BirdsFragment
FishFragment
The MainView.axml layout file will contain (a placeholder for) the fragment of the displayed animal group.
In WPF or WP8 app I could make use of a ContentPresenter and a Style to automatically display the selected ViewModel with its View.
How could I achieve something like that in Droid?
I could use a Switch/Case in the MainView.cs that sets the Fragment according to the type of the selected ViewGroup. But that means I have to modify the MainView every time I add a new View.
Any suggestions/ideas?
Currently MvvmCross doesn't provide any kind of automatic navigation mechanism for Fragments in the same way that it does for Activities.
However, within your use case, if you wanted to use a navigation approach, then you could automatically build a similar type of automated lookup/navigation mechanism.
To do this, the easiest developer root would probably be to use reflection to find a lookup dictionary for all the fragments
var fragments = from type in this.GetType().Assembly.GetTypes()
where typeof(IAnimalGroupView)..sAssignableFrom(type)
where type.Name.EndsWith("Fragment")
select type;
var lookup = fragments.ToDictionary(
x => x.Name.Substring(0, x.Name.Length - "Fragment".Length)
+ "ViewModel",
x => x);
With this in place, you could then create the fragments when they are needed - e.g.
assuming that you convert the Selection event via an ICommand on the ViewModel into a ShowViewModel<TViewModel> call
and assuming that you have a Custom Mvx presenter which intercepts these ShowViewModel requests and passes them to the activity (similar to the Fragment sample) - e.g.
public class CustomPresenter
: MvxAndroidViewPresenter
{
// how this gets set/cleared is up to you - possibly from `OnResume`/`OnPause` calls within your activities.
public IAnimalHostActivity AnimalHost { get; set; }
public override void Show(MvxViewModelRequest request)
{
if (AnimalHost != null && AnimalHost.Show(request))
return;
base.Show(request);
}
}
then your activity could implement Show using something like:
if (!lookup.ContainsKey(request.ViewModelType.Name))
return false;
var fragmentType = lookup[request.ViewModelType.Name];
var fragment = (IMvxFragmentView)Activator.Create(fragmentType);
fragment.LoadViewModelFrom(request);
var t = SupportFragmentManager.BeginTransaction();
t.Replace(Resource.Id.my_selected_fragment_holder, fragment);
t.Commit();
return true;
Notes:
if you aren't using ShowViewModel here then obviously this same approach could be adjusted... but this answer had to propose something...
in a larger multipage app, you would probably look to make this IAnimalHostActivity mechanism much more generic and use it in several places.
I'm trying to do something very simple. I have 2 tabs, one showing information about the breed of a dog and the other is showing a list of reviews that people have written describing the breed. I would like to include the number of reviews that were written in the Tab as well so it would look like so:
Breed Info | Reviews(19)
The issue is that I need to download said review data first in order to see the number of reviews there is on the tab.
So what I thought of as a solution was to add the tab first in my BreedProfile.java (ShelockActivity)
ActionBar.Tab reviewTab= ab.newTab();
reviewTab.setText("Reviews");
mTabsAdapter.addTab(reviewTab, DogReviewFragment.class, null);
Then in my BreedProfileReviewFragment.java I would download the reviews then update the reviewTab text by doing so:
getActivity().getActionBar().getTabAt(1).setText("Reviews 10");
However, the above method does not exist according to the LogCat.
03-05 18:15:26.460: E/AndroidRuntime(1286): FATAL EXCEPTION: main
03-05 18:15:26.460: E/AndroidRuntime(1286): java.lang.NoSuchMethodError: android.support.v4.app.FragmentActivity.getActionBar
So my question is, is it possible to access the TAB from the FRAGMENT to change the TEXT property of the TAB after it is added? If it is, how can I achieve that?
NOTES:
I cannot download the reviews together with the breed information because the API's are separate.
The BreedProfile.java Originates from a list of Breeds in a ListActivity BreedList.java.
You can implement an Interface. so you can run the code at the parent activity of the fragment.
create your interface in your fragment like below:.
public interface OnQuestionSelectedListener {
void onQuestionSelected(int Position, boolean isFirstTime);
}
Implement it at your parent activity side like below:
public class YourParentActivity extends Activity implements YourFragment.OnQuestionSelectedListener{
#Override
public void onQuestionSelected(int position, boolean isFirstTime) {
// your code.
}
}
Call it from your fragment like below:
((YourParentActivityName)getActivity()).onQuestionSelected(position, true);
(You can make changes in the code as per your need)
It is a very good practice to transfer all your logic of fragment to its parent because what I believe is fragment use for your UI part and Interface provide us a good way to transfer the fragment message to the parent.Do all the activity at parent and transfer the result to corresponding fragment.
Hope this will help.