IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Android入门系列(八):预定义、自定义Content Provider和SQLite的基本使用 -> 正文阅读

[移动开发]Android入门系列(八):预定义、自定义Content Provider和SQLite的基本使用

一、Content provider概述

Content provider即数据模型,在android中作为数据存放的容器,包含增删改查,看上去和sql有点类似,但它屏蔽了数据存储的细节,更加透明化,用户只需要关心uri即可,并且它支持不同Android应用程序之间的数据共享,操作起来更加方便

每个类型的Content provider只有一个单独的实例,用于多个进程ContentResolver类之间通信

数据模型类似于sql的存放方式,每一排代表一条记录,每一列代表类型

每一个content通过uri保存数据集,所有为provider提供的uri都是

content://com.xxxx.xxx/xxx/xxx

Android开发提供了各种URI,uri可以作为参数被访问

请求多条记录只需要指定uri的内容即可

二、预定义Content provider

安卓系统对常见的内容提供了预定的Content provider,例如声音,视频,联系人等

1.查询

要实现查询操作,先标识uri,再提供查询字段名称和数据类型,如果是特定的值,还需要提供id值

查询方法通过ContentResolver.query或者Activity.managedQuey方法,返回值为Cursor对象,即为查找内容的一个集合

public final Cursor query (Uri uri,String[] projection,String[] selection,String[] selectArgs,String sortOrder)

uri是provider的uri

projection是返回的数据列名称。null表示返回全部列,可以使用android预定义的常量,如果是自定义常量需要将名字定义在string数组中

selection是返回的行的指定,类似于WHERE语句。null表示全部返回行、

selectionArgs是替换掉selection参数中的问题

Cursor cursor = contentResolver
    .query(android.provider.ContactsContract.Contacts.CONTENT_URI
           ,new String[]{ContactsContract.Contacts._ID}
           ,ContactsContract.Contacts.DISPLAY_NAME + "=?"
           ,new String[]{"张三"}
           ,null)

sortOrder即为排序方式,null表示默认返回的可能为无序的

2.增加记录

通过inset方法

Cursor cursor = contentResolver.insert(Uri uri,ContentValues values)

ContentValues是通过k-v键值对存放列名-值,返回的对象即为修改后的URI

3.增加新值

调用以byte数组作为参数的ContentValues.put()方法向表格中增加少量的二进制数据,适用于小图片视频等。如果是大量的二进制数据,需要保存代表数据的content:URI到表格,使用文件URI调用ContentResolver.openOutputStream()方法

4.更新记录

Cursor cursor = contentResolver.update(Uri uri,ContentValues values,String where,String[] selectionArgs)

values为键值对,where过滤,selectionArgs替换问好

5.删除记录

Cursor cursor = contentResolver.delete(Uri uri,String where,String[] selectionArgs)

6.查询电话实例

package com.thundersoft.session6;

import android.app.Activity;
import android.content.ContentResolver;
import android.database.Cursor;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.widget.LinearLayout;
import android.widget.TextView;

import androidx.annotation.Nullable;

public class ProviderActivity extends Activity {
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        LinearLayout linearLayout = new LinearLayout(this);
        setContentView(linearLayout);
        TextView textView = new TextView(this);

        String[] columns = {ContactsContract.Contacts._ID,ContactsContract.Contacts.DISPLAY_NAME};
        StringBuilder stringBuilder = new StringBuilder();
        ContentResolver contentResolver = getContentResolver();
        Cursor cursor = contentResolver.query(ContactsContract.Contacts.CONTENT_URI, columns, null, null, null);

        int index0 = cursor.getColumnIndex(columns[0]);
        int index1 = cursor.getColumnIndex(columns[1]);
        for (cursor.moveToFirst();!cursor.isAfterLast();cursor.moveToNext()){
            int index0i = cursor.getInt(index0);
            String index1s = cursor.getString(index1);
            stringBuilder.append(index0i + ": "+ index1s + "\n");
        }
        cursor.close();

        textView.setText(stringBuilder.toString());
        linearLayout.addView(textView);
    }
}

通过查到cursor,获得索引,接着将索引值给cursor获取,遍历这个操作

不要忘记了在SVD中设置权限

这里是最简单的查询,通过columns数组只需要对一个表进行查询

如果需要同时将电话号记录下来,需要用到另外一张预定义的Provider表

即ContactsContract.CommonDataKinds.Phone.CONTENT_URI

通过这张表和上述代码中的表建立联合查询,代码如下

package com.thundersoft.session6;

import android.app.Activity;
import android.content.ContentResolver;
import android.database.Cursor;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.widget.LinearLayout;
import android.widget.TextView;

import androidx.annotation.Nullable;

public class Provider2Activity extends Activity {
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        LinearLayout linearLayout = new LinearLayout(this);
        setContentView(linearLayout);
        TextView textView = new TextView(this);

        String[] columns = {ContactsContract.Contacts._ID,ContactsContract.Contacts.DISPLAY_NAME
        ,ContactsContract.CommonDataKinds.Phone.NUMBER,ContactsContract.CommonDataKinds.Phone.CONTACT_ID};
        StringBuilder stringBuilder = new StringBuilder();
        ContentResolver contentResolver = getContentResolver();
        Cursor cursor = contentResolver.query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null);

        while (cursor.moveToNext()){
            int idIndex = cursor.getColumnIndex(columns[0]);
            int nameIndex = cursor.getColumnIndex(columns[1]);
            int id = cursor.getInt(idIndex);
            String name = cursor.getString(nameIndex);
            Cursor phone = contentResolver.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, columns[3] + "=" + id, null, null);
            while (phone.moveToNext()){
                int phoneNumIndex = phone.getColumnIndex(columns[2]);
                String phoneNum = phone.getString(phoneNumIndex);
                stringBuilder.append(name + ": " + phoneNum + "\n");
            }
        }
        cursor.close();

        textView.setText(stringBuilder.toString());
        linearLayout.addView(textView);
    }
}

这里查询的结果就包含了电话号码信息

三、自定义Content provider

如果需要自定义Content Provider,可以通过Android文件的存储方式,或者是SQLite数据库保存数据

Android提供SQLiteOpenHelper类帮忙创建数据库,SQLiteDatabase类帮忙管理数据库

访问数据通过继承ContentProvider类,同时还要再清单文件里声明

1.继承ContentProivder类

需要实现方法如下

在这里插入图片描述

使用ContentProivder的Cursor类来共享数据,六个方法的说明如下

onCreate:初始化provider

insert/delete/update/query:curd

getType:返回数据到MIME类型

查找必须要返回Cursor对象,用于遍历,它自身是一个接口,SQLiteCursor可以遍历存储在SQLite数据库中的数据

2.声明Content Provider

声明了对于Android系统才是可见的

Name属性是ContentProvider类子类的完整名称

authorities属性是provider定义的content:URI中authority部分

<provider
    android:authorities="com.thundersoft.session6.providerActivity"
    android:name=".Provider2Activity"/

其它的provider属性能设置读写数据的权限,现实的图标文本、启用禁用provider等

如果要同步多个同时运行的ContentProvider,需要设置multiprocess为true

这允许各个客户端进程传进一个provider实例,避免IPC

五、实践

1.要求

实现一个登录页面,提供记住密码和用户名功能,登陆后显示列表视图必须包含登录用户名,且点击列表会显示点击那一项

登录后主界面列表选择第一个选项后,显示一组图片,图片加载完成前需要显示进度条,加载完成后,长按某一个图片弹出提示框是否删除,如果确定就不再显示该图片

登录后主界面列表选择第二个选项后,跳转到另一个Activity,并且传过去一个字符串,在新的Activity中包含2个Fragment,左边的Fragment类似手机设置,含一个亮度设置选项,点击后右边的Fragment显示具体的亮度设置界面

登录后主界面列表选择第三个选项后,跳转到另一个Activity,并且传过去int/byte/Serializable等多种类型的数据,在新的Activity中显示传入的数据,检查是否所传所有类型的数据都正确接收,同时在Activity启动的时候开始监听android.net.conn.CONNECTIVITY_CHANGE,Activity退出后不再监听,当网络状态改变的时候提示用户网络状态改变情况。

登录后主界面列选择第四个选项后,跳转到另一个Activity,运用本章学习的资源、样式等知识,实现Activity中显示类似自己手机设置列表的效果(跟进到自己手机的设置界面一样)

(以上是Android 六 当中的实践要求)

登录后主界面列表选择第五个选项后,跳转到另一个Activity显示记账本,其含一个 记账项输入、金额输入、添加按钮和一个列表,添加记账功能往自定义Content Provider写入,数据可以存储在自定义数据库,或者xml文件里,或者最简单的存在列表变量里面;

2.代码实现

intent的就写在这里了

bill.xml布局文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="记账本"
        android:gravity="center"
        android:textSize="30dp"/>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal">
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:textSize="20dp"
                android:text="请输入金额:"/>
            <EditText
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_weight="7"
                android:id="@+id/money"/>
            <Button
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="确定"
                android:layout_weight="1"
                android:id="@+id/submit"/>
        </LinearLayout>
        <ListView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:id="@+id/bill"/>
    </LinearLayout>
</LinearLayout>

通过点击获取edittext里的内容

DBManager.java

package com.thundersoft.login;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

public class DBManager extends SQLiteOpenHelper {
    public static final String DATABASE_NAME = "michilay.db";
    private static final String CREATE_TABLE =
            "create table michilay (time varchar(60),money varchar(20));";

    public DBManager(Context context) {
        super(context, DATABASE_NAME, null, 1);
    }

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

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

    }
}

DBManager继承SQLiteOpenHelper,定义了数据库的名称michilay.db以及表的名称和结构create table michilay (time varchar(60),money varchar(20));

BillProvider.java

package com.thundersoft.login;

import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;



public class BillProvider extends ContentProvider {
    //声明UriMatcher对象
    private static final UriMatcher MATCHER = new UriMatcher(UriMatcher.NO_MATCH);
    //声明并初始化权限
    private static String authority = "com.thundersoft.login.billProvider";
    //初始化匹配码
    private static final int USER_CODE = 1;
    //声明数据库
    private DBManager myDataBase;
    //声明管理数据库
    private SQLiteDatabase db;

    //当MATCHER调用match()方法时,会进行匹配,并返回相应的自定义匹配码,根据匹配码进行操作
    static {
        MATCHER.addURI(authority, null, USER_CODE);
    }

    //创建或者打开数据库,只执行一次。当指定数据库名的数据库不存在时,创建新的数据库,当存在时,打开已有数据库
    @Override
    public boolean onCreate() {
        myDataBase = new DBManager(getContext());
        return true;
    }

    @Nullable
    @Override
    public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) {
        db = myDataBase.getWritableDatabase();
        return db.query("michilay", new String[]{"time","money"}, null, null, null, null, sortOrder);
    }

    @Nullable
    @Override
    public String getType(@NonNull Uri uri) {
        return null;
    }

    @Nullable
    @Override
    public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
        db = myDataBase.getWritableDatabase();
        db.insert("michilay",null,values);
        db.close();
        return null;
    }

    @Override
    public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
        return 0;
    }

    @Override
    public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) {
        return 0;
    }
}

这里自定义了一个ContentProvider,只对provider的查找和增加进行了编写

query方法返回的是一个cursor,起初想使用java集合来存储数据保存在cursor,很难行得通,比较常用的方法就是结合SQLite数据库的查询语句,返回的刚好是一个cursor(Android给你的能不好用吗)

insert方法返回的是一个uri,不需要在意,只需要在这个方法里对数据库进行增加操作,insert方法也是Android封装好的

注意操作时候db = myDataBase.getWritableDatabase();别忘了

使用了自定义Provider后一定要进行声明

<provider
    android:authorities="com.thundersoft.login.billProvider"
    android:name="com.thundersoft.login.BillProvider"
    android:exported="true"/>

name为类的名字,authorities为uri,小写开头

BillActivity.java

package com.thundersoft.login;

import android.app.Activity;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;

import androidx.annotation.Nullable;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class BillActivity extends Activity {

    private final String[] columns = {"time","money"};
    private Uri uri = Uri.parse("content://com.thundersoft.login.billProvider");
    private List<String> list = new ArrayList<>();

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.bill);
        EditText money = findViewById(R.id.money);
        Button button = findViewById(R.id.submit);
        ListView bill= findViewById(R.id.bill);

        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String s = money.getText().toString();
                list.clear();
//                add
                if (s != ""){
                    ContentResolver resolver = getContentResolver();
                    ContentValues contentValues = new ContentValues();

                    SimpleDateFormat formatter= new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                    Date date = new Date(System.currentTimeMillis());

                    contentValues.put("time",formatter.format(date));
                    contentValues.put("money",s);
                    Log.i("bill","target------------->" + contentValues.get("time") +"||"+ contentValues.get("money"));
                    resolver.insert(uri,contentValues);
//                query
                    Cursor cursor = resolver.query(uri, null, null, null, null);
                    while (cursor.moveToNext()){
                        int columnIndex = cursor.getColumnIndex(columns[0]);
                        int columnIndex1 = cursor.getColumnIndex(columns[1]);
                        String string = cursor.getString(columnIndex);
                        String string1 = cursor.getString(columnIndex1);
                        list.add(string + "   花费    " + string1);
                    }
                    ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(BillActivity.this, android.R.layout.simple_list_item_1, list);
                    bill.setAdapter(arrayAdapter);
                    cursor.close();
                }
            }
        });
    }
}

主程序中,每次点击都要进行list.clear操作,因为setadapter会将adapter中的list给加在后面而不是替换

通过对edittext和data类获取数据放在ContentValues对象中,以k-v的形式保存,k为数据库的属性名,v为值

Resolver对象将values传入uri中进行插入操作,调用自定义provider中的insert操作,传过去values值

query操作也是调用的自定义provider中的query操作,将结果返回并显示

注意每次测试之后需要删除程序才会删除数据库中的数据

3.实现效果

在这里插入图片描述

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2021-12-26 22:18:57  更:2021-12-26 22:20:53 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 9:31:40-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码