Android基础知识 - 内置SQLite数据库

2023-11-17

SQLite数据库简单介绍

  • SQLite是一款轻量级的关系型数据库,它的运算速度非常快,占用资源很少,通常只需要几百K的内存就足够了,因而特别适合在移动设备上使用。
  • SQLite不仅支持标准的SQL语法,还遵循了数据库的ACID事务。
  • 它甚至不用设置用户名和密码就能使用,可以快速上手。
  • 前面所学的文件存储和SharedPreferences存储毕竟只能适用于去保存一些简单的数据和键值对,当需要存储大量复杂的关系型数据的时候,就需要使用SQLite数据库,用来存储这些数据量大、结构性复杂的数据。

创建数据库

SQLiteOpenHelper类

简单概述

  • SQLiteOpenHelper类可以非常简单地对数据库进行创建和升级。
  • SQLiteOpenHelper类是一个抽象类,如果需要使用它,需要创建一个类去实现(继承)它。
  • SQLiteOpenHelper类中有两个抽象方法,分别是
    • onCreate()方法
    • onUpgrade() 方法
    • 我们必须在自己创建的类中去重写这两个方法,然后分别在这两个方法中去实现创建、升级数据库的逻辑。
  • SQLiteOpenHelper 类还有两个非常重要的实例方法
    • getReadableDatabase()方法
    • getWritableDatabase()方法
    • 这两个方法都可以创建或打开一个现有的数据库(如果数据库已存在则直接打开,否则创建一个新的数据库),并返回一个可对数据库进行读写操作的对象。不同的是,当数据库不可写入的时候(如磁盘空间已满)getReadableDatabase()方法返回的对象将以只读的方式打开数据库,而getWritableDatabase()方法则将出现异常。
  • SQLiteOpenHelper 类中有两个构造方法可供重写,一般使用参数少一点的那个构造方法即可。
    • 第一参数是Context,这个没什么好说的,必须要有它才能对数据库进行操作。
    • 第二个参数是数据库名,创建数据库时使用的就是这里指定的名称。
    • 第三个参数允许我们在查询数据的时候返回一个自定义的Cursor,一般都是传入null。
    • 第四个参数表示我们当前数据库的版本号,可用于对数据库进行升级操作。
  • 构建出SQLiteOpenHelper 的实例之后,在调用它的getReadableDatabase()或getWritableDatabase()方法就能够创建数据库了,数据库文件的存放目录,可以看我上篇博文的介绍 Android Studio中查看SQlite数据库和表的创建情况 。此时,重写的onCreate()方法也会得到执行,所以通常这里会去处理一些创建表的逻辑。

DatabaseTest项目

  • 创建一个名为BookStore.db的数据库,然后在这个数据库中新建一张Book表,表中有id(主键)、作者、价格、页数和书名等列。创建数据库表当然还是需要用建表语句的,Book表的建表语句如下所示:
    private static final String CREATE_BOOK = "create table Book ("
                    + "id integer primary key autoincrement, "
                    + "author text, "
                    + "price real, "
                    + "pages integer, "
                    + "name text)";
  //integer表示整型,real表示浮点型,text表示文本型,blob表示二进制类型。
  //上述建表语句中使用了primary key将id设为主键,并用autoincrement关键字表示id是自增长的。
  • 新建MyDatabaseHelper类继承自SQLiteOpenHelpler
package com.example.myapplication;

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

import androidx.annotation.Nullable;

public class MyDatabaseHelper extends SQLiteOpenHelper {

    private Context mContext;
    private static final String CREATE_BOOK = "create table Book ("
                    + "id integer primary key autoincrement, "
                    + "author text, "
                    + "price real, "
                    + "pages integer, "
                    + "name text)";


    public MyDatabaseHelper(@Nullable Context context, @Nullable String name, @Nullable SQLiteDatabase.CursorFactory factory, int version) {
        super(context, name, factory, version);
        mContext = context;
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL(CREATE_BOOK);
        Toast.makeText(mContext,"Create Succeeded!",Toast.LENGTH_LONG).show();
    }

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

    }
}
/* 可以看到我们把建表语句改成了一个字符串常量,然后在onCreate()方法中又调
用了SQLiteDatabase的execSQL()方法区执行这条语句,并弹出一个Toast提示创建
成功,这样就可以保证在数据库创建完成的同时还能成功创建Book表。*/
  • 修改activity_main.xml中的代码,如下所示:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <Button
        android:id="@+id/create_database"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Create Database"
        />
</LinearLayout>
<!-- 布局很简单,就是加入了一个按钮,用于创建数据库。 -->
  • 修改MainActivity中的代码,如下所示:
package com.example.myapplication;

import androidx.appcompat.app.AppCompatActivity;

import android.annotation.SuppressLint;
import android.content.ContentValues;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;

public class MainActivity extends AppCompatActivity {

    private MyDatabaseHelper dbOpenHelper;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        dbOpenHelper = new MyDatabaseHelper(this,"BookStore.db",null,1);
        Button createDatabase = (Button)findViewById(R.id.create_database);
        createDatabase.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                dbOpenHelper.getWritableDatabase();
            }
        });
   }
}
/* 这里我们在onCreate()方法中构建了一个MyDatabaseHelper对象,并且通过构造函数的参数
将数据库名改为BookStore.db,版本号指定为1,然后在Create Database按钮的点击事件里调用了
getWritableDatabase()方法。这样当第一次点击Create Database按钮时,就会检测到当前程序中
并没有BookStore.db这个数据库,于是会创建该数据库并调用MyDatabaseHelper中的onCreate()
方法,这样Book表就会得到创建,然后会弹出一个Toast提示创建成功。再次点击Create Database
按钮时,会发现此时已经存在BookStore.db数据库了,因此不会再创建一次。*/
  • 运行一次代码,在程序主界面上点击Create Database按钮,结果如图所示。
    在这里插入图片描述
  • 此时BookStore.db数据库和Book表都已经创建成功了,为证实它们存在,我们需要使用上篇博文 Android Studio中查看SQlite数据库和表的创建情况里提到的方法进行检验。
    在这里插入图片描述

升级数据库

  • onUpgrade()方法是用于对数据库进行升级的,它在整个数据库的管理当中起着非常重要的作用。
  • 目前数据库中已经有一张Book表存放书籍的各种详细信息,如果我们想再添加一张Category表用于记录书籍的分类该怎么做呢?
  • 比如Category表中有id(主键)、分类名和分类代码这几个列。
  • 将建表语句添加到MyDatabaseHelper类中,代码如下:
public class MyDatabaseHelper extends SQLiteOpenHelper {

    private Context mContext;
    private static final String CREATE_BOOK = "create table Book ("
                    + "id integer primary key autoincrement, "
                    + "author text, "
                    + "price real, "
                    + "pages integer, "
                    + "name text)";
    private static final String CREATE_CATEGORY = "create table Category ("
                    + "id integer primary key autoincrement, "
                    + "category_name text, "
                    + "category_code integer)";

    public MyDatabaseHelper(@Nullable Context context, @Nullable String name, @Nullable SQLiteDatabase.CursorFactory factory, int version) {
        super(context, name, factory, version);
        mContext = context;
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL(CREATE_BOOK);
        db.execSQL(CREATE_CATEGORY);
        Toast.makeText(mContext,"Create Succeeded!",Toast.LENGTH_LONG).show();
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        
    }
}
/*
	运行上面的程序,并点击Create Database按钮,发现竟然没有弹出创建成功的提示。
	当然,通过adb工具到数据库中再去检查下,这样你会更加确认,Category表没有创建成功。
	思考没有创建成功的原因,因为此时的BookStore.db数据库已经存在了,之后不管我们怎样
	点击Create Database按钮,MyDatabaseHelper中的onCreate()方法都不会再执行,因此
	新添加的表也就无法得到创建了。
	
*/
  • 解决上面的问题很简单,只需要先将程序卸载掉,对应的就是 清除模拟器中的数据(Wipe Data),然后重新运行,这时BookStore.db数据库就已经不存在了,如果再点击Create Database按钮,MyDatabaseHelper中的onCreate()方法就会执行,这时Category表就可以创建成功了。
  • 不过通过卸载数据库的方法来新增一张表毫无疑问是很极端的方法,其实我们只需要巧妙地运用SQLiteOpenHelper的升级功能就可以很轻松地解决这个问题。修改MyDatabaseHelper中的代码,如下所示:
    
public class MyDatabaseHelper extends SQLiteOpenHelper{
	@Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        db.execSQL("drop table if exists Book");
        db.execSQL("drop table if exists Category");
        onCreate(db);
    }
}
/*
	可以看到我们在onUpgrade()方法中执行了两条DROP语句,如果发现数据库中已经存在Book表或
	Category表,就将这两张表删除掉,然后再调用onCreate()方法去重新创建,这里先将已经存在
	的表删除掉,是因为如果在创建表时发现这张表已经存在了,就会直接报错。
*/
  • 接下来的问题就是如何让onUpgrade()方法能够执行了,还记得SQLiteOpenHelper的构造方法里接收的第四个参数吗?它表示当前数据库的版本号,之前我们传入的是1,现在只要传入一个比1大的数,就可以让onUpgrade()方法得到执行了。修改MainActivity中的代码,如下所示:
public class MainActivity extends AppCompatActivity {

    private MyDatabaseHelper dbOpenHelper;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        dbOpenHelper = new MyDatabaseHelper(this,"BookStore.db",null,2);
        Button createDatabase = (Button)findViewById(R.id.create_database);
        createDatabase.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                dbOpenHelper.getWritableDatabase();
            }
        });
   }
}
/*
这里将数据库的版本号改为2,表示我们对数据库进行升级了。现在重新运行程序,并点击
Create Database按钮,这时会再次弹出创建成功的提示。为了验证一下Category表
是不是已经创建成功了,我们可以利用adb工具打开数据库检验。
*/

在这里插入图片描述

对表中的数据进行操作

  • 对数据进行的操作无非四种,即CRUD。其中C代表添加,Create;R代表查询,Retrieve;U代表更新,Update;D代表删除,Delete。每一种操作又各自对应了一种SQL命令,添加数据时使用insert,查询数据时使用select,更新数据时使用update,删除数据时使用delete。但是除了SQL命令之外,Android还提供了一套辅助性方法。
  • 调用SQLiteOpenHelper的getReadableDatabase()或getWritableDatabase()方法是可以用于创建和升级数据库的,不仅如此,这两个方法都会返回一个SQLiteDatabse对象,借助这个对象我们就可以对数据进行CRUD操作了。

添加数据

  • SQLiteDatabase中提供了一个insert()方法,这个方法就是专门用来添加数据的。
    • 它接收三个参数,第一个参数是表名,我们希望向哪张表里添加数据,这里就传入该表的名字。
    • 第二个参数用于在未指定添加数据的情况下给某些可为空的列自动赋值NULL,一般我们用不到这个功能,直接传入null即可。
    • 第三个参数是一个ContentValues对象,它提供了一系列的put()方法重载,用于向ContentValues中添加数据,只需要将表中的每个列名以及相应的待添加数据传入即可。
  • 举例说明,修改activity_main.xml中的代码,如下所示。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    ......
    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/add_data"
        android:text="Add Data"
        />
</LinearLayout>
<!-- 新增了一个添加数据按钮 -->
  • 修改MainActivity中的代码,如下所示。
public class MainActivity extends AppCompatActivity {

    private MyDatabaseHelper dbOpenHelper;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        dbOpenHelper = new MyDatabaseHelper(this,"BookStore.db",null,2);
        ......
        Button addData = (Button) findViewById(R.id.add_data);
        addData.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                SQLiteDatabase db = dbOpenHelper.getWritableDatabase();
                ContentValues values = new ContentValues();
                values.put("author","Dan Brown");
                values.put("price",19.6);
                values.put("pages",454);
                values.put("name","The Da Vinci Code");
                db.insert("Book",null,values);// 插入第一条数据
                values.put("author","Dan Brown");
                values.put("price",19.95);
                values.put("pages",550);
                values.put("name","The Lost Symbol");
                db.insert("Book",null,values);// 插入第二条数据

            }
        });
    }
}
/*
在添加数据的按钮点击事件里,我们先获取到了SQLiteDatabase 对象,
然后使用ContentValues来对要添加的数据进行组装。我们发现没有对
id那一列进行赋值,这是因为在前面创建表的时候我们就将id设置为自增长
了,它的值会在入库的时候自动生成,所以不需要手动给它赋值,接下来调用
insert()方法将数据添加到表当中,注意这里我们实际添加了两条数据,上述代码
中使用了ContentValues分别组装了两次不同的内容,并调用了两次insert()方法。
*/
  • 接下来运行程序,界面和adb工具查询结果如下:
    • 界面
      在这里插入图片描述
    • adb查询结果
      在这里插入图片描述

更新数据

  • SQLiteDatabase提供了一个update()方法用于对数据进行更新
    • 第一个参数,表名,在这里指定去更新哪张表里的数据
    • 第二个参数,ContentValues对象,要把更新的数据在这里组装进去。
    • 第三、四个参数,用于去约束更新某一行或某几行中的数据,不指定的话默认就是更新所有的行。
  • 在以上数据库和表中进行修改:将添加进数据库里的第一本书的价格降低,来吸引更多的顾客。
  • 修改activity_main.xml中的代码,如下所示。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    ......

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/update_data"
        android:text="Update Data"
        />
</LinearLayout>
  • 修改MainActivity中的代码,如下所示。
public class MainActivity extends AppCompatActivity {

    private MyDatabaseHelper dbOpenHelper;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        dbOpenHelper = new MyDatabaseHelper(this,"BookStore.db",null,2);
        ......
        Button updateData = (Button)findViewById(R.id.update_data);
        updateData.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                SQLiteDatabase db = dbOpenHelper.getWritableDatabase();
                ContentValues values = new ContentValues();
                values.put("price",10.99);
                db.update("Book",values,"name = ?", new String[] {"The Da Vinci Code"});
            }
        });
    }
}
/*
这里在更新数据按钮的点击事件里面构建了一个ContentValues对象,并且只给定它指定了一组数据,
说明我们只是想把价格这一列的数据更新成10.99。然后调用了SQLiteDatabase的update()方法去
执行具体的更新操作,可以看到,这里使用了第三、四个参数来指定具体更新哪几行。第三个参数
对应的是SQL语句的where部分,表示去更新所有name等于?的行,而?是一个占位符,可以通过
第四个参数提供的一个字符串数组为第三个参数中的每个占位符指定相应的内容。因此上述代码
想表达的意图就是,将名字是The Da Vinci Code的这本书的价格改为10.99。
*/
  • 重新运行程序,界面如下所示。
    在这里插入图片描述
  • 点击Update Data按钮,再次在adb查询工具查询表中的数据情况,如下所示。
    在这里插入图片描述

删除数据

  • SQLiteDatabase中提供了一个delete()方法专门用于删除数据
    • 第一个参数,表名
    • 第二、三个参数,用于去约束删除某一行或某几行的数据,不指定的话默认就是删除所有行。
  • 修改activity_main.xml中的代码,如下所示。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    ......
    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/delete_data"
        android:text="Delete Data"
        />
</LinearLayout>
  • 修改MainActivity中的代码,如下所示。
public class MainActivity extends AppCompatActivity {

    private MyDatabaseHelper dbOpenHelper;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        dbOpenHelper = new MyDatabaseHelper(this,"BookStore.db",null,2);
        ......
        Button deleteData = (Button)findViewById(R.id.delete_data);
        deleteData.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                SQLiteDatabase db = dbOpenHelper.getWritableDatabase();
                db.delete("Book","pages > ?", new String[] {"500"});
            }
        });
    }
}
/*
可以看到我们在删除按钮的点击事件里指明去删除Book表中的数据,并且通过
第二、三参数来指定仅删除那些页数超过500页的书籍。
*/
  • 界面如下所示。
    在这里插入图片描述
  • adb查询工具查询结果如下所示。
    在这里插入图片描述

查询数据

  • SQLiteDatabase中提供了一个query()方法用于对数据进行查询,这里介绍最少参数(7个参数)的方法重载。调用query()方法后会返回一个Cursor对象,各参数含义如下表所示。
query()方法参数 对应SQL部分 描述
table from table_name 指定查询的表名
columns select column1,column2 指定查询的列名
selection where column=value 指定where的约束条件
selectionArgs - 为where中的占位符提供具体的值
groupBy group by column 指定需要group by的列
having having column = value 对group by后的结果进一步约束
orderBy order by column1,column2 指定查询结果的排序方式
  • 第二个参数,如果不指定默认查询所有列。
  • 第三、四个参数,不指定则默认是查询所有行的数据。
  • 第五个参数,不指定则表示不对查询结果进行group by的操作。
  • 第六个参数,不指定则表示不进行约束。
  • 第七个参数,不指定则表示使用默认的排序方式。
  • 其他几个query()方法的重载其实也大同小异。
  • 修改activity_main.xml中的代码,如下所示。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
	......
    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/query_data"
        android:text="Query Data"
        />

</LinearLayout>
  • 修改MainActivity中的代码,如下所示。
package com.example.myapplication;

import androidx.appcompat.app.AppCompatActivity;

import android.annotation.SuppressLint;
import android.content.ContentValues;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;

public class MainActivity extends AppCompatActivity {

    private MyDatabaseHelper dbOpenHelper;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        dbOpenHelper = new MyDatabaseHelper(this,"BookStore.db",null,2);
        ......
        Button queryData = (Button)findViewById(R.id.query_data);
        queryData.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                SQLiteDatabase db = dbOpenHelper.getWritableDatabase();
                // 查询表中所有的数据
                Cursor cursor = db.query("Book",null,null,null,null,null,null);
                if(cursor.moveToFirst()){
                    do{
                        // 遍历Cursor对象,取出数据并打印出来
                        @SuppressLint("Range") String author = cursor.getString(cursor.getColumnIndex("author"));
                        @SuppressLint("Range") double price = cursor.getDouble(cursor.getColumnIndex("price"));
                        @SuppressLint("Range") int pages = cursor.getInt(cursor.getColumnIndex("pages"));
                        @SuppressLint("Range") String name = cursor.getString(cursor.getColumnIndex("name"));

                        Log.d("MainActivity",author);
                        Log.d("MainActivity",""+price);
                        Log.d("MainActivity","" + pages);
                        Log.d("MainActivity",name);

                    }while(cursor.moveToNext());
                }
                cursor.close();
            }
        });
    }
}
/*
	可以看到,我们在查询按钮的点击事件里调用了SQLiteDatabase的query()方法
	去查询数据。这里的query()方法非常简单,只是使用了第一个参数指明去查询
	Book表,后面的参数全部为null。这就表示希望查询这张表中的所有数据,虽然
	这张表中目前只剩下一条数据了。查询完之后就得到了一个Cursor对象,接着
	我们调用它的moveToFirst()方法将数据的指针移动到第一行的位置,然后进入
	了一个循环当中,去遍历查询到的每一行数据。在这个循环中可以通过Cursor的
	getColumnIndex()方法获取到某一列在表中对应的位置索引,然后将这个索引
	传入到相应的取值方法中,就可以得到从数据库中读取到的数据了。接着我们用
	Log的方式将取出的数据打印出来,借此来检查一下读取工作有没有成功完成。
	最后调用close()方法来关闭Cursor。
*/
  • 界面如下所示。
    在这里插入图片描述
  • 点击一下Query Data按钮,查看LogCat的打印内容,结果如下所示。
    在这里插入图片描述

使用SQL操作数据库

  • 直接使用SQL来完成前面学过的CRUD(C代表添加,Create;R代表查询,Retrieve;U代表更新,Update;D代表删除,Delete)
//添加数据的方法如下:
db.execSQL("insert into Book (name, author, pages, price) values(?, ?, ?, ?)", new String[]{"The Da Vinci Code", "Dan Brown", "454", "16.96"});
db.execSQL("insert into Book (name, author, pages, price) values(?, ?, ?, ?)", new String[]{"The Lost Symbol", "Dan Brown", "510", "19.95"});
//更新数据的方法如下:
db.execSQL("update Book set price = ? where name = ?", new String[] {"10.99", "The Da Vinci Code"});
//删除数据的方法如下:
db.execSQL("delete from Book where pages > ?", new String[] {"500"});
//查询数据的方法如下
db.execSQL("select * from Book",null);
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android基础知识 - 内置SQLite数据库 的相关文章

  • Android 布局不需要的填充

    所以我有这个布局文件 如下 正如您所看到的 没有填充或边距 dimen xml 文件也没有任何填充 边距 最后 我根本不以编程方式更改布局
  • “此版本中使用了已弃用的 Gradle 功能,使其与 Gradle 7.0 不兼容。” -反应-原生

    当我尝试运行反应本机应用程序时 我遇到此错误react native run android 我无法安装该应用程序 我正在尝试构建一个相机应用程序 我当前的react native版本 0 62 0 React cli版本 2 0 1 De
  • 在Android内存中存储gif图像

    我对安卓还很陌生 我想将图像保存到内存中 然后从内存中检索图像并将其加载到图像视图中 我已使用以下代码成功将图像存储在内存中 void saveImage String fileName img cnt jpg File file new
  • Android-全屏视频视图

    我正在尝试使此 VideoView 以全屏模式显示 public class ViewVideo extends Activity private String filename private static final int INSER
  • Android Accessibility 执行触摸操作

    我想知道是否可以使用 Android 辅助功能服务在屏幕上的位置执行触摸操作 例如 Bundle arguments new Bundle arguments putInt coord X X value arguments putInt
  • 如何更改对话框的默认黑色暗淡背景“颜色”(而不是暗淡量)?

    这是随机显示的图像Dialog在网上找到的 我一直在实施一个自定义Dialog 我可以处理对话框上的几乎所有内容 除了对话框本身下方的默认黑色昏暗背景之外 但在其后面的整个屏幕上 基本上我想改变它color和阿尔法值 我一直在 StackO
  • 如何在我的 Android 应用程序中实现应用内购买?

    如何在我的 Android 应用程序中实现应用内购买 我提到 http developer android com guide market billing billing integrate html billing service ht
  • Android 性能:SharedPreferences 的成本

    当我的应用程序启动时 我使用分片首选项中的值填充容器类 这个想法是处理 SharedPreferences 和 PreferenceManager 一次 因为我猜它们很重 这是一个示例 SharedPreferences prefs Pre
  • 无法在 Java 中输出正确的哈希值。怎么了?

    在我的 Android 应用程序中 我有一个 SHA256 哈希值 我必须使用 RIPEMD160 消息摘要算法进一步对其进行哈希值 我可以输出任何字符串的正确 sha256 和ripemd160 哈希值 但是当我尝试使用ripemd160
  • 在尝试使用 GPS 之前如何检查 GPS 是否已启用

    我有以下代码 但效果不好 因为有时 GPS 需要很长时间 我该如何执行以下操作 检查GPS是否启用 如果启用了 GPS 请使用 GPS 否则请使用网络提供商 如果 GPS 时间超过 30 秒 请使用网络 我可以使用时间或 Thread sl
  • 使用 Glide 库设置图像加载完成后进度条的可见性

    您好 我想要一个图像进度条 该进度条将在图像加载时显示 但当图像加载完成时 我想将其设置为消失 早些时候我为此使用了毕加索库 但我不知道如何将它与 Glide 库一起使用 我知道有一些资源就绪功能 但我不知道如何使用它 谁能帮我 毕加索图书
  • 为什么 ExpandableListView 更改 ChildView 设置(Android)?

    我对使用 ExpandableListView 有疑问 就我而言 我有两个组视图和两个子视图 而子视图由一个带有多个按钮 文本视图等的相对布局组成 例如 当首先扩展第二组并对视图持有者进行一些更改并随后扩展第一组时 先前所做的更改也会自动应
  • 如何以编程方式创建 CardView

    我正在开发一个 Android 应用程序Java Android Studio 我想在活动中创建CardView以编程方式 我想将以下属性设置为CardView layout width wrap content layout row 0
  • 在上下文操作模式下选择时,ListView 项目不会在视觉上“突出显示”

    我关注了 Android 官方网站创建上下文操作菜单的教程 http developer android com guide topics ui menus html CAB 使用下面的代码 当我长按我的 ListView 项目之一时 它确
  • 创建日期范围表

    我正在编写一份需要显示每天值的报告 我有查询的开始日期和结束日期 但我希望避免丢失日期 以防表不包含特定日期的值 我正在考虑创建一个基本日期范围表 其中包含开始和结束之间的所有日期 然后将其与数据表左连接以显示每一天的值 我找到了一些适用于
  • Android UnityPlayerActivity 操作栏

    我正在构建一个 Android 应用程序 其中包含 Unity 3d 交互体验 我已将 Unity 项目导入 Android Studio 但启动时该 Activity 是全屏的 并且不显示 Android 操作栏 我怎样才能做到这一点 整
  • firebase中按范围查询

    我有一个食品价格范围滑块 根据滑块的最小值和最大值 我想显示此范围内的食品 滑块代码 multiSlider setOnThumbValueChangeListener new MultiSlider SimpleChangeListene
  • 画布:尝试使用回收的位图错误

    我是一个相当新的程序员 所以任何建议将不胜感激 我有一个类 每次调用它时都会在循环中运行 AsyncTask AsyncTask 看起来像这样 public class LoadImageTask extends AsyncTask
  • 在DialogFragment中,onCreate应该做什么?

    我目前正在摆弄 DialogFragment 以学习使用它 我假设相比onCreateView onCreate 可以这样做 public void onCreate Bundle savedInstanceState super onCr
  • 进程被杀死后不会调用 onActivityResult

    我有一个主要活动 Main 和另一个活动 Sub 由 Main 调用 startActivityForResult new Intent this SubActivity class 25 当我在 Sub 时 我终止该进程 使用任务管理器或

随机推荐

  • 【软件测试】未来软件测试必备的8大技能,你缺少哪几个?

    软件测试工程师是个神奇的职业 他是开发人员与老板之间的传话筒 三夹板 也是开发人员与老板的好帮手 他不仅需要有销售的沟通能力 也需要具备编辑人员的文档撰写技巧 如此一个面面俱到的岗位 他需要具备的技能到底有哪些呢 有逆向思维的能力 曾经采访
  • 算法:两个有序数组合并成一个有序数组 java语言

    题目 有两个有序数组a 和b 将它们合并成数组c 需要c 也是有序数组 思路 新建一个以两个集合长度之和为长度的新数组 从两数组最左边开始比起 把小的放入新集合 并用变量标记后一位置 每次比较都是比较的最左边未比较过的元素 通过变量 循环比
  • 分享一个可交互的小场景(二)

    先看效果 可互动的小场景 再看代码 JS部分
  • 正点原子I.MX6ULL开发板车牌识别项目实战 1

    1 项目总体概述 下图为 车牌识别项目 的系统框图 借助这个框图 简要介绍项目的总体思路和所需要做的准备工作 1 1 总体思路 通过摄像头采集图像信息 并将图像信息传递开发板 这里使用的是OpenCv 开发板收到图像信息之后 通过定时器 周
  • Python解决ModuleNotFoundError: No module named 'Queue'的问题

    我们知道Python2和Python3两个版本之间 有些不兼容的地方 Python3中引入Queue会报出这个问题 Python3中要这样引入 1 import queue Python2中要这样引入 1 import Queue 为了兼容
  • 第十六课,面剔除

    使用OpenGL的面剔除选项 它默认是禁用状态 glEnable GL CULL FACE 直接运行后 我们发现正方体的部分面确实被剔除了 但是却不是背向面 这是因为我们定义的正方体并不是严格遵循逆时针顺序定义的 原理详见教程 这里就不过多
  • python输出文本 去掉引号,如何从导出的python列表中删除逗号,引号和括号?

    You guys were super helpful with my last newbie question so I figured I would give it another shot Right now my Python 3
  • 基于范围的for循环

    一 基于范围的for循环 C 11 1 范围for的语法 2 范围for的使用条件 二 指针空值nullptr 一 基于范围的for循环 C 11 1 范围for的语法 对于一个有范围的集合而言 由程序员来说明循环的范围是多余的 有时候还会
  • 智能聊天机器人实现(源码+解析)

    前言 之前写了一篇 美女图片采集器 源码 解析 得到了众多朋友的支持 发现这样系列的教程还是挺受欢迎的 也激励我继续写下去 也在那一篇文章中提过 美女图片采集只是我先前那个完整APP中的一个功能罢了 还有其他几个比较好玩的尚未开源 之后有时
  • QWidgetAction实现鼠标滑过菜单项图标高亮显示

    需求是鼠标滑过菜单项时 菜单项的文字 icon以及子菜单的小箭头都要高亮显示 qss中只能设置item背景色 文字颜色以及子菜单小箭头的样式 icon的图片不能切换 另外曾经想过用indicator 对action setCheckable
  • Ubuntu18.04安装QT5

    提示 文章写完后 目录可以自动生成 如何生成可参考右边的帮助文档 文章目录 前言 一 QT5是什么 二 安装包安装 1 下载安装包 2 安装QT5 3 运行 4 其他方式 总结 前言 最近在学习QT5 在Windows上的安装自然不必多说
  • 爬虫 — 反爬

    目录 一 UA 反爬 二 Cookie 验证与反爬 1 Cookie 简介 2 使用 Cookie 原因 3 Cookie 作用 3 1 模拟登录 3 2 反反爬 三 Referer 反爬 一 UA 反爬 UA User Agent 用户代
  • [机械]“重工业面临两大危机”——向文波(三一重工股份有限公司执行总裁)

    向文波 三一重工股份有限公司执行总裁 向文波是三一重工的掌门人 但深受徐工事件影响 他以业内的视角 适时地向中国重工业的改革发出一个警示信号 提出一个超越 抓大放小 国进民退 等传统国企改革的新命题 产业安全 引起了舆论与政府的重视 中国重
  • 2021.11.13-15总结

    将C语言文件相关的内容学完了 了解了文件相关的函数
  • linux网络管理

    一 网络接口 1 在Linux系统中 主机的网络接口卡通常称为网络接口 使用ifconfig命令来查看网络 2 eth0 是Linux系统中第一块以太网卡的名称 3 lo 是Linux系统中的 环回 网络接口 lo 并不代表真正的网络接口
  • 用户访问session分析-按session粒度进行数据聚合

    思路 之前模拟创建了两张表 user visit action 和 user info 对于user visit action表 1 通过用户传过来的指定日期范围内 从user visit action中查询出指定的用户访问数据 变成 ac
  • nginx根据url参数动态代理

    nginx根据url参数动态代理 请求url格式 其中参数proxy后面的url就是需要访问的真实地址 http localhost 9388 proxy http localhost 8038 Content layui font ico
  • 腾讯滑块识别-通用滑块识别

    遇到滑块问题 在写爬虫的时候 经常会遇到滑块问题 很多次都想过尝试如何攻破滑块 但是每次都没成功 除了最开始的极验滑块 当时通过原图和滑块图的对比 能够得出缺口坐标 但是随着极验 网易 腾讯滑块的更新 已经不能够找到原图了 下面给出滑块通杀
  • python的gui神器——gooey

    python的gui神器 gooey python自带的gui库 tkinter库 最近研究的gui库 gooey tkinter教程 tkinter GUI编程 gooey地址和教程 gooey 入门教程 python使用tkinter库
  • Android基础知识 - 内置SQLite数据库

    文章目录 SQLite数据库简单介绍 创建数据库 SQLiteOpenHelper类 简单概述 DatabaseTest项目 升级数据库 对表中的数据进行操作 添加数据 更新数据 删除数据 查询数据 使用SQL操作数据库 SQLite数据库