Android Studio中SQLite的使用,主要介紹sqlite插入和讀出圖片(ViewBinder)的操作方法

2023-06-19 21:00:41

sqlite簡介

本人最近在寫一個小的安卓專案,開發app過程中用到了安卓自帶的sqlite。本文主要對sqlite圖片操作進行介紹,其他存入文字之類的操作和普通資料庫一樣,眾所周知,sqlite是一款輕型的資料庫,以下先簡單介紹一下sqlite,為後續做鋪墊,有了解的大佬可以跳過此部分:

 

SQLite是一種輕量級、嵌入式的關係型資料庫管理系統,它以庫的形式提供了一組程式設計介面,可以在各種作業系統上執行,如Windows、Linux、Mac OS等,被廣泛應用於移動裝置和嵌入式系統中。SQLite的資料儲存在單個檔案中,不需要專門的伺服器程序或後臺程序,它支援絕大多數的SQL語法,可以處理大部分中小型應用程式的資料儲存和管理需要。

 

SQLite的優點主要有以下幾個:

簡單易用:SQLite非常易於安裝和使用,只需要引入單個庫檔案,便可以開始使用它提供的API進行開發。

小巧靈活:由於SQLite的設計目標定位為輕量級的資料庫管理系統,因此它的庫檔案非常小巧,適合在嵌入式裝置和行動終端中使用。

零設定:SQLite不需要任何專門的設定或安裝過程,使用者只需要將其API引入到程式中即可使用,大大簡化了部署和維護的工作。

相容性強:SQLite支援大部分標準的SQL語法,同時可以通過外掛或擴充套件使用自定義的函數和AGGREGATE聚合函數。

 

SQLite的缺點也是比較明顯的:

不適合大規模資料儲存:由於SQLite的資料儲存在單個檔案中,因此不適合處理大規模資料儲存的需求,處理大量資料的查詢和更新操作效能可能較差。

難以擴充套件:SQLite的特性和限制都固定在庫檔案中,因此很難對其進行重構或擴充套件,無法滿足高度客製化化需求。

 

總的來說,SQLite是一種非常輕量級的資料庫管理系統,在小型應用開發及行動端開發中十分適合,但在處理大規模資料儲存及高並行操作的應用場景下效果不佳。

 

插入圖片

進入正題,在使用sqlite的過程中,我遇到了插入圖片失敗的問題,查了不少資料,才知道sqlite不能直接存入.jpg還有.png之類的檔案,需要以二進位制的形式儲存在sqlite中,這也是為什麼上面說的sqlite不適合大規模資料儲存,是一個輕量級資料庫。我用下面程式碼來進一步說明

 

要用到的方法以及部分名詞說明:

 

Bitmap是Android系統中的影象處理的最重要類之一。用它可以獲取影象檔案資訊,進行影象剪下、旋轉、縮放等操作,並可以指定格式儲存影象檔案。

BitmapFactory.decodeResource(?,?)這個帶兩個引數的方法:第一個引數是包含你要載入的點陣圖資原始檔的物件(一般寫成 getResources()就ok了);第二個時你需要載入的點陣圖資源的Id。

點陣圖介紹:點陣圖(Bitmap)格式其實並不能說是一種很常見的格式(從我們日常的使用頻率上來講,遠不如 .jpg .png .gif 等),因為其資料沒有經過壓縮,或最多隻採用行程長度編碼(RLE,run-length encoding)來進行輕度的無失真資料壓縮

這是一個寫好的呼叫語句和方法,insertdb()是寫好的方法,可以稍加修改後放入你的Activity頁面或fragment頁面,呼叫語句如圖。

複製程式碼
//你的圖片在andriod studio中是存在R.drawble中的,並且是int型的
//存入資料庫的id是自己定義資料庫時設計好的,可以參考我的資料庫程式碼
 
insertdb( R.drawable.你的圖片名,存入資料庫的id);
 
//s指你的圖片資源,int型,即R.drawable.你的圖片名
private void insertdb(int s,int id){
 
        //把你的圖片資源轉化成點陣圖
        Bitmap bitmap = BitmapFactory.decodeResource(this.getResources(), s);
 
        //Mysql是自己寫的資料庫類,需要自己編寫,下面兩句話是範例化一個sqlite資料庫物件
        Mysql mySqlLite = new Mysql(this);
        SQLiteDatabase database = mySqlLite.getReadableDatabase();
        
        //設定一個size大小,用來壓縮圖片檔案
        int size = bitmap.getWidth() * bitmap.getHeight() * 4;
 
        //ByteArrayOutputStream(位元組陣列輸出流)對byte型別資料進行寫入的類,屬於記憶體操作流
        ByteArrayOutputStream baos= new ByteArrayOutputStream(size);
 
        //壓縮點陣圖bitmap
        bitmap.compress(Bitmap.CompressFormat.PNG, 100, baos);
 
        //定義一個byte型別的陣列bytedata儲存點陣圖位元組流轉化成的byte陣列
        byte[] bytedata = baos.toByteArray();
 
        //sql語句是根據自己需求寫的,不要照抄
        database.execSQL("update 你的表名 set image=? where _id=?",new Object[] {bytedata,id});
    }
複製程式碼
複製程式碼
//MySQL.java
package 你的包名; import android.content.ContentValues; import android.content.Context; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; public class Mysql extends SQLiteOpenHelper { private static final String DB_NAME="INFORM.db"; private static final int DB_VERSION=1; public Mysql(Context context){ super(context,DB_NAME,null,DB_VERSION); } @Override public void onCreate(SQLiteDatabase db) { db.execSQL( "CREATE TABLE INFORMATION(" + "_id INTEGER PRIMARY KEY AUTOINCREMENT," +"NAME TEXT," +"TITLE TEXT," +"image blob," +"TEXTS TEXT);" ); insertTest(db, "程式設計師", "程式設計師.exe無響應","祝你有美好的一天"); insertTest(db, "程式設計師", "已停止執行","下輩子再也不用sqlite了"); @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { } public void insertTest(SQLiteDatabase db,String name,String title,String texts){ ContentValues value=new ContentValues(); value.put("NAME",name); value.put("TITLE",title); value.put("TEXTS",texts); db.insert("INFORMTION",null,value); } }
複製程式碼

 

讀取圖片

已經往資料庫插入圖片了,現在可以讀取圖片了,這裡我用的是遊標

複製程式碼
package 你的包名;
 
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.SimpleCursorAdapter;
import com.example.garden.database.Mydb;
 
public class SearchResult extends AppCompatActivity implements AdapterView.OnItemClickListener {
 
    //定義遊標
    private Cursor cursor;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_search_result);
 
        Intent rit = getIntent();
        String text = rit.getStringExtra("key");
 
        ListView listview=findViewById(R.id.listview);
 
        //幫助器和管理器兩個老朋友了,範例化資料庫物件
        SQLiteOpenHelper helper=new Mydb(this);
        SQLiteDatabase db=helper.getWritableDatabase();
 
        //遊標讀取資料庫
        cursor=db.rawQuery("select * from KNOW where name like '%"+text+"%'",null);
        cursor.moveToFirst();
 
        //資料庫的簡單遊標介面卡,簡單來說就是往模板填充內容的一個橋樑
        SimpleCursorAdapter mAdapter=new SimpleCursorAdapter(this,R.layout.item_list,
                cursor,new String[]{"NAME","image","TITLE"},new int[]{R.id.iv1,R.id.iv2,R.id.iv3},0);//自己的xml元件名R.id.iv1,R.id.iv2,R.id.iv3與資料庫欄位名"NAME","image","TITLE"對應,更多用法自己查
 
        //僅僅是上面的簡單遊標介面卡是不能讀取圖片的,重點來了,此處用到了ViewBinder
        SimpleCursorAdapter.ViewBinder binder=new SimpleCursorAdapter.ViewBinder() {
            @Override
            public boolean setViewValue(View view, Cursor cursor, int columnIndex) {
 
        //判斷是否是ImageView,這個判斷非常關鍵,詳細可以按ctr去查詢ViewBinder,就去檔案看,不要找其他資料,如果想真的搞懂一定要看!
                if (view instanceof ImageView) {
                    ImageView imageView = (ImageView) view;
 
           imageView.setImageBitmap(readImageFromDb(cursor.getString(cursor.getColumnIndex("_id"))));//為imageView設定id所對應的圖片   
                    return true;
                }
                return false;
            }
        };
 
        //設定ViewBinder
        mAdapter.setViewBinder(binder);
        //設定介面卡
        listview.setAdapter(mAdapter);
        //點選監聽器
        listview.setOnItemClickListener(this);
 
   }
 
    //
    @SuppressLint("Range")
    private Bitmap readImage(String id) {
 
    //至於為什麼又要範例化,是因為sqlite不能同時使用,術語不專業,總之要重新範例化,不然會報錯
        Mysql mySqlLite2 = new Mysql(this);
        SQLiteDatabase database2 = mySqlLite2.getReadableDatabase();
 
        Bitmap image= null;
        byte[] bytes;
        Cursor cursor = database2.rawQuery( "SELECT * FROM INFORMATION WHERE _id = ?", new String[]{id});
        if (cursor.moveToFirst()) {
            if ((bytes = cursor.getBlob(cursor.getColumnIndex("image"))) != null) {
                image= BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
            }
        }
        cursor.close();
        return image;
    }
 
 
    //listview的點選事件
    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        //此處寫點選事件,我用來傳值以及跳轉頁面
        Intent it=new Intent(this, Show.class);
        it.putExtra("ID",(int)id-1);
        startActivity(it);
        finish();
    }
}
複製程式碼

 

 

可能會出現的問題

此處重點!我遇到的大問題目前只有一個,就是行過大導致無法讀取資料庫,原因是我放入的圖片太大了,大概1MB左右的樣子,我其他的圖片大小一般是200KB到500KB左右,1MB的圖片太大了,導致那個點陣圖轉化的二進位制資料流太大了,資料庫無法一次讀取完,會導致程式直接崩潰,解決辦法就是不存入太大的圖片。畢竟它還只是個」孩砸「啊,sqlite是個輕量級的資料庫,不要存入太大的圖片

 

總結

寫程式碼的過程中遇到了不少問題,感謝網際網路各位大佬發的參考資料,由於參考了許多資料和文獻,也因為當時寫的太快了沒有記住大佬的部落格和文章,深表歉意,本專案後續完善後也會發到GitHub上面去,做一個開源小專案給大家參考,本人目前大二計科學生,希望和各位一同成長前進。