User Tools

Site Tools


android_learning:headfirst_android_development_notes:chapter_9

Chapter 9

The changes to Android Studio 1.5.1 have put this chapter well out of sync with both the “Blank Activity” and “Empty Activity” templates. So while this isn't a very long chapter, there will be a lot of corrections/addenda.

It might be a little ambiguous in the Chapter intro, so here's a summary of what you're going to do in the chapter. You will build an app that has an action bar. An action bar is space at the top of an app that holds the activity name or other info on the left (in LTR languages) as well as a menu on the right (in LTR languages). The menu will have a number of items; some of those items will be specified to be pulled out of the drop down list and placed on the action bar as action buttons alongside the menu.

The action bar is a bit of a clustercuss at the moment. It wasn't to Android added until relatively recently, and if you want to build apps using action bars that target older versions of Android, you'll have to use compatibility libraries. The syntax when compatibility libraries is just different enough from current Android “native” action bars to make things maximally painful to move from one to the other.

Another issue is that the compatibility libraries seem to be buggier than the current Android “native” action bars. So, I think it's best not to mess around with the compatibility libraries at first. Let the fun begin.

p. 370: Creating the project

When creating the project, set the minimum API level to 21 (not 17).

It will hurt if you don't.

Be sure you specify an Empty app template in the new app wizard.

The Empty activity template does not generate a menu_main.xml file, so you'll have to add one manually. In Android Studio, right click on the res folder in the Android view, select New > Menu resource file, and give the file the name menu_main.xml. Then replace the contents of that file with the following:

menu_main.xml
<menu 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"
    tools:context=".MainActivity">
 
    <item android:id="@+id/action_settings"
        android:title="@string/action_settings"
        android:orderInCategory="100"
        android:showAsAction="never" />
</menu>

and create a string resource

<string name="action_settings">Settings</string>

The main_menu.xml code you entered above will probably show you that there are errors. If this is the case, it means that Android Studio set up your app to use the compatibility libraries. The book tries to show you how to build the app either way, but we're only going to build this not using the compatibility libraries.

v7 appcompat libraries

Way over on p. 385 there is an aside about action items not appearing when using some versions of the v7 appcompat library because of an Android bug. I've been bit by this and it stands as the main reason I suggest not trying to use them for your maiden action bar voyage.

So, start by removing the project's dependency on the v7 appcompat library by using File > Project Structure… and selecting app > Dependencies, then right clicking on the appropriate entry to remove it.

This will make MainActivity.java very angry. Make MainActivity extend Activity rather than ActionBarActivity (and fixing imports), and this will make MainActivity.java a little happier. But you'll probably notice that R is broken. R is broken at this point because styles.xml makes reference to a “Theme.AppCompat.Light.DarkActionBar” value, which no longer exists because we're not using the compatibility libraries any more. We'll fix that shortly.

Isn't this fun?

p. 372

Open up AndroidManifest.xml and add

android:label="@string/app_name"

to the <activity> element. You might want to verify that the @string/app_name resource exists.

If a label isn't specified for an activity, Android will use the app's label instead. In this case we are setting the activity's label to be the same as the app's label, but this doesn't have to be the case.

p. 374

Now let's take care of the problem caused by the “Theme.AppCompat.Light.DarkActionBar” reference. Open styles.xml and change

<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">

to

<style name="AppTheme" parent="android:Theme.Material.Light">

Also get rid of the items for colorPrimary, colorPrimaryDark, and colorAccent.

If you are seeing errors now, it might be because you forgot to specify a minimum API level of 21 when you create the app. You can fix that now by opening File > Project Structure… and selecting app > Flavors and for the defaulConfig's “Min Sdk Version”, manually type in 21.

Try running the app. It's smoother sailing from here out.

p. 379

Let's add an action to the menu. Open and insert the following code before the “action_settings” item:

<item android:id="@+id/action_create_order"
	android:title="@string/action_create_order"
	android:icon="@drawable/ic_action_new_event"
	android:orderInCategory="1"
	android:showAsAction="ifRoom" />

Be sure to use android:showAsAction rather than app:showAsAction. The former works with “native” action bars; the latter is the syntax if you're using the compatibility libraries.

Isn't that nice?

Add the “@string/action_create_order” resource with a value of “Create order”.

The icons

The code above references “@drawable/ic_action_new_event”, which means Android is expecting to see ic_action_new_event.png icon files in the drawables folders. Don't bother looking for the specified icon files in the file you're directed to download in the text. They're not there anymore. For reasons known only to the Google, they've been removed.

Whee.

Instead the authors are now recommending you grab images from the drawables-* folders at http://tinyurl.com/HeadFirstAndroidNewEventIcons and drop them into folders of the same name in your project. You'll probably have to create the corresponding drawables-* folders. Or you can grab this zip that has the folders with images already in them.

p. 380

The author's code on this page doesn't need to be modified.

Yay.

@Override
public boolean onCreateOptionsMenu(Menu menu) {
	// Add menu_main items to the action bar (if present):
	getMenuInflater().inflate(R.menu.menu_main, menu);
	return super.onCreateOptionsMenu(menu);
}

Use Android Studio's code generation feature to stub out overridden methods. It saves a lot of typing.

p. 381

The author's code on this page doesn't need to be modified. But I would suggest you add a Toast to each of the cases to confirm that things are working as expected:

@Override
public boolean onOptionsItemSelected(MenuItem item) {
	switch (item.getItemId()) {
		case R.id.action_create_order:
			//Code to run when the Create Order item is clicked
			Toast.makeText(MainActivity.this, "Create!", Toast.LENGTH_SHORT).show();
			return true;
		case R.id.action_settings:
			//Code to run when the settings item is clicked
			Toast.makeText(MainActivity.this, "Settings!", Toast.LENGTH_SHORT).show();
			return true;
		default:
			return super.onOptionsItemSelected(item);
	}
}

p. 382

Be sure to create a new Empty activity. It should automagically generate with a parent class of Activity. Create a menu file for this activity as you did before.

p. 383

Add the specified code and take the app for a spin. Everything good?

Notice the name of the new activity is given as “Bits and Pizzas”. This is because there is no android:label entry for this activity in the AndroidManifest.xml. If an activity doesn't have an android:label in the manifest, Android will show the application's android:label instead. Change that by adding

android:label="@string/activity_order_name"

to the manifest and create an appropriate value for the new resource.

Sweet. The really annoying stuff is over.

p. 385

Read the aside about breaky v7 appcompat and be glad that you didn't go down that road now.

p. 387

Remember to use android:showAsAction instead of app:showAsAction:

<item android:id="@+id/action_share"
	android:title="@string/action_share"
	android:orderInCategory="2"
	android:showAsAction="ifRoom"
	android:actionProviderClass="android.widget.ShareActionProvider" />

p. 389: Code block

Here's the file I ended up with:

MainActivity.java
package com.hfad.bitsandpizzas;
 
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.ShareActionProvider;
import android.widget.Toast;
 
public class MainActivity extends Activity {
 
    private ShareActionProvider shareActionProvider;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
 
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Add menu_main items to the action bar (if present):
        getMenuInflater().inflate(R.menu.menu_main, menu);
        MenuItem menuItem = menu.findItem(R.id.action_share);
        shareActionProvider = (ShareActionProvider) menuItem.getActionProvider();
        setIntent("This is example text.");
        return super.onCreateOptionsMenu(menu);
    }
 
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.action_create_order:
                //Code to run when the Create Order item is clicked
                Intent intent = new Intent(this, OrderActivity.class);
                startActivity(intent);
                return true;
            case R.id.action_settings:
                //Code to run when the settings item is clicked
                Toast.makeText(MainActivity.this, "Settings!", Toast.LENGTH_SHORT).show();
                return true;
            default:
                return super.onOptionsItemSelected(item);
        }
    }
 
    private void setIntent(String text)
    {
        Intent intent = new Intent(Intent.ACTION_SEND);
        intent.setType("text/plain");
        intent.putExtra(Intent.EXTRA_TEXT, text);
        shareActionProvider.setShareIntent(intent);
    }
}

When you run the app, you may see the Messaging app's icon next to the Share icon, and when you click on the Share icon, nothing seems to happen. If this is the case, it's likely because there is only one app in your emulator that is set up to handle shared messages. To add another app to the heap, open the Email app in the emulator and set it up with an appropriate account. You may have to wait and/or restart the emulator, but eventually you should see an additional icon when you click the Share icon in your app.

p. 392

Since this app isn't supporting API 16 and lower, you don't need the meta-data stuff for the OrderActivity in AndroidManifest.xml.

p. 393

Code it like you see it.

Congratulations.

android_learning/headfirst_android_development_notes/chapter_9.txt · Last modified: 2016/03/16 03:34 by mithat

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki