Managing Data. However, we'll be looking at two other forms of persistence today: (shared) preferences, and databases.

Similar documents
More Effective Layouts

Adapting to Data. Before we get to the fun stuff... Initial setup

Eventually, you'll be returned to the AVD Manager. From there, you'll see your new device.

Meniu. Create a project:

Android Programs Day 5

Database Development In Android Applications

An Android Studio SQLite Database Tutorial

05. RecyclerView and Styles

Eng. Jaffer M. El-Agha Android Programing Discussion Islamic University of Gaza. Data persistence

Developing Android Applications Introduction to Software Engineering Fall Updated 1st November 2015

Spring Lecture 5 Lecturer: Omid Jafarinezhad

07. Data Storage

Android Specifics. Jonathan Diehl (Informatik 10) Hendrik Thüs (Informatik 9)

EMBEDDED SYSTEMS PROGRAMMING Application Tip: Saving State

Resources and Media and Dealies

Layout and Containers

The Stack, Free Store, and Global Namespace

Android Using Menus. Victor Matos Cleveland State University

Getting Started With Android Feature Flags

Mobile and Ubiquitous Computing: Android Programming (part 4)

MITOCW watch?v=rvrkt-jxvko

COSC 3P97 Assignment 1

Mobile Programming Lecture 10. ContentProviders

Our First Android Application

Vienos veiklos būsena. Theory

PROFESSOR: Last time, we took a look at an explicit control evaluator for Lisp, and that bridged the gap between

Lesson 3 Transcript: Part 1 of 2 - Tools & Scripting

Android Apps Development for Mobile and Tablet Device (Level I) Lesson 4. Workshop

Mobile Programming Lecture 7. Dialogs, Menus, and SharedPreferences

Mobile Programming Lecture 2. Layouts, Widgets, Toasts, and Event Handling

Post Experiment Interview Questions

Starting Another Activity Preferences

Arrays of Buttons. Inside Android

Debojyoti Jana (Roll ) Rajrupa Ghosh (Roll ) Sreya Sengupta (Roll )

Mobile Application Development Lab [] Simple Android Application for Native Calculator. To develop a Simple Android Application for Native Calculator.

MITOCW watch?v=0jljzrnhwoi

Produced by. Mobile Application Development. Higher Diploma in Science in Computer Science. Eamonn de Leastar

Accelerating Information Technology Innovation

Applied Cognitive Computing Fall 2016 Android Application + IBM Bluemix (Cloudant NoSQL DB)

Mobila applikationer och trådlösa nät, HI1033, HT2012

Using the API: Introductory Graphics Java Programming 1 Lesson 8

So on the survey, someone mentioned they wanted to work on heaps, and someone else mentioned they wanted to work on balanced binary search trees.

PROFESSOR: Well, yesterday we learned a bit about symbolic manipulation, and we wrote a rather stylized

MYOB Exo PC Clock. User Guide

Android Using Menus. Victor Matos Cleveland State University

10.1 Introduction. Higher Level Processing. Word Recogniton Model. Text Output. Voice Signals. Spoken Words. Syntax, Semantics, Pragmatics

Intents. Your first app assignment

Mobile Computing Practice # 2c Android Applications - Interface

Java Programming Constructs Java Programming 2 Lesson 1

It Might Be Valid, But It's Still Wrong Paul Maskens and Andy Kramek

Arduino IDE Friday, 26 October 2018

Azon Master Class. By Ryan Stevenson Guidebook #5 WordPress Usage

Assignment 1: grid. Due November 20, 11:59 PM Introduction

Mobile Computing Practice # 2d Android Applications Local DB

Agenda. Overview of Xamarin and Xamarin.Android Xamarin.Android fundamentals Creating a detail screen

SQLite Database. References. Overview. Structured Databases

ActionBar. import android.support.v7.app.actionbaractivity; public class MyAppBarActivity extends ActionBarActivity { }

Have a development environment in 256 or 255 Be familiar with the application lifecycle

Mobila applikationer och trådlösa nät, HI1033, HT2013

Contents. What's New. Version released. Newsletter #31 (May 24, 2008) What's New New version released, version 4.3.3

MITOCW watch?v=kz7jjltq9r4

EMBEDDED SYSTEMS PROGRAMMING Application Tip: Managing Screen Orientation

In our first lecture on sets and set theory, we introduced a bunch of new symbols and terminology.

Instructor: Craig Duckett. Lecture 04: Thursday, April 5, Relationships

mk-convert Contents 1 Converting to minikanren, quasimatically. 08 July 2014

CSCU9YH: Development with Android

Hi everyone. Starting this week I'm going to make a couple tweaks to how section is run. The first thing is that I'm going to go over all the slides

MITOCW watch?v=zm5mw5nkzjg

BEGINNER PHP Table of Contents

Android App Development. Mr. Michaud ICE Programs Georgia Institute of Technology

Upon completion of the second part of the lab the students will have:

Hello, and welcome to another episode of. Getting the Most Out of IBM U2. This is Kenny Brunel, and

Contents. What's New. Dropbox / OneDrive / Google drive Warning! A couple quick reminders:

Data Persistence. Chapter 10

Android Data Storage

Software Engineering Large Practical: Storage, Settings and Layouts. Stephen Gilmore School of Informatics October 27, 2017

Lab 1 - Setting up the User s Profile UI

Formal Methods of Software Design, Eric Hehner, segment 24 page 1 out of 5

CS 4330/5390: Mobile Application Development Exam 1

Chrome if I want to. What that should do, is have my specifications run against four different instances of Chrome, in parallel.

MITOCW MIT6_01SC_rec2_300k.mp4

Mobile Programming Lecture 5. Composite Views, Activities, Intents and Filters

Hi everyone. I hope everyone had a good Fourth of July. Today we're going to be covering graph search. Now, whenever we bring up graph algorithms, we

Produced by. Mobile Application Development. Higher Diploma in Science in Computer Science. Eamonn de Leastar

External Services. CSE 5236: Mobile Application Development Course Coordinator: Dr. Rajiv Ramnath Instructor: Adam C. Champion

Grocery List: An Android Application

P1_L3 Operating Systems Security Page 1

Class #7 Guidebook Page Expansion. By Ryan Stevenson

What's New. Version 9.2 release. Campground Master Contents 1. Contents. A couple quick reminders:

Mobile Computing Professor Pushpedra Singh Indraprasth Institute of Information Technology Delhi Andriod Development Lecture 09

Create Parent Activity and pass its information to Child Activity using Intents.

Casting in C++ (intermediate level)

SQLite. 5COSC005W MOBILE APPLICATION DEVELOPMENT Lecture 6: Working with Databases. What is a Database Server. Advantages of SQLite

Formal Methods of Software Design, Eric Hehner, segment 1 page 1 out of 5

This Week on developerworks Push for ios, XQuery, Spark, CoffeeScript, top Rational content Episode date:

Linked Lists. What is a Linked List?

Blitz2D Newbies: Definitive Guide to Types by MutteringGoblin

Android Navigation Drawer for Sliding Menu / Sidebar

Chapter 1 Getting Started

Android Programming Family Fun Day using AppInventor

Transcription:

Managing Data This week, we'll be looking at managing information. There are actually many ways to store information for later retrieval. In fact, feel free to take a look at the Android Developer pages: https://developer.android.com/guide/topics/data/data-storage.html We could store records in 'the cloud' and retrieve them later, say with some RESTful API. We could create a datafile for our application, and manipulate that. Both have their uses. However, we'll be looking at two other forms of persistence today: (shared) preferences, and databases. (Shared) Preferences Why? Consider the following: you load up your preferred calculator app, and switch to 'formula mode'. The next time you open your calculator, wouldn't it be nice if it remembered that you preferred formula mode last time? For that matter, if you had saved a particular value last time, perhaps it would be useful to still have it available upon the next execution? For other apps, think about all of the customizations you typically have: whether or not to silence when you're using the application, whether you want haptic feedback, how often to update weather information, what tune to play for notifications, accessibility preferences, etc. All of these are things that you wouldn't necessarily want to need to reset for each execution. They also have something else in common that we'll explain very soon. What? A 'shared preference' file is a very basic data management file that stores tuples of key-value pairs. There are different use cases (e.g. a single preferences file for the application that's mostly managed for you, a PreferenceActivity to make changing user settings more consistent across applications, multiple explicitlynamed preference files, 'world-readable' preference files so one application can access the user's preferences from another, etc.), but they all have the same basic mechanisms: Open a preference file Read by querying on a key Write by updating a new value for a key Because of the tuple-nature of the data, preferences are not for storing things like complex data, records, etc. Why could the calculator's saved memory be an exception? Because there's always only one memory bank (or always a fixed-size set of memory values). There's no table of records for selecting.

There are some very good reads here: https://developer.android.com/guide/topics/ui/settings.html https://developer.android.com/reference/android/preference/preferenceactivity.html https://developer.android.com/training/basics/data-storage/shared-preferences.html https://developer.android.com/reference/android/content/sharedpreferences.html Let's try a trivial example, just to demonstrate the mechanism. Let's start with a layout: <?xml version="1.0" encoding="utf-8"?> <LinearLayout 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_height="match_parent" tools:context="ca.brocku.efoxwell.a2017_sixthstage.mainactivity" android:orientation="vertical"> <TextView android:layout_width="wrap_content" android:text="do we have a preference?" android:id="@+id/preferentialdisplay" <EditText android:id="@+id/preferentialinput" android:onclick="buttony" <Button android:layout_width="wrap_content" android:text="save" android:id="@+id/preferentialretain" android:onclick="buttony" <Button android:layout_width="wrap_content" android:text="load" android:id="@+id/preferentialrestore" android:onclick="buttony" <Button android:id="@+id/doneprefs" android:text="next!" android:onclick="buttony" </LinearLayout> As you can see, it's just a couple buttons to trigger the basic actions we'll be wanting: loading and saving. On the code side, I think I'll abstract those behaviours out into separate methods. Upon creating the Activity, I'll have it invoke the retrieval behaviour, to auto-initialize the display. We've already seen this style of retrieving data. If we want something that doesn't exist, we'll need to provide a default value. In this case, we'll be storing a String, and if it doesn't exist, we'll just go with the empty string. Finally, empty strings are boring, so our code will only display a value if it has a 'real' one.

Let's look at retrieving data first: private void retrieve() { //Of course, we don't normally use this for widgets! SharedPreferences memories=getpreferences(context.mode_private); //we could use getsharedpreferences if we wanted to choose the preference file //Also, 0 would have been just fine for the mode TextView display=(textview)findviewbyid(r.id.preferentialdisplay); String value=memories.getstring("somekey","");//the second term is the default value if (!value.equals("")) display.settext(value); So let's explain the pieces here: The SharedPreferences object, used this way, loads the default preferences file for the application If you want to try opening in different modes, know that many access mechanisms have been deprecated by recent versions of Android (basically, if you want to share preferences across applications, it's possible, but less pleasant) The query syntax is basically the same as our 'extras' Of course, our oncreate can just call this at the end. Next, how can we save? //It's often a good idea to attach this kind of thing to onstop private void store() { TextView entry=(edittext)findviewbyid(r.id.preferentialinput); String value=entry.gettext().tostring(); if (!value.equals("")) { SharedPreferences memories=getpreferences(context.mode_private); SharedPreferences.Editor editor=memories.edit(); editor.putstring("somekey",value); //Please don't forget this part: editor.commit(); Note that, to make changes, we need to use an Editor. And please, pretty please, don't forget to commit the changes! By now, the buttons should be trivial: public void buttony(view v) { switch (v.getid()) { case R.id.preferentialRetain: store(); break; case R.id.preferentialRestore: retrieve(); break; case R.id.donePrefs: //start next activity break;

Well, let's give it a try! Reminders about preferences Though our simple example obviously worked, don't forget that this is not how one would typically interact with the data in a preference file. Most commonly, there are premade Activities/Fragments for managing actual user preferences. That's why most Android applications have effectively identical designs for their user settings: because it's provided for you. Also, though I'm sure you could find a way to jury-rig them into storing arbitrary data, you really shouldn't try to move outside the paradigm of single set of key-value tuples. Storing records Okay, so we shouldn't be using preference files to store arbitrary data/records. Well, if that's what we shouldn't use, then what should we? Let's pull back from Mobile and ask the same question for any other computer: I have several records, and wish to store them in an organized fashion, that will allow for later searching, retrieval, and updates; what do I do? A database? Then I guess that's our answer here, as well! SQLite Android includes SQLite. As the name implies, SQLite is a database management system for lightweight databases. How lightweight? Well, you probably wouldn't want ot use it on a server for most tasks, but it's just spiffy for single-user operation, which makes it perfect for storing data for a single application. That's why many programs use it for storing user settings, personal data, etc. (e.g. web browsers often use it for your cookies, bookmarks, and settings). It's worth noting that, between Android and Android Studio, you're also provided with a couple more tools for managing and inspecting SQLite databases, but we don't need to worry about that today. Source of database In order to user a database, we'll of course need to have said database. Depending on your needs, you could create it completely in advance, and distribute it with your application. Alternatively, your application can build it (e.g. on the first execution). Our example will be doing the latter. Operation The operation isn't terribly difficult. Android includes an abstract SQLiteOpenHelper class to help with opening and accessing the database. Queries use a Cursor to keep track of where you are within the query results.

First example Let's start very small. We'd like: To create a database if we don't already have one An activity for creating a new entry An activity to let us view one piece of data Some way of removing the data Creating the database As mentioned earlier, Android includes an SQLiteOpenHelper to help you manage your databases. It actually already does nearly all of the work for you. There's just one catch: If the desired database doesn't yet exist, it needs to be able to create it. But how would it know what to create? That's where you come in. Let's create a simple Java class: public class DataHelper extends SQLiteOpenHelper { public static final int DATABASE_VERSION = 2; public static final String DB_NAME = "sophia"; public static final String DB_TABLE = "wisdom"; public static final int DB_VERSION = 1; private static final String CREATE_TABLE = "CREATE TABLE " + DB_TABLE + " (rule INTEGER PRIMARY KEY, subject TEXT, lesson TEXT);"; DataHelper(Context context) { super(context,db_name,null,database_version); public void oncreate(sqlitedatabase db) { db.execsql(create_table); public void onupgrade(sqlitedatabase db, int oldversion, int newversion) { //How to migrate or reconstruct data from old version to new on upgrade Note that I skipped the package/import lines. So, what's going on here? This particular database is called sophia We have a single table, wisdom Each entry under wisdom is indexed by a rule number, and has both a subject and a lesson text

So far, so good. We can now use that whenever we want to access the database! We're going to have three basic operations for now: adding entries, showing a single entry, and wiping out the database. In a real application, there'd be more (e.g. editing existing entries; showing multiple entries simultaneously, probably using an adapter; and deleting individual records), but this is enough to see it working. Making a new entry Let's make our first Activity, NewWisdom, and have our initial activity start it upon the button press. First, the layout: <?xml version="1.0" encoding="utf-8"?> <LinearLayout 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_height="match_parent" tools:context="ca.brocku.efoxwell.a2017_sixthstage.newwisdom" android:orientation="vertical"> <EditText android:id="@+id/editsubject" <EditText android:id="@+id/editlesson" <Button android:text="save!" android:onclick="save" </LinearLayout> and now the Java code: public class NewWisdom extends AppCompatActivity { protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.activity_new_wisdom); public void save(view v) { EditText subwidget=(edittext)findviewbyid(r.id.editsubject); EditText leswidget=(edittext)findviewbyid(r.id.editlesson); DataHelper dh=new DataHelper(this); SQLiteDatabase datachanger=dh.getwritabledatabase(); ContentValues newwisdom=new ContentValues(); newwisdom.put("subject",subwidget.gettext().tostring()); newwisdom.put("lesson",leswidget.gettext().tostring()); datachanger.insert(datahelper.db_table,null,newwisdom); datachanger.close(); //startactivity(new Intent(this,ShowWisdom.class));

Let's look at what's new: First, see how our DataHelper actually helps us: we use it to open the database for us. If we want to make changes, get a writable database; otherwise get a readable one The way we encapsulate field values within a record is as a ContentValues We aren't explicitly specifying the rule number here, because we'd rather SQLite handle that for us After we're done, we explicitly close the database Starting the next Activity isn't important right now. It'll just be a temporary convenience thing. Let's give it a sample run, and verify that it works. More specifically, verify that it doesn't crash for some reason. Try adding an entry or two. Viewing an entry Queries are pretty easy in SQLite. Most of you already have some experience with databases, so this should be trivial. There's one thing worth noting: when we query for a selection of records, what we'll receive will be a Cursor. In this context, a Cursor is effectively a combination of a data structure, and your position within that data structure (think: cursored lists from 1P03). If our focus were on elaborate queries, we'd cover the finer points of SQL syntax, but you already know all that, so we're going to do this the easy way: we'll query everything, and simply ignore everything that isn't the first line. Let's make a new Activity, ShowWisdom. Our layout will be as follows: <?xml version="1.0" encoding="utf-8"?> <LinearLayout 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_height="match_parent" tools:context="ca.brocku.efoxwell.a2017_sixthstage.showwisdom" android:orientation="vertical"> <TextView android:id="@+id/showrule" <TextView android:id="@+id/showsubject" <TextView android:id="@+id/showlesson" <Button android:onclick="click" </LinearLayout>

The code will be pretty easy: public class ShowWisdom extends AppCompatActivity { protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.activity_show_wisdom); query(); private void query() { String[] fields=new String[]{"rule","subject","lesson"; TextView rulwidget=(textview)findviewbyid(r.id.showrule); TextView subwidget=(textview)findviewbyid(r.id.showsubject); TextView leswidget=(textview)findviewbyid(r.id.showlesson); DataHelper dh=new DataHelper(this); SQLiteDatabase datareader=dh.getreadabledatabase(); Cursor cursor=datareader.query(datahelper.db_table,fields, null,null,null,null,null); cursor.movetofirst(); if (!cursor.isafterlast()) { rulwidget.settext(""+cursor.getint(0)); subwidget.settext(cursor.getstring(1)); leswidget.settext(cursor.getstring(2)); if (cursor!=null &&!cursor.isclosed()) cursor.close(); public void click(view v) { //startactivity(new Intent(this,BobbyTables.class)); If we did want to inspect more of the results, the Cursor can be advanced via movetonext(). You'll have good reason to look into this again very soon, so for now, ensure that you can get this simpler example working, and then work on expanding later. Deletion Selective deletion is left as an exercise for now, but let's just take a gander at the nuclear option. I had one more Activity, BobbyTables. In it, behind a confirmation button, I have this: deletedatabase(datahelper.db_name); It kills records dead. One additional observation for our 'DataHelper': note that it's very minimal. Currently, we have code for insertion in one Activity, code for viewing in another, code for deletion in another, etc. Since those are all database-related actions, it would be entirely reasonable (and normal) to shift those over into the helper class.

Give everything one last test, to see what's going on. It should be easy to see how readily expandable it is. This is ridiculous Yup, it is. Why? Because we keep shimmying back and forth between Activities. To say that's less than ideal would be an understatement. If we wanted to, we could easily create a single Activity to act as our primary launch point to other tasks. We could even put each of the tasks into separate Fragments. However, what we're really talking about is an application that has different modes, into which we'd like to jump. How would we normally expect to achieve something like that? Exactly: menus. (If we have time) Menus Menus are our default go-to whenever we have a multitude of things we could do, and a long strip of buttons would be a bit unwieldy. There are different usages for menus, but they mostly fall under one of the following: Options menus Or an Activity menu. This is what you typically have that's always available to you (e.g. the 'three dots' in the corner of the Activity), to let you switch into a different mode, or initiate an action within the current display Context menus When you 'long-press' an entry in Android, you'll sometimes bring up a popup menu. That's also Submenus known as a context menu. It provides actions or information, normally specific to the exact widget/entry you just long-pressed Sometimes you can't fit everything into a single menu (or simply don't want to). If you have multiple entries that all tie to the same topic, then you might wish to bundle them all up together, and have them appear as a collection of menu options, under a single entry in a parent menu It's worth noting that, depending on your API level, you may have different options, or even the same options but behaving differently. For example, the Action Bar (a special widget to replace the normal title bar) was added quite a while ago.

Defining a menu (Prepare for deja vu) We could use Java to programmatically generate menus, and sometimes still might if there's a specific need to warrant it, but typically we'll define the menus in XML files. The default folder for a menu is res/menu. Depending on which entry you used in Android Studio to create your Activities, you might already have this folder (along with an accompanying sample menu). If not, just create the folder. We'll create our first menu, and just call it tasks. We'll start small, and expand it later: <?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/menu_greet" android:title="about" android:icon="@mipmap/ic_launcher" </menu> For now, let's just deal with what we can do with our initial activity. We need to add two separate chunks of code: public boolean oncreateoptionsmenu(menu menu) { MenuInflater inflater=getmenuinflater(); inflater.inflate(r.menu.tasks,menu); return true; This tells it how to construct the options menu. Note that we're overriding the default behaviour of, don't. Next: public boolean onoptionsitemselected(menuitem item) { Toast.makeText(this,"Hello",Toast.LENGTH_SHORT).show(); return true; This tells it how to handle clicking on a menu item. Of course, after this, we'll be comparing against ids. Expanding the idea Let's make some changes: Our menu should have new options for the tasks we've already implemented I think I'd prefer a static class to handle those menu tasks We no longer need the buttons to start new activities (but still need two of them for confirmation)

The new menu: <?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/menu_new" android:title="add entry" <item android:id="@+id/menu_show" android:title="show entry" <item android:id="@+id/menu_drop" android:title="purge database" <item android:id="@+id/menu_greet" android:title="about" android:icon="@mipmap/ic_launcher" </menu> Our first change to MainActivity: public boolean onoptionsitemselected(menuitem item) { return ModeSwitcher.handleMenuClicky(item,this); ModeSwitcher.java: public class ModeSwitcher { public static boolean handlemenuclicky(menuitem item, Context from) { //Activity? switch (item.getitemid()) { case R.id.menu_new: from.startactivity(new Intent(from,NewWisdom.class)); ((Activity)from).finish(); break; case R.id.menu_show: from.startactivity(new Intent(from,ShowWisdom.class)); ((Activity)from).finish(); break; case R.id.menu_drop: from.startactivity(new Intent(from,BobbyTables.class)); ((Activity)from).finish(); break; case R.id.menu_greet: Toast.makeText(from,"Hello",Toast.LENGTH_SHORT).show(); break; return true; In case it isn't readily apparent, the reason I'm doing this one this way is because we're going to be simply copying the menu to each of the activities. Since the code's entirely redundant, I preferred to have it centralized. But you wouldn't normally have each Activity share the same options menu. Normally, options menus show tasks specific to the displayed Activity.

Changes to the task Activities: public boolean oncreateoptionsmenu(menu menu) { MenuInflater inflater=getmenuinflater(); inflater.inflate(r.menu.tasks,menu); return true; public boolean onoptionsitemselected(menuitem item) { return ModeSwitcher.handleMenuClicky(item,this); Of course, we just tack this onto the end of each of them. Don't forget to also remove the startactivitys from any of them that still have it. Give it a try, and see how it works. Context Menus Let's say I want to have a long press menu attached to a displayed record. If there's time, I think this might be a good excuse to finally expand on the database query slightly. Let's create one more Activity, ListWisdom. For the layout, just add a single ListView, with an id of allentries. For the code: public class ListWisdom extends AppCompatActivity { protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.activity_list_wisdom); query(); private void query() { String[] fields=new String[]{"rule","subject","lesson"; ListView lv=(listview)findviewbyid(r.id.allentries); ArrayList<String> entries=new ArrayList<>(); DataHelper dh=new DataHelper(this); SQLiteDatabase datareader=dh.getreadabledatabase(); Cursor cursor=datareader.query(datahelper.db_table,fields, null,null,null,null,null); cursor.movetofirst(); while (!cursor.isafterlast()) { entries.add(integer.tostring(cursor.getint(0))+", "+ cursor.getstring(1)+", "+cursor.getstring(2)); cursor.movetonext(); if (cursor!=null &&!cursor.isclosed()) cursor.close(); ArrayAdapter<String> adapter=new ArrayAdapter<>(this, android.r.layout.simple_list_item_1,entries);

lv.setadapter(adapter); registerforcontextmenu(lv); datareader.close(); public void oncreatecontextmenu(contextmenu menu, View v, ContextMenu.ContextMenuInfo menuinfo) { if (v.getid()==r.id.allentries) { ListView lv=(listview) v; AdapterView.AdapterContextMenuInfo cmi= (AdapterView.AdapterContextMenuInfo) menuinfo; String entry=(string)lv.getitematposition(cmi.position); menu.setheadertitle(entry); menu.add("agree"); menu.add("disagree"); public boolean oncontextitemselected(menuitem item) { Toast.makeText(this,item.getTitle(),Toast.LENGTH_SHORT).show(); return true; public boolean oncreateoptionsmenu(menu menu) { MenuInflater inflater=getmenuinflater(); inflater.inflate(r.menu.tasks,menu); return true; public boolean onoptionsitemselected(menuitem item) { return ModeSwitcher.handleMenuClicky(item,this); Some observations: When you want a context menu, it's handled nearly identically to any other menu. The difference is that you register individual widgets for menus, instead of the Activity as a whole For the sake of comparison, this menu is programmatically created. There are a few extra nifty options, but honestly if you need anything remotely complicated, you shouldn't be creating it via the Java code We're not actually making any significant use of the selected contextual command Before testing it out, remember to actually add this new entry to the menu, and add the corresponding code to the ModeSwitcher class.

Submenus And, finally, submenus. Programmatically, these can be a bit of a pain, so we'll stick to XML-defined ones. Submenus in general are very simple: they're just menus within menus. There's a quirk, but it's easy to spot: <?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/menu_new" android:title="add entry" <item android:title="query"> <menu> <item android:id="@+id/menu_show" android:title="show entry" <item android:id="@+id/menu_list" android:title="list all entries" </menu> </item> <item android:id="@+id/menu_drop" android:title="purge database" <item android:id="@+id/menu_greet" android:title="about" android:icon="@mipmap/ic_launcher" app:showasaction="ifroom" </menu> While we were at it, the About entry has also changed slightly. Of course, there are also additional menu options, like check boxes and such (use group, along with checkablebehavior), you can have the application icon appear in the corner for clicking, and with later API levels even more was added. But this is a good starting point. If you'd like to learn more, this is a good resource: https://developer.android.com/guide/topics/ui/menus.html huh... there's still space down here... Did we ever do anything about that spare button for showing a single record? Can we guess what getsupportactionbar() is for?