Android uses SQLiteOpenHelper to realize offline browsing

I believe that in Android development, many apps will use the database to save data. Today we will discuss its usage and use the database to realize offline browsing. There are many types of databases, and Android uses SQLite by default.

First let's look at the interface

Write picture description here

Very simple, classic mixed graphics and text.

To realize APP offline browsing, we need:

  • Create a class that inherits SQLiteOpenHelper (this class helps us encapsulate many database operations)
  • abstract the functionality
  • Create database management class
  • Use the database we created for offline browsing.

First we create SQLiteOpenHelper based on the model class

model class

public class News {
    private int id;
    private String title;
    private String postdate;
    private String editor;
    private String icon;

    public News(int id, String title, String postdate, String editor, String icon) {
        this.id = id;
        this.title = title;
        this.postdate = postdate;
        this.editor = editor;
        this.icon = icon;
    }

   // getter and setter ...
}

public class NewsSQLiteOpenHelper extends SQLiteOpenHelper {
    
    

    // 数据库名
    private static final String NAME = "learn.db";
    // 数据库版本
    private static final int VERSION = 1;
    // 建表语句
    private static final String CREATE_NEWS = "create table if not exists news(" +
            "_id integer primary key," +
            "title text," +
            // 这个时间字段只是单纯的为了后面查询时好排序
            "time integer," +
            "icon text," +
            "editor text," +
            "postdate text)";

    public NewsSQLiteOpenHelper(Context context) {
        super(context, NAME, null, VERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL(CREATE_NEWS);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

    }
}

The main method to be implemented here is onCreate, which completes our initialization and table creation work. The four parameters that the constructor needs to pass in are: context, database name, cursor factory (null by default), and version number. The onUpgrade method will only be called when the database is updated. We won't use it here.

abstract the functionality

public interface INewsDB {
    List<News> getAllNews();

    void deleteAllNews();

    News getNewsById(int id);

    void insertAllNews(List<News> newsList);

    void insertNews(News news);

}

Let me first talk about why such an interface is created. It is very simple, decoupled, and convenient for maintenance and modification in the future. These abstracted functions are what we will use later, and they are all basic addition, deletion, modification and query operations.

Create a database management class (emphasis)


public class NewsDBManager implements INewsDB {
    
    

    private static NewsDBManager sManager;

    private NewsSQLiteOpenHelper mHelper;

    private NewsDBManager(Context context) {
        mHelper = new NewsSQLiteOpenHelper(context);
    }

    public static NewsDBManager getInstance(Context context) {
        if (sManager == null) {
            synchronized (NewsDBManager.class) {
                if (sManager == null) {
                    sManager = new NewsDBManager(context);
                }
            }
        }
        return sManager;
    }

    /**
     * 查询所有新闻
     *
     * @return
     */
    @Override
    public List<News> getAllNews() {
        SQLiteDatabase db = mHelper.getReadableDatabase();
        Cursor cursor = db.rawQuery("select * from news order by time    ASC", null);
        List<News> newsList = new ArrayList<>();
        while (cursor.moveToNext()) {
            int id = cursor.getInt(cursor.getColumnIndex("_id"));
            String title = cursor.getString(cursor.getColumnIndex("title"));
            String icon = cursor.getString(cursor.getColumnIndex("icon"));
            String editor = cursor.getString(cursor.getColumnIndex("editor"));
            String postdate = cursor.getString(cursor.getColumnIndex("postdate"));

            News news = new News(id, title, postdate, editor, icon);
            newsList.add(news);
        }
        mHelper.close();
        return newsList;
    }

    /**
     * 删除所有新闻
     */
    @Override
    public void deleteAllNews() {
        SQLiteDatabase db = mHelper.getWritableDatabase();
        db.execSQL("delete from news");
        mHelper.close();
    }

    /**
     * 通过给定的id获取新闻
     *
     * @param id
     * @return
     */
    @Override
    public News getNewsById(int id) {
        SQLiteDatabase db = mHelper.getReadableDatabase();
        Cursor cursor = db.rawQuery("select * from news where _id = ?", new String[]{String.valueOf(id)});
        cursor.moveToNext();
        String title = cursor.getString(cursor.getColumnIndex("title"));
        String icon = cursor.getString(cursor.getColumnIndex("icon"));
        String editor = cursor.getString(cursor.getColumnIndex("editor"));
        String postdate = cursor.getString(cursor.getColumnIndex("postdate"));

        News news = new News(id, title, postdate, editor, icon);
        mHelper.close();
        return news;
    }

    @Override
    public void insertAllNews(List<News> newsList) {
        for (News news : newsList) {
            insertNews(news);
        }
    }

    @Override
    public void insertNews(News news) {
        SQLiteDatabase db = mHelper.getWritableDatabase();
        db.execSQL("insert into news(_id,title,time,icon,editor,postdate) values(?,?,?,?,?,?)", new Object[]{news.getId(), news.getTitle(), System.currentTimeMillis(), news.getIcon(), news.getEditor(), news.getPostdate()});
    }
}

Let’s analyze the code: here we create a News database management class, which is dedicated to adding, deleting, modifying and querying the database to realize the abstract function of INewsDB. I won’t explain much about the code for adding, deleting, modifying and checking. Here, pay attention to the delete operation. Android’s delete has a honey bug. The original database delete operation should be delete * from table, but this * cannot be compiled, so it can only delete from table.

practical use

Well, it's finally the last step, so I'm very excited.


    private void initView() {
        mNewsRv = ((RecyclerView) findViewById(R.id.rv_news));
        mLoading = findViewById(R.id.pb_loading);

        LinearLayoutManager layout = new LinearLayoutManager(this);
        mNewsRv.setLayoutManager(layout);
        mAdapter = new NewsAdapter(this, null);
        mNewsRv.setAdapter(mAdapter);

        mLoading.setVisibility(View.VISIBLE);
        // 加载数据的时候先检测网络
        if (NetworkUtils.checkNetworkState(this)) {
            Log.d(TAG, "initView: 从网络获取数据");
            getDataFromInternet();
        } else {
            Log.d(TAG, "initView: 从数据库获取数据");
            getDataFromDB();
        }
    }


    private void getDataFromInternet() {
        HttpUtils.getAsynString(Urls.URL_NEWS_ITEM_SOFTWARE, new HttpUtils.ResultCallback() {
            @Override
            public void onFailure(Exception e) {
                Toast.makeText(MainActivity.this, e.getMessage(), Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onFinish(String result) {
                Gson gson = new Gson();
                List<News> data = gson.fromJson(result, new TypeToken<List<News>>() {
                }.getType());
                mAdapter.update(data);
                NewsDBManager manager = NewsDBManager.getInstance(MainActivity.this);
                // 删除旧数据,保存最新数据
                manager.deleteAllNews();
                manager.insertAllNews(data);
                mLoading.setVisibility(View.GONE);
            }
        });
    }


    private void getDataFromDB() {
        NewsDBManager manager = NewsDBManager.getInstance(this);
        List<News> data = manager.getAllNews();
        if (data.size() > 0) {
            mAdapter.update(data);
        }
        mLoading.setVisibility(View.GONE);
    }

Finally, let's look at the debugging results

Write picture description here

According to the log, when there is no network, getDataFromDB() is used at the end, and the interface data is displayed normally as when there is a network.

Project source code

Guess you like

Origin blog.csdn.net/Leavessilent/article/details/56837547