File caching in android

Displaying Cache data or Offline mode support in android application

Problems without caching
1. Fetching data over a network connection is an expensive operation. Sometimes due to poor network connectivity, it takes a lot of time to display result( which is a bad experience in terms of mobile application).

2. Sometimes requirement may come with offline support or to display previously fetched response when there is no internet connectivity.

Thanks to Caching mechanism. We can solve the above requirements if we cache some data.

In my project, I have used the dagger, so I have written all the code for caching in ApiModule class. If you want to skip then directly go to below link

How to enable cache
1. define cache memory size

2. Create a cache object ( provide application context )

Provide this cache object in OkHttpClient

Now we will create 2 interceptors ( onlineInterceptor and offlineInterceptor). Interceptors are a powerful mechanism that can monitor, rewrite, and retry calls.

OnlineInterceptor which will be used when the device is connected to the network

OfflineInterceptor which will be used when the device is not connected to the network

Now its time to add cache interceptor to OkHttpClient.

Finally, add OkHttpClient to Retrofit

Using this retrofit instance, we can make an API call and the caching mechanism will work.

Few points to remember

Soon I will post more articles on android, core java.
till then happy learning… 🙂

MindOrks

Our community publishes stories worth reading on Android…

Источник

How to store data locally in an Android app

Almost every app we use or develop has to store data for one purpose or another. It’s not all the same data, either — some apps need access to settings, images, and much more. The big question is how to manage this data so that your device can grab only what it needs. Luckily for developers, Android is full of ways to store data, and we’re here to run you through how they work.

For this article, we’ll discuss the different data storage techniques available to Android developers, along with sample code to get you started or to refresh your memory.

Ways to store data

Using Shared Preferences

Shared Preferences is the way to go if you’re saving primitive data as key-value pairs. It requires a key, which is a String, and the corresponding value for the said key. The value can be any of the following: a boolean, float, int, long, or another string.

Your Android device stores each app’s Shared Preferences inside of an XML file in a private directory. Apps can also have more than one Shared Preferences file, and they’re ideally used to store app preferences.

Before you can store data with shared preferences, you must first get a SharedPreferences object. There are two Context methods that you can use to retrieve a SharedPreferences object.

For when your app will have a single preferences file, and

for when your app could have multiple preferences files, or if you prefer to name your SharedPreferences instance.

On getting the SharedPreferences object, you then access its Editor using the edit() method. To actually add a value, use the Editor’s putXXX() method, where XXX is one of Boolean, String, Float, Long, Int, or StringSet. You can also remove a key-value preference pair with remove().

Finally, make sure to call the Editor’s commit() method after putting or removing values. If you don’t call commit, your changes will not be persisted.

For our sample app, we allow the user to specify a SharedPreferences filename. If the user specifies a name, we request for the SharedPreferences with that name; if not, we request the default SharedPreference object.

Unfortunately, there is no way to get a single list of all SharedPreferences files stored by your app. Instead, you will need a static list or access to the SharedPreferences name if you’re storing more than one file.

Читайте также:  Топ шутеров для слабых андроидов

You could also save your SharedPreferences names in the default file. If you need to store user preferences, you may want to use the PreferenceActivity or PreferenceFragment command. Just remember that they both use Shared Preferences, too.

Using internal storage

There are plenty of times where you may need to persist data, but you find Shared Preferences too limiting. For example, you may need to persist objects or images in Java. You might also need to persist your data logically with the file system hierarchy. This is where internal storage comes in. It is specifically for when you need to store data on the file system, but you don’t want other apps or users to have access.

This data storage is so private, in fact, that it’s deleted from the device as soon as you uninstall your app.

Using internal storage is similar to saving with any other file system. You can get references to File objects, and you can store data of virtually any type using a FileOutputStream. What sets it apart is the fact that its contents are only accessible by your app.

To get access to your internal file directory, use the Context getFilesDir() method. To create (or access) a directory within this internal file directory, use the getDir(directoryName, Context.MODE_XXX) method. The getDir() method returns a reference to a File object representing the specified directory, creating it first if it doesn’t exist.

In the sample above, if the user-specified filename is empty, we get the base internal storage directory. If the user specifies a name, we get the named directory, creating first if needed.

To read files, use your preferred file reading method. For our example, we read the complete file using a Scanner object. To read a file that’s directly within your internal storage directory (not in any subdirectory), you can use the openFileInput(fileName) method.

Similarly, to access a file for writing directly within the Internal Storage directory, use the openFileOutput(fileName) method. To save files, we use the FileOutputStream write.

As you can see in the image above, the file path is in a folder not accessible by the file manager or other apps. The only exception to this will be if you have a rooted device.

External Storage

Google has made a few key changes to external storage, beginning with Android 10 and continuing in Android 11. To give users better control over their files and cut down on clutter, apps now have scoped access to external storage by default. This means that they can tap into the specific directory on external storage and the media that the app creates.

For more information about requesting scoped directory access, check out this Android developer tutorial.

If your app tries to access a file that it did not create, you will have to permit it to do so every single time. Data you store outside of select folders will also disappear if you delete your app.

Apps are expected to store files in one of two app-specific locations designed for the app’s specific persistent files and cached files, respectively. To access these locations, the app must verify the storage is available (which is not guaranteed, as it is for internal storage). The volume’s state can be queried using:

If MEDIA_MOUNTED is returned, that means you can read and write files to external storage. You will find a number of predefined directories that should aid with logical storage and prevent clutter. These include the likes of DIRECTORY_DOCUMENTS and DIRECTORY_MOVIES.

You can read a full explanation of how to use scoped storage here.

SQLite database

Finally, Android provides support for apps to use SQLite databases for data storage. The databases you create remain specific to your app and can only be accessed inside your app. Of course, you should have at least some knowledge of SQL before you attempt to store data with an SQLite database.

We’ll discuss each of these in turn, and we use data binding techniques for our sample code. Android provides complete support for SQLite databases. The recommended way of creating SQLite databases is to subclass the SQLiteOpenHelper class and override the onCreate() method. For this sample, we create a single table.

Источник

Caching in the Android Build Process

Table of Contents

So what is Gradle?

Android Studio includes a powerful code editor and developer tools but rather than reinventing the wheel and managing a project’s build process as well, it delegates to an existing build automation tool: Gradle. At a high level, Grade’s build process includes compiling your source code into Dalvik bytecode (.dex files) and compiled resources, then combining the compiled files into an APK, and finally signing the APK. Each step is configurable, and all the Gradle-related files you see in an Android project — build.gradle , gradle.properties , etc — are used to customize and configure the project’s build.

Читайте также:  Увеличивает скорость работы android

Gradle is flexible enough to build almost any type of software, and can be used for specific project types by adding a layer of conventions and prebuilt functionality through plugins. Android Studio uses the Android Gradle plugin, which adds features specific to the app build process. For example, you probably have a buildTypes block in your project’s build.gradle file, which doesn’t exist in the base Gradle API but is used by the Android Gradle plugin to support building different versions (debug, release, etc) of your app from a single project.

You can see which version of Gradle you’re using by looking at the dependencies block in your root-level build.gradle :

Since Gradle and the Android plugin run independently of Android Studio, you can build and run your app from the command line as well, by using various ./gradlew command-line commands. In Gradle, a task represents one piece of work you may do on a project, for example running tests ( ./gradlew test ) or generating Javadoc ( ./gradlew javadoc ). They can have dependencies on other tasks. You can see all the tasks available for your project by opening the Gradle panel located on Android Studio’s top right:

The interplay of code editing happening in Android Studio and app building being delegated to Gradle means there are three caching mechanisms used during the build process — the build directory, the Gradle cache, and the Android Studio system cache. This article will go over each mechanism, how they may cause build errors, and how to fix the errors.

The build directory and incremental builds

What it does

You’re probably already familiar with the build directory, which is generated whenever you build your app. The file in this directory that you will usually be most interested in is the APK file (or AAR or JAR if it’s a library module) inside the “outputs” folder, but other files created during the build process will also appear here, including any code files generated by annotation processors such as Dagger or Room, or the results of any linters you use.

The build directory usually appears at the root level of your project, although you can change where it shows up by configuring the buildDir in your root build.gradle file:

There are multiple Android Studio menu options that generate the build directory, including “Run ‘app’”, “Rebuild Project”, and “Build APK(s)”. You can also use ./gradlew assembleDebug to generate it from the command line, which runs Gradle’s assembleDebug task.

By default, Gradle uses the incremental build feature when building an Android project. This means that, before running a task, Gradle will check whether the input files have changed from the previous build. If they haven’t, it’ll reuse the output from the previous build rather than rerun the task to generate new output. In other words, Gradle uses the generated build directory as a cache, cutting down build times significantly. You can get the full benefits of this by using incremental annotation processors whenever possible. For example, if you use Room as your database library, it’s recommended that you enable its incremental annotation processing, which you can do by adding the following to your app-level build.gradle :

When you see “UP-TO-DATE” beside a task name, it means Gradle is reusing the existing build outputs rather than rerunning the task.

When and how to clear it

Unfortunately, Gradle sometimes misses code changes in input source files. For instance, you can run into problems where you updated Dagger code or a resource file but Gradle didn’t notice, and tries to reuse invalid output files from a previous build, causing the build to fail. Two common errors are “Error converting byte to dex” and “R.layout.main Cannot Be Found/Cannot Resolve Symbol R”, meaning Android Studio is having trouble generating the R.java file for resources.

Читайте также:  Xiaomi mi tv oled transparent 55 l55m6 tm fhd android

When you see a build failure that mentions a generated file from the build directory, doing a clean build is a good first step. You’ll have to run Gradle’s “clean” task, which deletes the entire build directory. This is what Android Studio’s “Build” -> “Clean Project” menu option does. The command-line equivalent is running ./gradlew clean .

The Gradle build cache

What it does

The Gradle build cache was introduced in 2017 in Gradle 4.0 and is a separate mechanism from the build directory. Since the build directory lives inside your project’s workspace, it can only be used as a cache for your current project, on your local machine. The build cache, on the other hand, stores task outputs in a local or remote build cache rather than the project workspace. By default, it’s located at

/.gradle/caches . It’s shared between any Gradle projects you work on, allowing Gradle to reuse task outputs from any earlier build of any other projects. An example where this is useful is if you have multiple projects that depend on the same external library — once Gradle downloads it while building one project, it’ll be available when Gradle builds the other project as well.

Even if you’re only working with a single Android project, the build cache can improve build times. For example, when you are switching branches back and forth, the task outputs get rebuilt over and over again, since their inputs are slightly different between different branches. Incremental builds aren’t too helpful in this case since they only cache the outputs from the most recent build. The build cache remembers the earlier build outputs, and greatly reduces the need to rebuild things when they have already been built locally several builds prior.

If you’re working on a project with a team, you can also share a remote build cache using Gradle Enterprise. This means your build may use your teammates’ build outputs instead if they’re more up-to-date than yours. A remote cache can speed up your continuous integration builds, too.

The Gradle build cache can be enabled or disabled by adding the org.gradle.caching=true/false to your gradle.properties .

When and how to clear it

The downside of using the build cache is that since it can use cached files outside of the build directory inside your project, cleaning the project no longer guarantees it’s being built from scratch; even with the build directory deleted, you can still encounter build errors caused by stale cached files.

To bypass the build cache, you can use the —no-build-cache flag. If a clean wasn’t enough to fix your build errors, try running ./gradlew clean assembleDebug —no-build-cache from the command line to both delete the local build folder and skip the Gradle cache.

Unfortunately, there’s no Android Studio menu option for bypassing the build cache on a build.

You can also delete the cache by running rm -rf $HOME/.gradle/caches/ .

Android Studio system cache

What it does

The Android Studio system cache is what gets invalidated when you click “Invalidate Caches / Restart”.

Android Studio uses it to store information about the project structure, and it’s unrelated to Gradle and the build process. Other Jetbrains IDEs use a similar cache. Generally, the Android Studio cache improves IDE performance, but over time, more and more files get cached and the cache may become overloaded. It may also store things that you never need again, for example information about a short-term project that you’re no longer working on. Note that the cache files don’t actually get deleted until Android Studio restarts.

When and how to clear it

Since the Android Studio cache stores project structure information, it can get confused if you move files around or create new XML files. You may run into errors in the code editor as a result; common ones are “Unresolved reference” and “Cannot resolve symbol”.

I’d recommend trying to rebuild the project first, since sometimes that will resolves the error and is much faster than clearing any caches. But if a rebuild doesn’t help, an “Invalidate Caches / Restart” is the way to go. I encounter these errors a lot when using ViewBindings; Android Studio sometimes misses changes in the dynamically generated bindings files.

Similarly, if you encounter a build failure after you’ve moved files around, the root cause may be stale information in the Android Studio cache rather than the Gradle caches.

Источник

Оцените статью