I'm implementing a list which needs to be displayed by an activity and modified (add items, remove items, sort) by the user. Currently I have two different classes - the activity class and the list class which has all the operations on the list. However, the activity class is going to need access to the list in order to adapt and display it, and it seems kind of clumsy to either duplicate the list for the activity or make the list public. I get the feeling I might not be understanding what activities are correctly - should my two classes really be one single class? I assumed activities were mostly for UI, not for modifying the underlying datastructure.
Activities are the main building blocks of Android, all the different screens that you see in your Application are Activities. You should understand that not all Java Classes used in your Android App are Activities (only those Java Classes that extends Activity are Activities).
The Java Classes that are not Activity (used in your code) can be simply plain Data Models, Custom Adapters, Custom Views, Database Handlers, Services, and so on.
All these Java files are used separately from the Activity Class to provide Modularity and to avoid creating a Mess and deficiency by implementing all the Functionality in a Single Activity Class.
You use the instances of these other Java Classes (or use them statically) in your Activity Class.
For Displaying a Simple List, you can use ListView widget, and you don't really need a separate class for it's implementation. Likewise, if you are preparing to implement a ListView with functionality such as Delete, Add, Update, etc. Then Custom ListView is the alternative option that you can use.
You cannot implement a Custom List View in a single Activity Class, you will be needing a Custom Adapter Class, a Custom Data Model Class and other related classes for it's implementation.
Here is a list of some useful tutorials for implementing Simple and Custom ListViews:
Vogella's ListView Tut
The Open Tutorials
Android Example 1
Android Example 2
I hope this helps.
I'm implementing a list which needs to be displayed by an activity and modified (add items, remove items, sort) by the user.
You can do the simple operations defined by the List<T> interface like add, remove, etc. You can write a custom Comparator<T> to perform sort operations. Then use the Collections.sort() method to do your work.
Currently I have two different classes - the activity class and the list class which has all the operations on the list.
It depends. I generally prefer to make a singleton instance of the list and let my activity modify it on callbacks from ListView. There is nothing clumsy about letting your Activity handle the addition or removal from list.
However, the activity class is going to need access to the list in order to adapt and display it, and it seems kind of clumsy to either duplicate the list for the activity or make the list public.
Like I said, look up what a Singleton Instance is. Share your list across multiple activities by creating a class that has the list in it. Declare the list public. That way, you share the list and do not duplicate it. Remember: if you duplicate the data multiple times. keeping them in sync is going to be a tough nut to crack.
Think about it like that. Your oncreate is called once. If you need things done on the list, they will most probably be on your onItemClick, onItemLongClick kinda events. And when that happens, you should call a AsyncTask, coded in your same activity, so that the onPostExecute can modify its UI elements and the list. Some example below.
Note, the code below has been reduced bigtime, so excuse syntax
package com.taxeetaregistration;
public class Bookings extends ListActivity implements OnClickListener, OnItemClickListener {
private static LayoutInflater inflater = null;
private LinkedList<BookingRecord> bookingRecord;
private ListView customerList;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.bookings);
Log.d("Taxeeta", "Entered BookingExperience");
bookingRecord = new LinkedList<BookingRecord>();
customerList = (ListView) findViewById(android.R.id.list);
customerList.setAdapter(new CustomerList());
customerList.setOnItemClickListener(this);
getBookings = new GetBookings();
getBookings.execute();
}
public class CustomerList extends BaseAdapter implements OnClickListener {
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null || convertView.getTag() == null) {
convertView = inflater.inflate(R.layout.bookingresponse_row, null);
final CustomerViewHolder viewHolder = new CustomerViewHolder();
viewHolder.customerRow = (LinearLayout) convertView.findViewById(R.id.customerRow);
viewHolder.customerName = (TextView) convertView.findViewById(R.id.customerName);
viewHolder.customerPhoneNumber = (TextView) convertView
.findViewById(R.id.customerPhoneNumber);
convertView.setTag(viewHolder);
}
// Setting all values in listview
String temp = bookingRecord.get(position).customer.getFullName();
((CustomerViewHolder) (convertView.getTag())).customerName.setText(temp);
temp = bookingRecord.get(position).customer.getPhoneNumber();
((CustomerViewHolder) (convertView.getTag())).customerPhoneNumber.setText(temp);
return convertView;
}
public class GetBookings extends AsyncTask<Object, Integer, Object> {
#Override
protected Object doInBackground(Object... params) {
connectToServer();
//Do all network related work here, and update
publishProgress(j);
}
}
return null;
}
#Override
public void onPostExecute(Object result) {
super.onPostExecute(result);
if (bookingRecord != null && bookingRecord.size() > 0) {
busy.setVisibility(View.GONE);
((BaseAdapter) customerList.getAdapter()).notifyDataSetChanged();
} else {
progressBarUpper.setVisibility(View.GONE);
Log.d("Taxeeta", "No cabbies found");
}
}
#Override
protected void onProgressUpdate(Integer... i) {
super.onProgressUpdate(i);
boolean found = false;
customersFound.setText("" + totalCabbiesSubscribed);
BookingRecord newRecord = new BookingRecord();
newRecord.customerJourney = customerJourney;
newRecord.customer = customer;
bookingRecord.addLast(newRecord);
customersConfirmed.setText("" + bookingRecord.size());
}
}
private class CustomerViewHolder {
public LinearLayout customerRow;
public TextView customerName;
public TextView customerPhoneNumber;
public TextView customerFrom, customerTo;
public ListView cabbieList;
public float distanceFromCustomer = -1.0f;
}
public class BookingRecord {
public BookingRecord() {
cabbies = new ArrayList<CabbieDetails>();
}
public IJourneyDetails customerJourney;
public IUserDetails customer;
public SearchResultsConcrete cabbieList;
public ArrayList<CabbieDetails> cabbies;
}
}
Related
I have an activity that shows some of its content based on a users role.
For example home activity shows add/delete views for manager and show add/delete/edit views for senior manager and I am currently using MVP pattern and I need best design patterns for the presentation layer in my case as I have more than 6 user types and may increase.
I just draw my login through coding. Hopefully, It may help you.
Create a sperate Java class and declare all the UI components with
public and static keyword.
public class UI {
public static TextView textView1,textView2;
public static Button add,delete,edit,commit;
}
In your MainActivity initialize the UI Components which declared in
separate java class.
public class MainActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
UI.textView1 = (TextView) findViewById(R.id.tv1);
//.. Intialize one by one there....
}
}
In your presenter Class make a method named UserType(String user)
and start comparing user and set Visibility to UI Components
according to the user.
public void UserType(String user){
if (user.contentEquals("admin")){
UI.add.setVisibility(View.VISIBLE);
UI.delete.setVisibility(View.VISIBLE);
UI.edit.setVisibility(View.VISIBLE);
UI.commit.setVisibility(View.VISIBLE);
}else if (user.contentEquals("user")){
UI.add.setVisibility(View.VISIBLE);
UI.delete.setVisibility(View.VISIBLE);
UI.edit.setVisibility(View.GONE);
UI.commit.setVisibility(View.GONE);
}
}
In my Android Application I've some objects which represent different kinds of operations.
public class OperacionDivisa implements IOperacion {
public class OperacionLargo implements IOperacion {
public class OperacionMedio implements IOperacion {
public class OperacionOpciones implements IOperacion {
Each kind of operation implements IOperation interface so I can make an ArrayList of IOperations and store all operations in a single ArrayList.
Now I'd like to do the inverse process. I want to get the arraylist of operations from Firebase (which has already been achieved) and I'd like to show the operations in a ListView
I created a custom adapter as follows:
public class ListViewAdapterOperaciones extends ArrayAdapter<IOperacion>
The issue is that I need to cast each object to its original class to show in a textview different attributes. So this is not useful.
IOperacion operacion = (IOperacion) getItem(position);
So, for each object I'd like to show some data in the listView but I haven't been able to figure out how to do this. Any help would be appreciated.
Thanks in advance.
Use an if statement (or similar) to check instanceof, then use the objects as the subclass.
if (operacion instanceof OperacionLargo) {
// Large operation
} else if (operacion instanceof OperacionDivisa) {
// Other operation
}
So I have an Activity. The Activity hosts a ViewPager with tabs, each tab holding a Fragment in it. The Fragments themselves have a RecyclerView each. I need to communicate changes from the RecyclerView's adapter to the activity.
Currently, I am using the listener pattern and communicating using interface between each of the components. i.e I have an interface between the RecyclerView's adapter and the Fragment holding it. Then an interface from the Fragment to the ViewPager's FragmentStatePagerAdapter which is creating all the Fragments. And 1 more interface between the ViewPager's adapter and the Activity hosting the ViewPager. I feel that there are too many interfaces for all the components because of how they are structured.
Currently I am not facing issues as such but I think the listener pattern is acting like an anti-pattern due to all the nested components. Instead of creating independent components I think the hierarchy will make it difficult for making code changes in future.
Am I doing it correctly or is there a better way to do it? Is this a case where I should use an Event Bus or Observer Pattern (If yes can you point me to some examples where someone overcame a similar problems using it)?
NOTE : If it matters, I need it to maintain a global object in the activity, something like a shopping cart where I can add or remove items and these items are present in RecyclerView's adapter from where I can add it to the cart and also increment or decrement the count for a particular item. The ViewPager and Tabs help segregate these items in various categories.
Edit 1 : Some code trying out #LucaNicoletti's approach -
I have skipped one level that is the level with the ViewPager's FragmentStatePagerAdapter. I guess that should not matter and stripped of some other code to keep it small.
MainActivity:
public class MainActivity extends AppCompatActivity implements View.OnClickListener, FoodAdapter.OnFoodItemCountChangeListener {
#Override
public void onFoodItemDecreased(FoodItemModel foodItemModel, int count) {
Log.d("Test", "Dec");
}
#Override
public void onFoodItemIncreased(FoodItemModel foodItemModel, int count) {
Log.d("Test", "Inc");
}
// Other methods here
}
Fragment hosting the Adapter:
public class FoodCategoryListFragment extends Fragment implements FoodAdapter.OnFoodItemCountChangeListener {
// Other boring variables like recyclerview and layout managers
FoodAdapter foodAdapter;
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
// Other boring intializations for recyclerview and stuff
// I set the click listener here directly on the adapter instance
// I don't have this adapter instance in my activity
foodAdapter.setOnFoodItemClickListener(this);
rvFoodList.setAdapter(foodAdapter);
}
}
The adapter class at the lowest level:
public class FoodAdapter extends RecyclerView.Adapter<FoodAdapter.FoodViewHolder> {
private OnFoodItemCountChangeListener onFoodItemCountChangeListener;
private List<FoodItemModel> foodItems;
// The interface
public interface OnFoodItemCountChangeListener {
void onFoodItemIncreased(FoodItemModel foodItemModel, int count);
void onFoodItemDecreased(FoodItemModel foodItemModel, int count);
}
// This is called from the fragment since I don't have the adapter instance
// in my activty
public void setOnFoodItemClickListener(OnFoodItemCountChangeListener onFoodItemCountChangeListener) {
this.onFoodItemCountChangeListener = onFoodItemCountChangeListener;
}
// Other boring adapter stuff here
#Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.bMinus:
onFoodItemCountChangeListener.onFoodItemDecreased(foodItems.get(getAdapterPosition()),
Integer.parseInt(etCounter.getText().toString()));
}
break;
case R.id.bPlus:
onFoodItemCountChangeListener.onFoodItemIncreased(foodItems.get(getAdapterPosition()),
Integer.parseInt(etCounter.getText().toString()));
}
break;
}
}
}
my comments were:
what you should/could do it's to have a global data repo which holds the shopping cart and listeners associated with changes to it. Like a singleton, like ShoppingCart.getInstance().addListener(this); and ShoppingCart.getInstance().addItem(new Item(id));
and
Yes. That's what I'm suggesting. Do not forget that this Singleton can never ever holds Context or Activity because u don't want to leak memory, so always call removeListener. On my opinion it would reduce dependency as all your view controllers only interact with the data model
and I'll add some code to exemplify as a proper answer.
Below is a very crude, typed by heart code, but it should give an idea. All the UI elements are only tied to the data, and not to each other.
Similar stuff could be implemented with libraries that provide observable pattern out of the box for data-only objects.
public class ShoppingCart {
private ShoppingCart single;
private static void init(){
.. init single if not null
}
private List<Item> items = new ArrayList<>();
public int numberOfItems;
public long totalPrice;
private static void addItem(Item item){
init()
single.items.add(item);
single.numberOfItems++;
single.totalPrice+=item.price;
dispatchChange();
}
private static void removeItem(Item item){
init();
single.numberOfItems--;
single.totalPrice-=item.price;
dispatchChange();
single.items.remove(item);
}
private void dispatchChange(){
// TODO: write real loop here
for(single.listeners) listener.onCartChanged(single.cart);
}
public interface Listener {
void onCartChanged(ShoppingCart cart);
}
private List<Listener> listeners = new ArrayList<>();
// TODO: addListener and removeListener code
public static class Item {
String id;
String name;
long price;
}
}
To communicate between components (Activity, Fragment) you have to use an event bus.
In android, you could choose between:
RxJava
Otto
Green Robot EventBus
A blog to explain this.
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.
My MainActivity calls another Activity A which needs to access some members of MainActivity.
What is the best way to send a reference to Main Activity (or its context) to Activity A without resorting to complicated methods like parcelables etc?
There are some heavyweight android wrestling matches here but I am not sure that it is relevant to my problem.
details
I have Alert and Alerted objects in a one-to-many relationship (Alerted represents the various times an Alert was rung).
AlertsListActivity extends ListActivity which displays a list of Alert objects from a SQLite database table (primary key: alertId). It has an AlertsListAdapter.
AlertedsListActivity has a ListFragment which displays a list of Alerted objects from Alerted table (foreign key is alertId from Alert table).
It has an AlertedsListAdapter.
AlertsListActivity needs to call AlertedsListActivity to display the list of Alerted objects. I used startActivityForResult().
Inside AlertedsListAdapter
public View getView(int position, View convertView, ViewGroup parent) {
final Alert alertItem = (Alert) mainActivity.alertsListAdapter.getItem(position);
final Alerted alertedItem = (Alerted) getItem(position);
...
I do need the Alert objects also, in order to display some identifying information from them with each Alerted list item. Hence I need the reference to mainActivity.alertsListAdapter
How can AlertedsListActivity access AlertsListActivity?
Update: Since I did not get any solutions, I implemented a workaround. The data that I needed to access from Main Activity, I modified. So the Alert object was made a parcelable, and the SQLOpenHelper was made a singleton.
This allows the data to be accessed from Activity A.
Here's the simple, common way to do it:
singletons typically have variables like the below example, "useThisContext" or "mainFeedIsHere".
public class Cloud
{
private static Cloud ourInstance = new Cloud();
private Cloud() { Utils.Log("cloud singleton launched"); }
public synchronized static Cloud getInstance()
{
return ourInstance;
}
/////////////////////////////////////////////////
public Context useThisContext;
another example ...
public class Feed
{
private static Feed ourInstance = new Feed();
private Feed()
{
Utils.Log("feed singleton launched");
freshestPostsForDisplay = new ArrayList<ParseObject>();
}
public synchronized static Feed getInstance()
{
return ourInstance;
}
public List<ParseObject> freshestPosts;
public MainActivity mainFeedIsHere;
Quite simply when everything launches (or when it changes), those "things" need to set those variables in the singleton. In other words, those things "tell the singleton, where they are." It's that simple.
So, in the MainActivity perhaps, in onCreate, it might say something like...
CLOUD.useThisContext = this;
FEED.mainFeedIsHere = this;
Then for example inside Feed.java you may have say
mainFeedIsHere.feedReload();
It goes without saying you have to check that they are not null (but how else could it be?) and you have to keep them up-to-date as it were. (i.e., for whatever reason you may want to change "useThisContext" -- again how else could it be?)
{Sometimes you'll have one "centralised" singleton .. perhaps "State" .. to sort of combine all these together - so that anyone can "get to" any of those "exposed" things as needed. This is, really, how game engines go; so that you can say more or less SoundEffects.Booms() or Tanks.Faster() or AI.FindVillains() at any time anywhere.}
Cheers!
Since I did not get any solutions, I implemented a workaround. The data that I needed to access from Main Activity, I modified. So the Alert object was made a parcelable, and the SQLOpenHelper was made a singleton.
This allows the data to be accessed from Activity A.