Android Product Directory

PART 3: Pass Data To Detail Activity

When working with Master/Detail activities, while you could create a separate detail activity for each list item, a better approach is to create a single detail activity that can change dynamically to accommodate data that is passed to it or data from a data source.

When navigating from one activity to another, you can pass data as an Extra that can be one of many Java data types (e.g., string, number, array, Boolean or collections of name/value pairs called bundles which is similar to a Java HashMap).

In this part of the project, we will pass a single value from the MainActivity to the DetailActivity and then have the DetailActivity use that value to get a complex object from the DataProvider class to display the requested detail information. This is akin to passing a query string to another page to populate it with data from a database using server-side technology like PHP, ASP, JSP or ColdFusion.

Prep for Part 3

  1. Copy the ProductDirectoryAppPart2 and paste it in the same directory as ProductDirectoryAppPart3.
  2. Open ProductDirectoryAppPart3 in Android Studio.
  3. Right-click on the package and Refactor > Rename… and change the 2 to 3 on the package name: com.example.productdirectoryapppart3 and then click the OK button.
  4. In the strings.xml file change the 2 to 3 for the app name attribute:

    <string name="app_name">ProductDirectoryApp Part 3</string>

 

  1. Open the MainActivity class and write the following highlighted code in the setOnItemClick() method after the Intent statement to get a reference to the current product that a user selected and then pass data to the intent object as an Extra.

    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
    Intent intent = new Intent(MainActivity.this, DetailActivity.class);
    Product product = products.get(position);
    intent.putExtra(PRODUCT_ID, product.getProductId());

    startActivity(intent);
    }

    CODE EXPLANATION:
    - This is a complex product.
    - The products.get() is a method of the List object.
    - The putExtra method takes two arguments. The first argument is a string that represents the name of the Extra. The second argument is a Java data type (bundle, HashMap). In this case, we choose the putExtra that passes a string and a character sequence (string) as its value. This is similar to the Log.x method that requires two strings where x is the type of log.
    - The first argument is assigned a constant (PRODUCT_ID) and the second argument is assigned to product.getProductId() which represent the value that will be SENT TO the DetailActivity that will RECEIVE that value.

  2. ALT+CLICK inside of PRODUCT_ID and select Create constant field ‘PRODUCT_ID’, choose the MainActivity class, press the TAB key and enter PRODUCT_ID or anything you want. Change private to public as the access modifier.

    public static final String PRODUCT_ID = “PRODUCT_KEY”;

    CODE EXPLANATION:
    The access modifier was changed from private to public so that the constant can be available between the two activities.

  3. Open the DetailActivity class and add the following highlighted code in the onCreate() method to retrieve the value of the Extra passed FROM the MainActivity.

    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_detail);
    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);

    String productId = getIntent().getStringExtra(MainActivity.PRODUCT_ID);

    CODE EXPLANATION: A string variable (productId) is created and assigned the getIntent() and the getStringExtra methods. Remember, you used putExtra when you SENT DATA and getIntent and getStringExtra when you RECEIVE DATA.

  4. Below the String variable, add the following highlighted code:

    String productId = getIntent().getStringExtra(MainActivity.PRODUCT_ID);
    Product product = DataProvider.productMap.get(productId);
    TextView textview = (TextView) findViewById(R.id.nameText);
    textview.setText(product.getName());


    CODE EXPLANATION:
    - If you look back at the DataProvider class, you see that it has a productMap that is a map of all the data objects with a key of String and a data type of Product. Product product = DataProvider.productMap.get(productId); represent a complex object.
    - A reference to the TextView object is created and then the setText method is used to set the text to the value of product.getName() which represents the name of the selected product.

  5. CHECK POINT: Run the app in an emulator. You should see the actual name for the item you selected. Click the Back button and select another item and you see that it displays the correct name for that item as well. However, the other components still have the same values regardless of the item you click on. This will be resolved in the upcoming steps. However, there is code in the ProductListAdapter class that we will use and modify to meet our needs.
  6. Go to the ProductListAdapter class and copy the getBitmapFromAsset method. Return to the DetailActivity class and paste it OUTSIDE of the onCreate() method which will open the Select Classes to Import dialog box. Accept all of the recommended imports for the classes needed and then click the OK button.

    private Bitmap getBitmapFromAsset(String productId) {
    AssetManager assetManager = getContext().getAssets();
    InputStream stream = null;

    try {
    stream = assetManager.open(productId + ".png");
    return BitmapFactory.decodeStream(stream);
    } catch (IOException e) {
    e.printStackTrace();
    return null;
    }
    }

    }

  7. Delete getContext(). from the following statement:

    AssetManager assetManager = getAssets();

    CODE EXPLANATION:
    getContext() is not needed because the assetManager is being called from within an activity class so the context is already known and can be called from the current class.

  8. Go back to ProductListAdapter class AGAIN, and select the following highlighted code and return to the DetailActivity class and paste it BELOW of the TextView code which will open the Select Classes to Import dialog box. Accept all of the recommended imports for the classes needed and then click the OK button.

    TextView tv = (TextView) findViewById(R.id.nameText);
    tv.setText(product.getName());

    NumberFormat formatter = NumberFormat.getCurrencyInstance();
    String price = formatter.format(product.getPrice());
    TextView priceText = (TextView) convertView.findViewById(R.id.priceText);
    priceText.setText(price);

    ImageView imageview = (ImageView) convertView.findViewById(R.id.imageView);
    Bitmap bitmap = getBitmapFromAsset(product.getProductId());
    imageview.setImageBitmap(bitmap);


  9. Delete the two instances of convertView. on the TextView and ImageView for the same reason discussed earlier:

    TextView priceText = (TextView) findViewById(R.id.priceText);
    priceText.setText(price);
    ImageView imageview = (ImageView) findViewById(R.id.imageView);

  10. In the DetailActivity class, add the following highlighted code below the other TextView:

    TextView priceText = (TextView) findViewById(R.id.priceText);
    priceText.setText(price);

    TextView scrollView = (TextView) findViewById(R.id.descriptionText);
    scrollView.setText(product.getDescription());


  11. CHECK POINT: Run the app in an emulator. You should see that if you click on any item in the list ALL of the components are populated with the correct data from the DataProvider class. You could have pass a multitude of extras values or pass a single primary key value (akin to query string) and then use its value in the DetailActivity to get the data you need.