Perhaps you would like to get your notes off of our book reader app and
into someplace else, or perhaps you would like to share them with somebody
else. Either way, we can do that using an ACTION_SEND
operation, to allow
the user to choose how to “send” the notes, such as sending them by email
or uploading them to some third-party note service.
To make this work, we will add a ShareActionProvider
to our action bar
on the NoteFragment
.
This is a continuation of the work we did in the previous tutorial.
You can find the results of the previous tutorial and the results of this tutorial in the book’s GitHub repository.
First, we need to allow the user to indicate that they want to “share” the
note displayed in the current NoteFragment
. By putting an action bar item
on the activity where the NoteFragment
is displayed, we do not need to
worry about letting the user choose which note to send — we simply send
whichever note they happen to be viewing or editing.
By using a ShareActionProvider
, the action item will handle most of the
work for allowing the user to choose where to send the note to. We only need
to provide an Intent
that identifies what is to be shared.
Modify res/menu/notes.xml
to add in the new share
toolbar button:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/share"
android:actionProviderClass="android.widget.ShareActionProvider"
android:showAsAction="ifRoom"
android:title="@string/share"/>
<item
android:id="@+id/delete"
android:icon="@drawable/ic_delete_white_24dp"
android:showAsAction="ifRoom|withText"
android:title="@string/delete">
</item>
</menu>
Note that this menu definition requires a new string resource, named share
,
with a value like Share
.
Now, we need to configure the ShareActionProvider
, in particular supplying it
with a continuously-updated Intent
, based upon what the user has typed into
the EditText
.
Add a ShareActionProvider
data member to NoteFragment
, named share
,
along with an Intent
data member named shareIntent
configured to use
ACTION_SEND
of a MIME type of text/plain
:
private ShareActionProvider share=null;
private Intent shareIntent=
new Intent(Intent.ACTION_SEND).setType("text/plain");
Then, in onCreateView()
, tell the EditText
to let us know when the user
changes the text, via addTextChangedListener()
:
@Override
public View onCreateView(LayoutInflater inflater,
ViewGroup container,
Bundle savedInstanceState) {
View result=inflater.inflate(R.layout.editor, container, false);
editor=(EditText)result.findViewById(R.id.editor);
editor.addTextChangedListener(this);
return(result);
}
This will fail to compile, as our NoteFragment
is not implementing the
TextWatcher
interface. So, modify the NoteFragment
class declaration
to include the TextWatcher
interface:
public class NoteFragment extends Fragment implements TextWatcher {
That, in turn, will require us to implement three methods:
afterTextChanged()
beforeTextChanged()
onTextChanged()
In our case, we care about afterTextChanged()
. So, add the following three
methods to NoteFragment
:
@Override
public void afterTextChanged(Editable s) {
shareIntent.putExtra(Intent.EXTRA_TEXT, s.toString());
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
// ignored
}
@Override
public void onTextChanged(CharSequence s, int start, int before,
int count) {
// ignored
}
Here, we update the shareIntent
with the latest text to be shared, storing
it in EXTRA_TEXT
, per the instructions in the Android developer documentation
for working with ACTION_SEND
.
However, we have not initialized share
yet. We can do that in onCreateOptionsMenu()
,
adding a call to findItem()
to find our R.id.share
menu item, then calling
getActionProvider()
to get the ShareActionProvider
out of the menu item:
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.notes, menu);
share=
(ShareActionProvider)menu.findItem(R.id.share)
.getActionProvider();
share.setShareIntent(shareIntent);
super.onCreateOptionsMenu(menu, inflater);
}
Here, we also attach the shareIntent
to the ShareActionProvider
, so when it comes
time to share the text, the ShareActionProvider
knows how to do that.
If you run this on a device and navigate to a filled-in note, you will see the new action bar item:
Figure 301: ShareActionProvider in NoteFragment
If you tap on it, you will get a roster of possible ways to share the text:
Figure 302: ShareActionProvider in NoteFragment, Expanded
Figure 303: ShareActionProvider in NoteFragment, Fully Expanded
The exact options you see will vary based on your device or emulator, and what apps are installed on it that know how to share plain text. If you only have one choice (e.g., Messenger), it will appear next to the share icon, and you will only be able to tap on that one choice.
Unfortunately, your emulator may have nothing that can handle this Intent
.
If that is the case, you will crash with an ActivityNotFoundException
.
To get past this, if you enter http://goo.gl/w113e
in your emulator’s browser,
that should allow you to download and install a copy of the APK from the
Intents/FauxSender
sample project that we covered earlier in this book.
When the download is complete (which should be very quick), open up the
notification drawer and tap on the “download complete” notification. This
should begin the installation process. Depending on your Android version,
you may also need to “allow installation of non-Market apps” — after
fixing this, you can use the Downloads app on the emulator to try installing
the APK again. Once FauxSender
is installed, it will respond to your attempts to share a note.
… we will allow the user to update the book’s contents over the Internet.