Skip to Content

Customize the Wizard Generated Application

Customize a wizard-generated application and learn how to use Fiori object cells, search UI, and the collection view.
You will learn
  • How to customize the values displayed in an object cell
  • How to modify the navigation between screens
  • How to change menu options
  • How to add a Fiori search UI enabling the filtering of object cells on a list screen
  • How to add a collection view showing the top products
flyingfish162Bruce MengMarch 22, 2022
Created by
danielva
October 14, 2018
Contributors
danielva
flyingfish162

Prerequisites

  • Step 1
    1. Run the previously created project.

    2. Tap the Products entity.

      Entities screen

      Notice that it displays the category name rather than the product name.

      Original Products Screen

      The category name is displayed (rather than the product name) because the app was generated from the OData service’s metadata, which does not indicate which of the many fields from the product entity to display. When creating the sample user interface, the SDK wizard uses the first property found as the value to display. To view the complete metadata document, open the res/raw/com_sap_edm_sampleservice_v2.xml file.

      Product metadata

      Each product is displayed in an object cell, which is one of the Fiori UI for Android controls.

      object cell

      As seen above, an object cell is used to display information about an entity.

  • Step 2

    In this section, you will configure the object cell to display a product’s name, category, description, and price.

    1. In Android Studio, on Windows, press Ctrl+N, or, on a Mac, press command+O, and type ProductsListFragment, to open ProductsListFragment.java.

    2. On Windows, press Ctrl+F12, or, on a Mac, press command+F12, and type populateObjectCell, to move to the populateObjectCell method. Change the parameter in the first line of the method in getDataValue from Product.category to Product.name. This will cause the product name to be shown as the headline value of the object cell:

      Java
      Copy
      DataValue dataValue = productEntity.getDataValue(Product.name);
      
    3. At the end of the populateObjectCell method, find the lines that set the subheadline, footnote, and icon, as shown below.

      Java
      Copy
      viewHolder.objectCell.setSubheadline("Subheadline goes here");
      viewHolder.objectCell.setFootnote("Footnote goes here");
      if (masterPropertyValue == null || masterPropertyValue.isEmpty()) {
          viewHolder.objectCell.setIcon("?", 0);
      } else {
          viewHolder.objectCell.setIcon(masterPropertyValue.substring(0,1), 0);
      }
      viewHolder.objectCell.setIcon(R.drawable.default_dot, 1, R.string.attachment_item_content_desc);
      viewHolder.objectCell.setIcon("!", 2);
      
    4. Replace these lines with the following code, which will display category, description, and price.

      Java
      Copy
      dataValue = productEntity.getDataValue(Product.category);
      
      if (dataValue != null) {
          viewHolder.objectCell.setSubheadline(dataValue.toString());
      }
      dataValue = productEntity.getDataValue(Product.shortDescription);
      if (dataValue != null) {
          viewHolder.objectCell.setFootnote(dataValue.toString());
      }
      
      dataValue = productEntity.getDataValue(Product.price);
      if (dataValue != null) {
          viewHolder.objectCell.setStatusWidth(200);
          viewHolder.objectCell.setStatus("$ " + dataValue.toString(), 1);
      }
      
    5. On Windows press Ctrl+F12, or, on a Mac, press command+F12 and type onViewStateRestored, to move to the onViewStateRestored method.

    6. After the if (recyclerView == null) line, paste the following code, which adds a divider between product items.

      Java
      Copy
      LinearLayoutManager linearLayoutManager = new LinearLayoutManager(currentActivity);
      DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(recyclerView.getContext(), linearLayoutManager.getOrientation());
      recyclerView.addItemDecoration(dividerItemDecoration);
      recyclerView.setLayoutManager(linearLayoutManager);
      

      If classes LinearLayoutManager and DividerItemDecoration appear red, this indicates that Android Studio could not locate the classes. Select each class and on Windows press Alt+Enter, or, on a Mac, press option+return to make use of Android Studio quick fix to add the missing imports.

      An alternate option is to enable the below setting. (Windows: Settings, Mac: Android Studio > Preferences…)

      Add unambiguous imports on the fly
    7. On Windows, press Ctrl+N, or, on a Mac, press command+O and type Repository, to open Repository.java.

    8. On Windows, press Ctrl+F12, or, on a Mac, press command+F12 and type initialRead, to move to the initialRead method.

    9. Below the line that calls the orderBy method of dataQuery, add the following to specify that the sort order be by category and then by name for products.

      Java
      Copy
      if (entitySet.getEntityType() == ESPMContainerMetadata.EntityTypes.product) {
          dataQuery.thenBy(Product.name, SortOrder.DESCENDING);
      }
      

      After the change the code should appear as shown below.

      Java
      Copy
      if (orderByProperty != null) {
          dataQuery = dataQuery.orderBy(orderByProperty, SortOrder.ASCENDING);
          if (entitySet.getEntityType() == ESPMContainerMetadata.EntityTypes.product) {
              dataQuery.thenBy(Product.name, SortOrder.DESCENDING);
          }
      }
      
    10. Re-run (quit first) the app and notice that the Products screen has been formatted to show the product’s name, category, description, and price and the entries are now sorted by category and then name.

      Nicely formatted product list

    Which properties of the object cell were set in this section?

  • Step 3

    Examine the ProductCategories screen.

    Original product categories screen

    In this section, you will update the screen’s title, configure the object cell to show the category name, main category name, add the number of products in a category, and add a separator decoration between cells.

    1. Press Shift twice and type strings.xml to open res/values/strings.xml.

    2. Add the following entry:

      XML
      Copy
      <string name="product_categories_title">Product Categories</string>
      
    3. On Windows, press Ctrl+N, or, on a Mac, press command+O, and type ProductCategoriesListFragment, to open ProductCategoriesListFragment.java.

    4. On Windows, press Ctrl+F12, or, on a Mac, press command+F12, and type onViewStateRestored, to move to the onViewStateRestored method, find the currentActivity.setTitle(activityTitle) line.

    5. On Windows, press Ctrl+/, or, on a Mac, press command+/, to comment out the line.

    6. Add the following line right after the line to set the screen’s title:

      Java
      Copy
      currentActivity.setTitle(getResources().getString(R.string.product_categories_title));
      
    7. Still in this method, after the if (recyclerView == null) line, paste the following code that adds a divider between categories:

      Java
      Copy
      LinearLayoutManager linearLayoutManager = new LinearLayoutManager(currentActivity);
      DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(recyclerView.getContext(), linearLayoutManager.getOrientation());
      recyclerView.addItemDecoration(dividerItemDecoration);
      recyclerView.setLayoutManager(linearLayoutManager);
      
    8. On Windows, press Ctrl+F12, or, on a Mac, press command+F12, and type populateObjectCell to move to the populateObjectCell method.

    9. At the end of the method, find the following lines that set the subheadline, footnote, and icon.

      Java
      Copy
      viewHolder.objectCell.setSubheadline("Subheadline goes here");
      viewHolder.objectCell.setFootnote("Footnote goes here");
      if (masterPropertyValue == null || masterPropertyValue.isEmpty()) {
          viewHolder.objectCell.setIcon("?", 0);
      } else {
          viewHolder.objectCell.setIcon(masterPropertyValue.substring(0, 1), 0);
      }
      viewHolder.objectCell.setIcon(R.drawable.default_dot, 1, R.string.attachment_item_content_desc);
      viewHolder.objectCell.setIcon("!", 2);
      
    10. Replace these lines with the following, to display the main category instead, hide the footnote, and show the number of products per category.

      Java
      Copy
      dataValue = productCategoryEntity.getDataValue(ProductCategory.mainCategoryName);
      if (dataValue != null) {
          viewHolder.objectCell.setSubheadline(dataValue.toString());
      }
      
      viewHolder.objectCell.setLines(2);  //Not using footnote
      
      dataValue = productCategoryEntity.getDataValue(ProductCategory.numberOfProducts);
      if (dataValue != null) {
          viewHolder.objectCell.setStatusWidth(220);
          viewHolder.objectCell.setStatus(dataValue.toString() + " Products", 1);
      }
      
    11. Run the app again and notice that the title, subheadline, and status are now displayed and the icon and footnote are no longer shown.

      Modified ProductCategories Screen
  • Step 4

    In this section, you will modify the app to initially show the Product Categories screen when opened. Selecting a category will navigate to a Products screen for the selected category. The floating action button on the Categories screen will be removed.

    1. On Windows, press Ctrl+N, or, on a Mac, press command+O, and type MainBusinessActivity, to open MainBusinessActivity.java.

    2. On Windows, press Ctrl+F12, or, on a Mac, press command+F12, and type startEntitySetListActivity, to move to the startEntitySetListActivity method.

    3. Add the following line below the other Intent declaration:

      Java
      Copy
      Intent pcIntent = new Intent(this, ProductCategoriesActivity.class);
      
    4. After the call to startActivity(intent), add the following line:

      Java
      Copy
      startActivity(pcIntent);
      

      This will cause the Product Categories screen to be the first screen seen when opening the app, but because the EntityList screen is opened first, it can be navigated to by pressing the Back button. The EntityList screen contains the Settings menu so, to simplify things, this screen is still displayed.

    5. On Windows, press Ctrl+N, or, on a Mac, press command+O, and type ProductCategoriesListFragment, to open ProductCategoriesListFragment.java.

    6. On Windows, press Ctrl+F12, or, on a Mac, press command+F12, and type onViewStateRestored, to move to the onViewStateRestored method.

    7. Find the following code:

      Java
      Copy
      if (navigationPropertyName != null && parentEntityData != null) {
          floatButton.hide();
      } else {
          floatButton.setOnClickListener((v) -> {
              listener.onFragmentStateChange(UIConstants.EVENT_CREATE_NEW_ITEM, null);
          });
      }
      
    8. Replace it with the following code:

      Java
      Copy
      floatButton.hide();
      
    9. On Windows, press Ctrl+F12, or, on a Mac, press command+F12, and type onCreateOptionsMenu, to move to the onCreateOptionsMenu method.

    10. Add the following line below the inflater.inflate call, which will remove the Home menu from the Product Categories screen, which is now the home screen of the app.

      Java
      Copy
      menu.removeItem(R.id.menu_home);
      
    11. On Windows, press Ctrl+F12, or, on a Mac, press command+F12, and type setOnClickListener, to move to the setOnClickListener method.

    12. Replace the code with the following, which will enable the navigation from the Category list screen to the Product list screen.

      Java
      Copy
      holder.view.setOnClickListener(view -> {
          Intent productsIntent = new Intent(currentActivity, ProductsActivity.class);
          productsIntent.putExtra("category", productCategoryEntity.getCategoryName());
          view.getContext().startActivity(productsIntent);
      });
      
    13. On Windows, press Ctrl+N, or, on a Mac, press command+O, and type ProductsListFragment, to open ProductsListFragment.java.

    14. On Windows, press Ctrl+F, or, on a Mac, press command+F, and search for adapter.setItems(products). Replace that line with the following code, which will filter the products list to only show products for a selected category.

      Java
      Copy
      String category = currentActivity.getIntent().getStringExtra("category");
      if (category != null) {
          List<Product> matchingProducts = new ArrayList<>();
          for (Product product : products) {
              if (product.getCategory() != null && product.getCategory().equals(category)) {
                  matchingProducts.add(product);
              }
          }
          adapter.setItems(matchingProducts);
      } else {
          adapter.setItems(products);
      }
      
    15. Run the app again and notice that the Product Categories screen is now the first screen shown, that the Home menu is no longer shown, and that selecting a category shows the products list screen, which now displays only products for the selected category.

      Product category list screen
  • Step 5

    In this section you will add a search field to ProductCategoriesListActivity, enabling a user to filter the results displayed on the product category screen.

    1. First, right-click the res/drawable folder to create a new Drawable Resource File ic_search_icon.xml, and use the following XML content.

      Create a new Drawable Resource File
      XML
      Copy
      <?xml version="1.0" encoding="utf-8"?>
      <vector xmlns:android="http://schemas.android.com/apk/res/android"
          android:width="24dp"
          android:height="24dp"
          android:viewportWidth="24"
          android:viewportHeight="24">
          <path
              android:fillColor="#FFF"
              android:pathData="M15.5,14h-0.79l-0.28,-0.27C15.41,12.59 16,11.11 16,9.5 16,5.91 13.09,3 9.5,3S3,5.91 3,9.5 5.91,16 9.5,16c1.61,0 3.09,-0.59 4.23,-1.57l0.27,0.28v0.79l5,4.99L20.49,19l-4.99,-5zM9.5,14C7.01,14 5,11.99 5,9.5S7.01,5 9.5,5 14,7.01 14,9.5 11.99,14 9.5,14z"/>
      </vector>
      

      The current menu res/menu/itemlist_menu.xml is shared among all list screens. We will now use a new XML file for the Product Categories screen.

    2. Right-click the res/menu folder to add a new Menu Resource File named product_categories_menu.xml, and use the following XML for its contents.

      Add a new Menu Resource File
      XML
      Copy
      <?xml version="1.0" encoding="utf-8"?>
      <menu xmlns:android="http://schemas.android.com/apk/res/android"
          xmlns:app="http://schemas.android.com/apk/res-auto">
      
          <item
              android:id="@+id/action_search"
              android:icon="@drawable/ic_search_icon"
              android:title="Search"
              app:actionViewClass="com.sap.cloud.mobile.fiori.search.FioriSearchView"
              app:showAsAction="always|collapseActionView"
              style="@style/FioriSearchView" />
      
          <item
              android:id="@+id/menu_refresh"
              android:icon="@drawable/ic_menu_refresh"
              app:showAsAction="always"
              android:title="@string/menu_refresh"/>
      </menu>
      
    3. On Windows, press Ctrl+N, or, on a Mac, press command+O, and type ProductCategoryListAdapter, to open the ProductCategoryListAdapter class, which is in the ProductCategoriesListFragment.java file.

    4. Add the following member to the top of this class.

      Java
      Copy
      private List<ProductCategory> allProductCategories;
      
    5. On Windows, press Ctrl+F12, or, on a Mac, press command+F12, and type setItems, to move to the setItems method.

    6. Add the following to the top of the function:

      Java
      Copy
      if (allProductCategories == null) {
          allProductCategories = new ArrayList<>(currentProductCategories);
      }
      
    7. On Windows, press Ctrl+F12, or, on a Mac, press command+F12, and type onCreateOptionsMenu, to move to the onCreateOptionsMenu method.

    8. Replace the contents of the method with the following code, which uses the new product_categories_menu and sets a listener that will filter the list of categories in the list when text is entered in the search view. (Make sure to import all the un-imported classes with alt+Enter on Windows or option+Enter on Macs.)

      Java
      Copy
      inflater.inflate(R.menu.product_categories_menu, menu);
      FioriSearchView searchView = (FioriSearchView) menu.findItem(R.id.action_search).getActionView();
      searchView.setBackgroundResource(R.color.transparent);
      // make sure to import androidx.appcompat.widget.SearchView
      searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
        @Override
        public boolean onQueryTextSubmit(String s) {
            return false;
        }
      
        @Override
        public boolean onQueryTextChange(String newText) {
            if (adapter == null) {
                return false;
            }
      
            List filteredCategoriesList = new ArrayList();
            if (newText != null && newText.trim().length() > 0) {
                for (int i = 0; i < adapter.allProductCategories.size(); i++) {
                    ProductCategory pc = adapter.allProductCategories.get(i);
                    if (pc.getCategoryName().toLowerCase().contains(newText.toLowerCase())) {
                        filteredCategoriesList.add(pc);
                    }
                }
            }
            else {
                filteredCategoriesList = adapter.allProductCategories;
            }
            adapter.productCategories = filteredCategoriesList;
            return false;
        }
      });
      
    9. Run the app again and notice that there is now a search toolbar item.

      Filter Categories in action 1
    10. Try it out: click the search item, enter some text, press Enter, and notice that the product categories that are displayed in the list are now filtered.

      Filter Categories in action 2

    Further information on the Fiori search UI can be found at SAP Fiori for Android Design Guidelines and Fiori Search User Interface.

  • Step 6

    In this section, you will add a Top Products section to the Products screen, which displays the products that have the most sales, as shown below.

    Collection View on Products Screen

    First, we’ll generate additional sales data in the sample OData service.

    1. In SAP Mobile Services cockpit, navigate to Mobile Applications > Native/Hybrid > com.sap.wizapp and go to Mobile Sample OData ESPM.

      Sample OData feature on Mobile Services
    2. Change the Entity Sets dropdown to SalesOrderItems and then click the generate sample sales orders icon five times. This will create additional sales order items, which we can use to base our top products on, based on the quantity sold.

      Generating Sample Sales Orders on Mobile Services
    3. In Android Studio, on Windows, press Ctrl+Shift+N, or, on a Mac, press command+Shift+O, and type fragment_entityitem_list, to open fragment_entityitem_list.xml.

    4. Replace the fragment_entityitem_list.xml content with the following code. This adds the CollectionView to the Products pane when created.

      XML
      Copy
      <?xml version="1.0" encoding="utf-8"?>
      <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
          xmlns:app="http://schemas.android.com/apk/res-auto"
          xmlns:tools="http://schemas.android.com/tools"
          android:layout_width="match_parent"
          android:layout_height="match_parent">
      
          <com.google.android.material.floatingactionbutton.FloatingActionButton
              android:id="@+id/fab"
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:layout_gravity="bottom|end"
              android:layout_margin="@dimen/fab_margin"
              android:src="@drawable/ic_add_circle_outline_black_24dp"
              app:tint="@color/colorWhite"
              app:backgroundTint="?attr/sap_fiori_color_s2"
              app:fabSize="normal" />
      
          <LinearLayout
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:orientation="vertical"
              android:id="@+id/wrapperLayout" >
      
              <com.sap.cloud.mobile.fiori.object.CollectionView
                  app:layout_scrollFlags="scroll|enterAlways"
                  android:id="@+id/collectionView"
                  android:layout_height="wrap_content"
                  android:layout_width="match_parent"
                  android:background="@color/transparent"
                  tools:minHeight="200dp">
              </com.sap.cloud.mobile.fiori.object.CollectionView>
      
              <androidx.swiperefreshlayout.widget.SwipeRefreshLayout
                  android:id="@+id/swiperefresh"
                  android:layout_width="match_parent"
                  android:layout_height="match_parent">
      
                  <androidx.recyclerview.widget.RecyclerView
                      android:id="@+id/item_list"
                      android:name="ItemListFragment"
                      android:layout_width="match_parent"
                      android:layout_height="match_parent"
                      app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />
              </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
      
          </LinearLayout>
      
      </FrameLayout>
      
    5. On Windows, press Ctrl+N, or, on a Mac, press command+O, and type ProductsListFragment, to open ProductsListFragment.java.

    6. Add the following import libraries to the top of the document:

      Java
      Copy
      import android.widget.LinearLayout;
      import com.sap.cloud.android.odata.espmcontainer.ESPMContainer;
      import com.sap.cloud.android.odata.espmcontainer.SalesOrderItem;
      import com.sap.cloud.mobile.fiori.common.FioriItemClickListener;
      import com.sap.cloud.mobile.fiori.object.AbstractEntityCell;
      import com.sap.cloud.mobile.fiori.object.CollectionView;
      import com.sap.cloud.mobile.fiori.object.CollectionViewItem;
      import com.sap.cloud.mobile.odata.DataQuery;
      
      import java.util.Collections;
      import java.util.Comparator;
      import java.util.HashMap;
      import java.util.Iterator;
      import java.util.LinkedHashMap;
      import java.util.LinkedList;
      import java.util.Map;
      
    7. Add the following variables to the top of the ProductsListFragment class:

      Java
      Copy
      private List<Product> productList = new ArrayList<>();
      private HashMap<String, Integer> salesList = new HashMap<>();
      private HashMap<String, Product> productTracker = new HashMap<>();
      
    8. Add the following methods to the class:

      Java
      Copy
      // Function to sort hashmap by values
      public static HashMap<String, Integer> sortByValue(HashMap<String, Integer> hm) {
          // Create a list from elements of HashMap
          List<Map.Entry<String, Integer>> list = new LinkedList<>(hm.entrySet());
      
          // Sort the list
          Collections.sort(list, new Comparator<Map.Entry<String, Integer>>() {
              public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) {
                  return (o2.getValue()).compareTo(o1.getValue());
              }
          });
      
          // Put data from sorted list to linked hashmap
          HashMap<String, Integer> temp = new LinkedHashMap<String, Integer>();
          for (Map.Entry<String, Integer> aa : list) {
              temp.put(aa.getKey(), aa.getValue());
              LOGGER.debug("CollectionView: id = " + aa.getKey() + ", count = " + aa.getValue());
          }
          return temp;
      }
      
      // Function to query the products
      private void queryProducts() {
          SAPServiceManager sapServiceManager = ((SAPWizardApplication) currentActivity.getApplication()).getSAPServiceManager();
          ESPMContainer espmContainer = sapServiceManager.getESPMContainer();
          DataQuery query = new DataQuery().orderBy(Product.productID);
          LOGGER.debug("CollectionView" + query.toString());
          espmContainer.getProductsAsync(query, (List<Product> queryProducts) -> {
              LOGGER.debug("CollectionView: executed query in onCreate");
              for (Product product : queryProducts) {
                  LOGGER.debug("CollectionView" + product.getName() + " : " + product.getProductID() + " : " + product.getPrice());
                  productTracker.put(product.getProductID(), product);
              }
      
              LOGGER.debug("CollectionView: size of topProducts = " + queryProducts.size());
              createTopProductsList();
              CollectionView cv = currentActivity.findViewById(R.id.collectionView);
              createCollectionView(cv);
          }, (RuntimeException re) -> {
              LOGGER.debug("CollectionView: An error occurred during products async query: " + re.getMessage());
          });
      }
      
      // Function to order product list by the sorted sales list
      private void createTopProductsList() {
          Iterator it = salesList.entrySet().iterator();
          while (it.hasNext()) {
              Map.Entry pair = (Map.Entry) it.next();
              productList.add(productTracker.get(pair.getKey()));
              it.remove();
          }
      }
      
      // Function to set features of the CollectionView
      private void createCollectionView(CollectionView cv) {
          LOGGER.debug("CollectionView: in createCollectionView method");
          cv.setHeader(" Top Products");
          cv.setFooter(" SEE ALL (" + productTracker.size() + ")");
      
          // If the footer "SEE ALL" is clicked then the Products page will open
          cv.setFooterClickListener(new View.OnClickListener() {
              @Override
              public void onClick(View v) {
                  cv.setVisibility(View.GONE);
              }
          });
      
          // If any object is clicked in CollectionView then the Product's detail page for that object will open
          cv.setItemClickListener(new FioriItemClickListener() {
              @Override
              public void onClick(@NonNull View view, int position) {
                  LOGGER.debug("You clicked on: " + productList.get(position).getName() + "(" + productList.get(position).getProductID() + ")");
                  showProductDetailActivity(view.getContext(), UIConstants.OP_READ, productList.get(position));
              }
      
              @Override
              public void onLongClick(@NonNull View view, int position) {
                  Toast.makeText(currentActivity.getApplicationContext(), "You long clicked on: " + position, Toast.LENGTH_SHORT).show();
              }
          });
      
          CollectionViewAdapter collectionViewAdapter = new CollectionViewAdapter();
          cv.setCollectionViewAdapter(collectionViewAdapter);
      
          if (getResources().getBoolean(R.bool.two_pane)) {
              refreshLayout = currentActivity.findViewById(R.id.swiperefresh);
              LinearLayout linearLayout = currentActivity.findViewById(R.id.wrapperLayout);
              int height = linearLayout.getHeight() - cv.getHeight();
              refreshLayout.setMinimumHeight(height);
          }
      }
      
      // Opens the product's detail page activity
      private void showProductDetailActivity(@NonNull Context context, @NonNull String operation, @Nullable Product productEntity) {
          LOGGER.debug("within showProductDetailActivity for " + productEntity.getName());
          boolean isNavigationDisabled = ((ProductsActivity) currentActivity).isNavigationDisabled;
          if (isNavigationDisabled) {
              Toast.makeText(currentActivity, "Please save your changes first...", Toast.LENGTH_LONG).show();
          } else {
              adapter.resetSelected();
              adapter.resetPreviouslyClicked();
              viewModel.setSelectedEntity(productEntity);
              listener.onFragmentStateChange(UIConstants.EVENT_ITEM_CLICKED, productEntity);
          }
      }
      
      public class CollectionViewAdapter extends CollectionView.CollectionViewAdapter {
          private List<Product> products;
      
          public CollectionViewAdapter() {
              products = productList;
          }
      
          @Override
          public void onBindViewHolder(@NonNull CollectionViewItemHolder collectionViewItemHolder, int i) {
              CollectionViewItem cvi = collectionViewItemHolder.collectionViewItem;
              Product prod = products.get(i);
              String productName = prod.getName();
      
              cvi.setDetailImage(null);
              cvi.setHeadline(productName);
              cvi.setSubheadline(prod.getCategoryName() + "");
              cvi.setImageOutlineShape(AbstractEntityCell.IMAGE_SHAPE_OVAL);
      
              if (prod.getPictureUrl() == null) {
                  // No picture is available, so use a character from the product string as the image thumbnail
                  cvi.setDetailImageCharacter(productName.substring(0, 1));
                  cvi.setDetailCharacterBackgroundTintList(com.sap.cloud.mobile.fiori.R.color.sap_ui_contact_placeholder_color_1);
              } else {
                  SAPServiceManager sapServiceManager = ((SAPWizardApplication)currentActivity.getApplication()).getSAPServiceManager();
                  cvi.prepareDetailImageView().setScaleType(ImageView.ScaleType.FIT_CENTER);
                  Glide.with(currentActivity.getApplicationContext())
                      .load(EntityMediaResource.getMediaResourceUrl(prod, sapServiceManager.getServiceRoot()))
                      // Import com.bumptech.glide.Glide for RequestOptions()
                      .apply(new RequestOptions().fitCenter())
                      .transition(DrawableTransitionOptions.withCrossFade())
                      .into(cvi.prepareDetailImageView());
              }
          }
      
          @Override
          public int getItemCount() {
              return products.size();
          }
      }
      
    9. On Windows, press Ctrl+F12, or, on a Mac, press command+F12, and type prepareViewModel, to move to the prepareViewModel method.

    10. Add the following code to the first “else”-block of the method:

      Java
      Copy
      CollectionView cv = currentActivity.findViewById(R.id.collectionView);
      createCollectionView(cv);
      
    11. On Windows, press Ctrl+F12, or, on a Mac, press command+F12, and type onCreate, to move to the onCreate method.

    12. Add the following lines of code at the end of the method:

      Java
      Copy
      // Get the DataService class, which we will use to query the back-end OData service
      ESPMContainer espmContainer = sapServiceManager.getESPMContainer();
      
      // Query the SalesOrderItems and order by gross amount received from sales
      // Change the orderBy arguments to SalesOrderItem.property_name to rearrange the CollectionView order of products
      DataQuery dq = new DataQuery().orderBy(SalesOrderItem.productID);
      espmContainer.getSalesOrderItemsAsync(dq, (List<SalesOrderItem> querySales) -> {
          LOGGER.debug("CollectionView: executed sales order query in onCreate");
          if (querySales != null) {
              for (SalesOrderItem sale : querySales) {
                  if (salesList.containsKey(sale.getProductID())) {
                      salesList.put(sale.getProductID(), salesList.get(sale.getProductID()).intValue() + sale.getQuantity().intValue());
                  } else {
                      salesList.put(sale.getProductID(), sale.getQuantity().intValue());
                  }
                  LOGGER.debug("CollectionView" + sale.getProductID() + ": " + sale.getQuantity() + ": " + sale.getGrossAmount());
              }
      
              salesList = sortByValue(salesList);
      
              LOGGER.debug("CollectionView: salesList size = " + salesList.size());
              queryProducts();
          } else {
              LOGGER.debug("CollectionView: sales query list is null");
          }
      }, (RuntimeException re) -> {
          LOGGER.debug("CollectionView: An error occurred during async sales query: " + re.getMessage());
      });
      
    13. Run the app and notice that the Products screen now has a component at the top of the screen that allows horizontal scrolling to view the top products. Tap a product to see more details. Alternatively, tap SEE ALL to see all the products.

      Collection View on Products Screen

      For more details, see Collection View in SAP Fiori for Android Design Guidelines and Collection View

      For more information on SAP Fiori for Android and the generated app, see Fiori UI Overview, SAP Fiori for Android Design Guidelines, Fiori UI Demo Application and the WizardAppReadme.md file located in the generated app.

    Congratulations! You have now made use of SAP Fiori for Android and have an understanding of some of the ways that the wizard-generated application can be customized to show different fields on the list screens, add or remove menu items, perform a search, and use a collection view.

Back to top