Coding With Fun
Home Docker Django Node.js Articles Python pip guide FAQ Policy

Chapter 10 Application Data


May 21, 2021 Android SDK Getting started


Table of contents


Chapter 10 Application Data

We are already familiar with the structure and basic components of Android applications, including resources, manifests, and user interfaces. A fter embarking on the development of a functional application for the Android platform, you will certainly need to save data information in one way or the other. The Android platform offers a variety of options for processing data storage tasks in the app, which is at the heart of today's article.

Broadly speaking, there are five main types of data storage options in Android apps: save data in your app's sharing preferences, save it in internal storage (exclusive to the app itself), save it in external storage (exposed to devices), save it in a database, and save it in Web resources that can be accessed over your device's Internet connection. Limited by space, we can't discuss these options in detail, but we summarize the underlying characteristics of each scenario to help you figure out how to solve storage problems when you need persistent data.

1. Share preferences

The first step

Shared preferences allow people to save basic data types as key-value pairs. A n application's shared preference file is often considered the simplest data storage option, but it essentially places some restrictions on the object being stored. I t allows you to store basic type numbers such as integers, long numbers, and floating-point numbers, Boolean values, and text strings. W e need to assign a name to each value we save so that we can retrieve it as the application runs. Because shared preferences are likely to be used in the first app you create, we help you consolidate the necessary knowledge by making it the focus of our presentation and expressing it in a more detailed way than other options.

You can try this code in your main Acty class and test it later when you run the app samples for this series of tutorials. I deally, sharing preferences should match the user configuration options in the application, just as you would a skin setting. A s you should recall, we created a simple button that shows "Ouch" text content on the screen after the user clicks on it. N ow let's assume that you want the user to keep the word "Ouch" on the button after one click, and that the state remains the same while the application is running. This means that the initial text on the button exists only before the user's first click.

Let's add shared preferences to the app. Before the class starts, before the onCreate method, we choose a name for the sharing preference:

public static final String MY_APP_PREFS = "MyAppPrefs"

With the "public static" modifier, we can access this variable in any class within the app, so we just need to save the preference name string here. W e use capital because the variable is a constant, and so does the "final" modifier. Everyone must use the same name each time you retrieve or set a data entry in your application preferences.

Step two

Now let's write shared preferences. In our onClick method, below the text settings section of the button "Ouch", try to get this shared preference back by name:

SharedPreferences thePrefs = getSharedPreferences(MY_APP_PREFS, 0);

You need to add an import to the "android.conent.SharedPreferences" class. H over over the SharedPreferences text and use eclipse prompts to complete the import. The first parameter is the preferred name we define, and the second is our basic pattern as the default option.

Now we need to specify a set of editors for shared preferences to set the values in them:

SharedPreferences.Editor prefsEd = thePrefs.edit();

Now we can write values to shared preferences:

prefsEd.putBoolean("btnPressed", true);

Here we use the Boolean type because the current state is divided into two types - the user has pressed or has not pressed the button. T he editor offers a variety of different types from which we can choose to preserve this set of sharing preferences, each with its own name and value parameters. Finally, we need to submit the edits:

prefsEd.commit();

Step three

Now let's use the saved values to detect what the button should show after the user runs the application. Add shared preferences after the existing code in onCreate:

SharedPreferences thePrefs = getSharedPreferences(MY_APP_PREFS, 0);

This time we don't have to use the editor because we just need to get a value:

boolean pressed = thePrefs.getBoolean("btnPressed", false);

Now we retrieve the value with the name we've set and read the results in the variable. I f the value has not been set, the second argument returned, the default value, represents a negative meaning. Now let's use this value:

if(pressed) theButton.setText("Ouch");

If the user presses the button after the application runs, the button displays the word "Ouch" directly. I n subsequent articles in this series, you'll see how we do this while the app is running. T his simple example is a good illustration of the use of shared preferences. You'll find that sharing preferences play an important role in helping applications match user preferences through appearance and usage.

2. Private internal files

The first step

You can save files in the internal and external storage of the user's device. I f you save a file in internal storage, Android treats it as private data that is exclusive to the current app. S uch files are essentially part of the application and cannot be accessed directly outside the application. Again, if the application is removed, the files are emptied at the same time.

You can create a file in memory storage using the following output routines:

FileOutputStream fileOut = openFileOutput("my_file", Context.MODE_PRIVATE);

You need to import the "java.io.FileOutputStream" class. W e provide a file name and pattern, and choosing a private mode means that the file will only be used by the application. I f you add this code toActivity now, such as the onClick method, Eclipse will pop up the error prompt. T his is because when we do input/output operations, the application may encounter some errors that need to be addressed. I f everyone's input/output operations do not resolve such errors, Eclipse will prompt for an abnormal condition and the application will abort. To ensure that the application still works in this situation, we need to encapsulate our own input/output code in a try block:

try{
    FileOutputStream fileOut = openFileOutput("my_file", Context.MODE_PRIVATE);
}
catch(IOException ioe){ 
    Log.e("APP_TAG", "IO Exception", ioe);
}

If the input/output operation causes an exception, the above code in the catch block is executed to write the error message to the log. Y ou'll often use the Log class in your application in the future (import 'android.util.Log'), which records what happens when the code is executed. W e can define a class variable for the string label, which is the first argument in the code above. This allows you to view exception information in Android LogCat in the event of an error.

Step two

Now back to the try block, after you've created the file output routine, you can try writing the following code to the file:

String fileContent = "my data file content"
fileOut.write(fileContent.getBytes());

After you're writing everything you need to the data file, end with the following code:

fileOut.close();

Step three

When you need to retrieve the contents of an internal file, you can do so through the following process:

try{
    FileInputStream fileIn = openFileInput("my_file");
    //read the file
}
catch(IOException ioe){ 
    Log.e("APP_TAG", "IO Exception", ioe);
}

In the try block, use the buffer reader to read the contents of the file:

InputStreamReader streamIn = new InputStreamReader(fileIn);
BufferedReader fileRead = new BufferedReader(streamIn);
StringBuilder fileBuild = new StringBuilder("");
String fileLine=fileRead.readLine();
while(fileLine!=null){
    fileBuild.append(fileLine+"\n");
    fileLine=fileRead.readLine();
}
String fileText = fileBuild.toString();
streamIn.close();

Don't be intimidated by the large number of different objects involved, which is actually a standard Java input/output operation. O ne of the while loops is executed once on each line of the file. When the execution is complete, the fileText variable saves the contents of the file as a string for our direct use.

Public external documents

The first step

Our applications can also store files in external storage as long as the user device supports them. T here is a wide variety of external storage, including SD cards, other portable media, or memory storage mechanisms that users cannot remove but are considered external types by the system. When we save a file in external storage, its contents are completely public and no one can prevent users or other apps from accessing it in any way.

Before we try to save data in external storage, we must first check that the corresponding storage mechanism is available -- it's definitely a good habit to try to avoid unexpected situations:

String extStorageState = Environment.getExternalStorageState();

The information is returned as a string that you can analyze and compare to the external storage state fields in the Environment class:

if(Environment.MEDIA_MOUNTED.equals(extStorageState)){
    //ok to go ahead and read/ write to external storage
}
else if(Environment.MEDIA_MOUNTED_READ_ONLY.equals(extStorageState)){
    //can only read
}
else{
    //cannot read or write
}

Even if external storage does exist on the device, we cannot preconsume that the app can write data to it.

Step two

After confirming that we were indeed able to write data to the external storage, we then need to retrieve the directory to specify where the file was saved. The following application settings point to eight levels and higher APIs:

File myFile = new File(getExternalFilesDir(null), "MyFile.txt");

This allows you to write and read the file. But don't forget to add the following to your project's inventory file:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

As the applications we develop become more complex, you may want to share your saved files with other applications. In this case, you can use a variety of generic entries in the public directory, such as pictures and music files.

4. Database

As our applications involve more and more complex structural data, sharing preferences or internal/external files may not be able to meet the actual needs, so it's time to consider using a database scenario. A ndroid enables developers to create and access the SQLite database within the application. When we create a set of databases, it will serve the application as a private component service.

There are a variety of ways to take advantage of the SQLite database in Android applications, and it is recommended that you use the class that extends SQLiteOpenHelper to achieve this requirement. In this class, we need to define database properties, create various class variables, including the database list name we define and its SQL creation string, as follows:

private static final String NOTE_TABLE_CREATE = 
    "CREATE TABLE Note (noteID INTEGER PRIMARY KEY AUTOINCREMENT, " +
    "noteTxt TEXT);";

The example given here relates to a very simple set of tables with two columns, one with ID and the other with text, both of which are used to record user comment information. I n the SQLite OpenHelper class, you can rewrite the onCreate method to create your own database. In other parts of the application, such as theActivity class, access to the database can be achieved through SQLiteOpenHelper, new records are inserted using the WeritableDatabase method, existing records are queried using the getReadAbleDatabase method, and the results are displayed in the application UI.

As we iterate on the results of the query, our application uses the Cursor class, which refers in turn to each row in the result set.

Internet data

Many applications use Internet data resources, and some applications are even largely composed of a set of interfaces and a large number of Web data sources. Y ou can use the Internet connection on the user's device to store and retrieve data from the Web, as long as the network connection is effective, this mechanism can function properly. To do this, we need to add "android.permission.INTERNET" permissions to our manifest file.

If we want our app to be able to get data from the Internet, we must ensure that the process is removed from the app's main UI thread. With AsyncTask, you can get data from a Web source through a background process, write the results to the UI after the data download is complete, and finally let the UI perform its functions normally.

You can also add an internal AsyncTask class to the Actity class and create an AsyncTask instance in ThatActivity when you need to get data. By introducing doInBackground and onPostExecute into AsyncTask, you can retrieve the data obtained in Actity and write it to the user interface.

Getting Web data is a medium-difficult task in application development, and it's best to try it after you've mastered Android development. H owever, you may soon find that such a data acquisition mechanism is ideal for many applications because it makes efficient use of the connection resources of the user's device. Both Java and Android provide tools to process returned structured data, such as JSON feeds.

Conclusion

In today's article, we get a basic understanding of the data storage scenarios that you need to be exposed to when developing Android applications. R egardless of which scenario you choose in the end, you should use actual requirements as a reference criterion, because different scenarios are only suitable for specific needs. I n the next installed part of this series of tutorials, we'll explore how to connect physical devices to installed Eclipses and learn how to create virtual devices. A fter that, we'll also explore how to get your application to run on both types of devices. By the way, two more articles in this tutorial series will be over, and in the last article, we'll look at generic classes and the Android Activity lifecycle to help you get ready to develop your application.