SoFunction
Updated on 2025-04-11

Android optimization implementation of storage optimization

Exchange data format

Protocal Buffers launched by Google is a lighter and more efficient storage structure, but consumes more memory.

FlatBuffers Also launched by Google, it focuses on performance and is suitable for mobile devices. The storage occupies more than Protocal.

SharePreferences Optimization

  • When the SharedPreferences file has not been loaded into memory, calling the getSharedPreferences method initializes the file and reads it into memory, which can easily cause longer time.
  • The difference between the commit or apply method of the Editor is synchronous write and asynchronous write, and whether the return value is required. Using the apply method can greatly improve performance without the need for a return value.
  • commitToMemory() in the SharedPreferences class locks the SharedPreference object, and the put() and getEditor() methods lock the Editor object, and even lock a write lock when writing to disk. Therefore, the best way to optimize is to avoid frequent reading and writing SharedPreferences and reduce unnecessary calls. For batch operations of SharedPreferences, it is best to get an editor for batch operations first, and then call the apply method.

Bitmap decoding

  • 4.4 The above decodeFile does not use cache internally, so the efficiency is not high. To use decodeStream, the file stream passed in is BufferedInputStream.
  • decodeResource also has performance problems, use decodeResourceStream.

Database optimization

1. Use StringBuilder instead of String

2. Return fewer result sets and fewer fields when querying

When querying, only the required fields and result sets are taken. More result sets will consume more time and memory, and more fields will cause more memory consumption.

3. Use less

The time consumption according to the observation during performance tuning is almost the same as that of the performance tuning process. You can use the static variable to remember the index of a certain column when creating a table, and directly call the corresponding index instead of each query.

4. Asynchronous threading

When there is not much data in Android, table query may not take much time and will not cause ANR. However, when it is greater than 100ms, the user will also feel delay and lag, and can be run in a thread. However, sqlite has limitations in concurrency, and multi-threading control is troublesome. At this time, a single-thread pool can be used to perform db operations in the task, and the results are returned to interact with the UI thread through handler. It will not affect the UI thread, but also prevent exceptions caused by concurrency.

5、SQLiteOpenHelper Maintain a single case

Because SQLite's support for multi-threads is not very perfect, if two threads operate the database at the same time, because the database is occupied by another thread, an exception of "Database is locked" will be reported. Therefore, using singleton pattern in database management classes can ensure that the database object is the same no matter which thread is obtained.

The best way is to unify all database operations to the same thread queue management, while the business layer uses cache synchronization, which can completely avoid the problems of out-of-synchronization and deadlock caused by multi-threaded database operation.

6. Initialization in Application

  • Use Application's Context to create a database and close it again at the end of the Application lifecycle.
  • The database is initialized first during the application startup process to avoid the increase in the relevant operation time after entering the application and then initializing it.

7. Use less AUTOINCREMENT

After adding AUTOINCREMENT to the primary key, it can ensure that the primary key is strictly incremented, but it cannot guarantee that 1 will be added every time, because after the insertion fails, the failed line number will not be multiplexed, which will cause the primary key to be separated, which will then take more than 1 times the time for INSERT.

The AUTOINCREMENT keyword will increase the burden on CPU, memory, disk space and disk I/O, so try not to use it unless necessary. Normally not required.

Transactions

Two major benefits of using transactions are atomic commits and better performance:

  • Atomic commit: means that all modifications within the same transaction are either completed or not made. If a modification fails, it will automatically roll back so that all modifications do not take effect.
  • Improved performance: Sqlite creates a transaction for each insertion and update operation by default, and submits it immediately after each insertion and update. In this way, if the data is inserted 100 times in succession, it is actually a process that creates transactions, executes statements, and submits is repeated 100 times. If a transaction is created explicitly, this process is only done once, and this one-time transaction can greatly improve performance. Especially when the database is located in the SD card, it can save about two orders of magnitude in time.

There are three main methods: beginTransaction, setTransactionSuccessful, and endTransaction.

SQLiteStatement

Using SQLiteStatement provided by the Android system to insert data has improved performance and also solved the problem of SQL injection.

SQLiteStatement statement = ().compileStatement("INSERT INTO EMPERORS(name, dynasty, start_year) values(?,?,?)"); 
();
(1, "Max"); 
(2, "Luk"); 
(3, "1998"); 
();

SQLiteStatement can only insert data in one table, and the last data must be cleared before inserting.

index

Indexes are like directories of books. Directories can quickly find the number of pages they are located in. Indexes in the database can help quickly find data without scanning the full table. Appropriate indexes can greatly improve the efficiency of database query.

Advantages: It greatly speeds up database retrieval, including single-table query, continuous table query, group query, and sort query. Often one to two orders of magnitude performance increases and increases with the order of magnitude of data.

shortcoming:

  • There is a consumption of the creation and maintenance of indexes, and the index will occupy physical space and increase with the increase in the amount of data.
  • When adding, deleting and modifying the database, the index needs to be maintained, so it will have an impact on the performance of adding, deleting and modifying.

Classification

1. Create indexes directly and create indexes indirectly

  • Direct creation: Use SQL statements to create. You can create statements directly in SQLiteOpenHelper's onCreate or onUpgrade in Android, such asCREATE INDEX mycolumn_index ON mytable (myclumn)
  • Indirect creation: Define primary key constraints or unique key constraints, and indirect indexes can be created. The primary key defaults to a unique index.

2. Normal index and unique index

  • Normal index:CREATEINDEXmycolumn_indexONmytable(myclumn)
  • Unique index: Ensure that all data in the index column is unique, and can be used for both clustered and non-clustered indexes. The statement isCREATE UNIQUE COUSTERED INDEX myclumn_cindex ON mytable(mycolumn)

3. Single index and composite index

  • Single Index: The index creation statement contains only a single field, such as the normal index and unique index creation example above.
  • Composite index: also known as a combination index, which contains multiple fields at the same time in the index creation statement, such asCREATEINDEXname_indexONusername(firstname,lastname),where firstname is the leading column.

4. Clustered index and non-clustered index (clustered index, clustered index)

  • Clustered index: physical index, the same physical order as the base table, the order of data values ​​is always arranged in order, such as CREATE CLUSTERED INDEX mycolumn_cindex ON mytable(mycolumn) WITH ALLOW_DUP_ROW,inWITH ALLOW_DUP_ROW Indicates that clustered indexes are allowed with duplicate records
  • Nonclustered index:CREATEUNCLUSTEREDINDEXmycolumn_cindexONmytable(mycolumn),The index defaults to nonclustered indexes

Use scenarios

  • When the data update frequency of a certain field is low and the query frequency is high, there are often range queries. (>, <, =,>=, <=) or order bygroup by It is recommended to use indexes when they occur. And the greater the selection degree (number of unique values ​​in a field / total number), the more advantage it is to build an index.
  • Many columns are often accessed at the same time, and each column contains duplicate values, so consider creating a composite index.

Rules of use

  1. For composite indexes, use the most frequently used column as the leading column (the first field in the index). If the leading column is not in the query condition during query, the composite index will not be used. likecreate unique index PK_GRADE_CLASS on student (grade, class)select * from student where class = 2 The index is not used,select * from dept where grade = 3Index used
  2. Avoid calculating index columns. Any calculation of where clause columns cannot be compiled and optimized will cause index failure during queryselect * from student where tochar(grade)='2
  3. Compare values ​​to avoid using NULL
  4. When querying multiple tables, you should pay attention to choosing the appropriate table as the inner table. The joining conditions should fully consider the table with indexes and tables with many rows. The selection of internal and external tables can be determined by the formula: the number of matching rows in the outer table * the number of searches in the inner table, and the minimum product is the best solution. Before the actual multi-table operation is actually executed, the query optimizer will list several possible connection solutions based on the connection conditions and find out the best solution with the lowest system overhead.
  5. Query columns and index column order are consistent
  6. Replace EXISTS clause with multi-table joins
  7. Put the condition with the largest number of filter records first
  8. Good at using stored procedures, it makes SQL more flexible and efficient (Sqlite does not support stored procedures)

Other general optimizations

  1. The frequently used data is cached after reading and reading to avoid repeated repeated reading and writing, causing "write amplification"
  2. Child thread reads and writes data
  3. When ObjectOutputStream is serialized, each object in memory will be saved to disk. When saving the object, each data member will bring an I/O operation. Encapsulate an output stream ByteArrayOutputStream or BufferedOutputStream on the ObjectOutputStream. First write the serialized information into the cache area, and then write it to disk one after another; accordingly, use ByteArrayInputStream or BufferedInputStream instead of ObjectInputStream.
  4. Reasonably select the size of the buffer buffer. Too small leads to an increase in the number of I/O operations, and too large leads to a longer application time. For example, 4-8 KB.

The above is all the content of this article. I hope it will be helpful to everyone's study and I hope everyone will support me more.