Android使用SQLiteOpenHelper实现离线浏览

来源:互联网 发布:mac arp 嗅探工具dmg 编辑:程序博客网 时间:2024/05/01 09:40

相信在Android开发中,很多APP都会用到数据库来保存数据,今天我们来讨论一下它其中用法,用数据库实现离线浏览。数据库类型很多,Android默认是使用SQLite。

首先我们来看一下界面

这里写图片描述

很简单,经典的图文混排。

要想实现APP离线浏览,我们需要:

  • 创建一个类继承SQLiteOpenHelper(该类帮我们封装好了很多数据库操作)
  • 将功能抽象出来
  • 创建数据库管理类
  • 使用我们创建的数据库来实现离线浏览。

首先我们根据模型类来创建SQLiteOpenHelper

模型类

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) {    }}

这里主要要实现的方法是onCreate,在里面完成我们的初始化建表工作,构造函数需要传入的四个参数分别为:上下文、数据库名、游标工厂(默认为null)、版本号。onUpgrade方法 只会在数据库更新才会调用。这里我们不会用到。

将功能抽象出来

public interface INewsDB {    List<News> getAllNews();    void deleteAllNews();    News getNewsById(int id);    void insertAllNews(List<News> newsList);    void insertNews(News news);}

这里首先说一下为什么要创建这么一个接口,很简单,解耦合,以后维护修改的时候方便。抽象出来的这些功能都是我们后面将用到的,都是基本的增删改查操作。

创建数据库管理类(重点)

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()});    }}

解析一下代码:这里我们创建一个News数据库管理类,专门进行数据库的增删改查操作,实现INewsDB抽象的功能。增删改查的代码就不多解释了,这里注意一下delete操作,Android的delete有一个蜜汁bug,本来数据库的删除操作应该是delete * from table,但是这个 * 无法通过编译,所以只能delete from table。

实际运用

好了,终于到最后一步了,有木有很激动。

    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);    }

最后再来看看调试结果

这里写图片描述

根据log可知,没网时,最后走了getDataFromDB(),界面数据也与有网时一样正常显示出来。

项目源码

1 0