Android使用SQLiteOpenHelper实现离线浏览

相信在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(),界面数据也与有网时一样正常显示出来。

项目源码

猜你喜欢

转载自blog.csdn.net/Leavessilent/article/details/56837547