Android中数据存储--采用SQLite存储数据及在SDCard中创建数据库 .

SQLite数据库简单的认识

       SQLite,是一款轻型的数据库,是遵守ACID的关联式数据库管理系统,它的设计目标是嵌入式的,而且目前已经在很多嵌入式产品中使用了它,它占用资源非常的低,在嵌入式设备中,可能只需要几百K的内存就够了。它能够支持Windows/Linux/Unix等等主流的操作系统,同时能够跟很多程序语言相结合,比如 Tcl、C#、PHP、Java等,还有ODBC接口,同样比起Mysql、PostgreSQL这两款开源世界著名的数据库管理系统来讲,它的处理速度比他们都快。SQLite第一个Alpha诞生于2000年5月. 至今已经有10个年头,SQLite也迎来了一个版本 SQLite 3已经发布。

 

SQLite特性

下面是访问SQLite官方网站: http://www.sqlite. org/ 时第一眼看到关于SQLite的特性.

  1. ACID事务   

      2. 零配置 – 无需安装和管理配置   

      3. 储存在单一磁盘文件中的一个完整的数据库   

      4. 数据库文件可以在不同字节顺序的机器间自由的共享   

      5. 支持数据库大小至2TB   

      6. 足够小, 大致3万行C代码, 250K   

      7. 比一些流行的数据库在大部分普通数据库操作要快   

      8. 简单, 轻松的API   

      9. 包含TCL绑定, 同时通过Wrapper支持其他语言的绑定   

      10. 良好注释的源代码, 并且有着90%以上的测试覆盖率   

      11. 独立: 没有额外依赖   

      12. Source完全的Open, 你可以用于任何用途, 包括出售它   

      13. 支持多种开发语言,C, PHP, Perl, Java, ASP .NET,Python

 

下面我以一个完整的Demo例子来展示对SQLite数据库操作,包括对数据库表的增、删、改、查等基本操作。下面的一个截图是该演示Demo的项目框架图:

通过上面的截图可以看到该项目src目录下包含两个类:MainActivity.java 和 MySQLiteOpenHelper.java 。其中MySQLiteOpenHelper.java是对数据库操作辅助类。

 

布局文件main.xml的代码:

 

[c-sharp] view plain copy print ?
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:orientation="vertical"  
  4.     android:layout_width="fill_parent"  
  5.     android:layout_height="fill_parent">  
  6.     <TextView android:id="@+id/tv_title"  
  7.        android:layout_width="fill_parent"  android:layout_height="wrap_content"   
  8.        android:text="Hello, Welcome to Andy's blog!" android:textSize="16sp"/>  
  9.       
  10.     <Button android:id="@+id/newTable" android:layout_width="fill_parent"    
  11.         android:layout_height="wrap_content" android:text="1.新建数据表"/>    
  12.     <Button android:id="@+id/addOne" android:layout_width="fill_parent"    
  13.         android:layout_height="wrap_content" android:text="2.插入一条记录"/>    
  14.     <Button android:id="@+id/query" android:layout_width="fill_parent"     
  15.         android:layout_height="wrap_content" android:text="3.查询数据库"/>    
  16.     <Button android:id="@+id/editOne" android:layout_width="fill_parent"    
  17.         android:layout_height="wrap_content" android:text="4.修改一条记录"/>    
  18.     <Button android:id="@+id/deleteOne" android:layout_width="fill_parent"    
  19.         android:layout_height="wrap_content" android:text="5.删除一条记录"/>    
  20.     <Button android:id="@+id/deleteTable" android:layout_width="fill_parent"    
  21.         android:layout_height="wrap_content" android:text="6.删除数据表"/>    
  22.           
  23.     <TextView android:id="@+id/tv_result"  
  24.        android:layout_width="fill_parent"  android:layout_height="wrap_content"   
  25.        android:text="测试显示的结果" android:textSize="16sp"/>  
  26.       
  27. </LinearLayout>  

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <TextView android:id="@+id/tv_title" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Hello, Welcome to Andy's blog!" android:textSize="16sp"/> <Button android:id="@+id/newTable" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="1.新建数据表"/> <Button android:id="@+id/addOne" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="2.插入一条记录"/> <Button android:id="@+id/query" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="3.查询数据库"/> <Button android:id="@+id/editOne" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="4.修改一条记录"/> <Button android:id="@+id/deleteOne" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="5.删除一条记录"/> <Button android:id="@+id/deleteTable" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="6.删除数据表"/> <TextView android:id="@+id/tv_result" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="测试显示的结果" android:textSize="16sp"/> </LinearLayout>

 

 

MainActivity.java代码:

 

[c-sharp] view plain copy print ?
  1. package com.andyidea.sqlite;  
  2. import java.io.File;  
  3. import java.io.IOException;  
  4. import android.app.Activity;  
  5. import android.content.ContentValues;  
  6. import android.database.Cursor;  
  7. import android.database.sqlite.SQLiteDatabase;  
  8. import android.os.Bundle;  
  9. import android.view.View;  
  10. import android.view.View.OnClickListener;  
  11. import android.widget.Button;  
  12. import android.widget.TextView;  
  13. import android.widget.Toast;  
  14. public class MainActivity extends Activity {  
  15.     private Button btn_newTable,btn_addOne,btn_query,  
  16.             btn_editOne,btn_deleteOne,btn_deleteTable;  
  17.     private TextView tv;  
  18.     private MySQLiteOpenHelper myOpenHelper;  
  19.     private SQLiteDatabase sqlitedb;  
  20.       
  21.     //----以下两个成员变量是针对在SD卡中存储数据库文件使用----    
  22.     //private File path = new File("/sdcard/dbfile"); //数据库文件目录   
  23.     //private File f = new File("/sdcard/dbfile/AndyDemo.db"); //数据库文件   
  24.       
  25.     /** Called when the activity is first created. */  
  26.     @Override  
  27.     public void onCreate(Bundle savedInstanceState) {  
  28.         super.onCreate(savedInstanceState);  
  29.         setContentView(R.layout.main);  
  30.           
  31.         initializeViews();  
  32.           
  33.         //实例化默认数据库辅助操作对象   
  34.         myOpenHelper = new MySQLiteOpenHelper(this);  
  35.           
  36.         //----如要在SD卡中创建数据库文件,先做如下的判断和创建相对应的目录和文件----   
  37.         //if(!path.exists()){   //判断目录是否存在   
  38.         //  path.mkdirs();    //创建目录   
  39.         //}   
  40.         //if(!f.exists()){      //判断文件是否存在   
  41.         //  try{   
  42.         //      f.createNewFile();  //创建文件   
  43.         //  }catch(IOException e){   
  44.         //      e.printStackTrace();   
  45.         //  }   
  46.         //}   
  47.     }  
  48.       
  49.     /** 
  50.      * 初始化UI界面 
  51.      */  
  52.     private void initializeViews(){  
  53.         tv = (TextView)findViewById(R.id.tv_result);  
  54.         btn_newTable = (Button)findViewById(R.id.newTable);  
  55.         btn_addOne = (Button)findViewById(R.id.addOne);  
  56.         btn_query = (Button)findViewById(R.id.query);  
  57.         btn_editOne = (Button)findViewById(R.id.editOne);  
  58.         btn_deleteOne = (Button)findViewById(R.id.deleteOne);  
  59.         btn_deleteTable = (Button)findViewById(R.id.deleteTable);  
  60.           
  61.         btn_newTable.setOnClickListener(new ClickEvent());  
  62.         btn_addOne.setOnClickListener(new ClickEvent());  
  63.         btn_query.setOnClickListener(new ClickEvent());  
  64.         btn_editOne.setOnClickListener(new ClickEvent());  
  65.         btn_deleteOne.setOnClickListener(new ClickEvent());  
  66.         btn_deleteTable.setOnClickListener(new ClickEvent());  
  67.     }  
  68.       
  69.     class ClickEvent implements OnClickListener{  
  70.         @Override  
  71.         public void onClick(View v) {  
  72.             try{  
  73.                 //[1]--如果是在默认的路径下创建数据库,那么实例化sqlitedb的操作如下   
  74.                 sqlitedb = myOpenHelper.getWritableDatabase(); //实例化数据库   
  75.                   
  76.                 //[2]--如果是在SD卡中创建数据库,那么实例化sqlitedb的操作如下   
  77.                 //sqlitedb = SQLiteDatabase.openOrCreateDatabase(f, null);   
  78.                   
  79.                 if(v == btn_newTable){   //1.新建数据表   
  80.                     String TABLE_NAME = "andy";  
  81.                     String ID = "id";  
  82.                     String TEXT = "text";  
  83.                     String str_sql2 = "CREATE TABLE " + TABLE_NAME + "(" + ID    
  84.                         + " INTEGER PRIMARY KEY AUTOINCREMENT," + TEXT    
  85.                         + " text );";  
  86.                     sqlitedb.execSQL(str_sql2);  
  87.                     tv.setText("新建数据表成功!");  
  88.                       
  89.                 }else if(v == btn_addOne){  //2.插入一条记录   
  90.                     //----第1种插入数据的方法----   
  91.                     //ContentValues是一个哈希表HashMap,key值是对应数据表中字段名称,   
  92.                     //value值是字段的值。可以通过ContentValues的put方法把数据存放到   
  93.                     //ContentValues对象中,然后把数据插入到相对应的数据表中。   
  94.                     ContentValues cv = new ContentValues();  
  95.                     cv.put(MySQLiteOpenHelper.TEXT, "新数据");  
  96.                     sqlitedb.insert(MySQLiteOpenHelper.TABLE_NAME, null, cv);  
  97.                     //db.insert(String table, String nullColumnHack, ContentValues values);方法解说   
  98.                     //public long insert (String table, String nullColumnHack, ContentValues values)   
  99.                     //该方法是向数据表中插入一条记录   
  100.                     //[1]参数table:需要插入操作的表名   
  101.                     //[2]参数nullColumnHack:默认null即可,若在插入一行数据时,若没有指定某列的值,   
  102.                     //   则默认使用null值传入。   
  103.                     //[3]参数values:插入的数据   
  104.                       
  105.                     //----第2种插入数据的方法----   
  106.                     // String INSERT_DATA =     
  107.                     // "INSERT INTO andy (id,text) values (1, '第2种插入数据的方法')";     
  108.                     // sqlitedb.execSQL(INSERT_DATA);   
  109.                       
  110.                     tv.setText("添加新数据成功!");  
  111.                       
  112.                 }else if(v == btn_query){   //3.查询数据库   
  113.                     Cursor cur = sqlitedb.rawQuery("SELECT * FROM "+MySQLiteOpenHelper.TABLE_NAME, null);  
  114.                     if(cur != null){  
  115.                         String temp = "";  
  116.                         int i = 0;  
  117.                         while(cur.moveToNext()){  
  118.                             temp += cur.getString(0);  //0代表数据列的第一列,即id   
  119.                             temp += cur.getString(1);  //1代表数据列的第二列,即text   
  120.                             i++;  
  121.                             temp += "/n";    //定义显示数据的格式,一行一个数据   
  122.                         }  
  123.                         tv.setText(temp);  
  124.                           
  125.                     }  
  126.                 }else if(v == btn_editOne){  //4.修改一条记录   
  127.                     //----第1种方式修改数据----   
  128.                     ContentValues cv = new ContentValues();  
  129.                     cv.put(MySQLiteOpenHelper.TEXT, "更新后的数据");  
  130.                     sqlitedb.update("andy", cv, "id " + "=" + Integer.toString(1), null);  
  131.                     //[1]参数table:需要操作的表名   
  132.                     //[2]参数values:ContentValues   
  133.                     //[3]参数whereClause:更新的条件   
  134.                     //[4]参数whereArgs:更新条件对应的值   
  135.                       
  136.                     //----第2种方式修改数据----   
  137.                     // String UPDATA_DATA =     
  138.                     // "UPDATE andy SET text='通过SQL语句来修改数据'  WHERE id=1";     
  139.                     // sqlitedb.execSQL(UPDATA_DATA);     
  140.                     tv.setText("修改数据成功!");  
  141.                       
  142.                 }else if(v == btn_deleteOne){  //5.删除一条记录   
  143.                     //----第1种方式删除数据----   
  144.                     sqlitedb.delete("andy", MySQLiteOpenHelper.ID + "= 1"null);  
  145.                     //public int delete(String table, String whereClause, String[] whereArgs)解说   
  146.                     //[1]参数table:需要操作的表名   
  147.                     //[2]参数whereClause:删除的条件   
  148.                     //[3]参数whereArgs:删除条件对应的值   
  149.                       
  150.                     //----第2种方式删除数据----   
  151.                     //String DELETE_DATA = "DELETE FROM andy WHERE id=1";    
  152.                     //sqlitedb.execSQL(DELETE_DATA);   
  153.                     tv.setText("删除数据成功!");  
  154.                       
  155.                 }else if(v == btn_deleteTable){  //6.删除数据表   
  156.                     sqlitedb.execSQL("DROP TABLE andy");  
  157.                     tv.setText("删除数据表成功!");  
  158.                       
  159.                 }  
  160.             }catch(Exception e){  
  161.                 tv.setText("操作失败");  
  162.             }finally{  
  163.                 sqlitedb.close();  
  164.             }  
  165.         }  
  166.           
  167.     }  
  168. }  

package com.andyidea.sqlite; import java.io.File; import java.io.IOException; import android.app.Activity; import android.content.ContentValues; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.TextView; import android.widget.Toast; public class MainActivity extends Activity { private Button btn_newTable,btn_addOne,btn_query, btn_editOne,btn_deleteOne,btn_deleteTable; private TextView tv; private MySQLiteOpenHelper myOpenHelper; private SQLiteDatabase sqlitedb; //----以下两个成员变量是针对在SD卡中存储数据库文件使用---- //private File path = new File("/sdcard/dbfile"); //数据库文件目录 //private File f = new File("/sdcard/dbfile/AndyDemo.db"); //数据库文件 /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); initializeViews(); //实例化默认数据库辅助操作对象 myOpenHelper = new MySQLiteOpenHelper(this); //----如要在SD卡中创建数据库文件,先做如下的判断和创建相对应的目录和文件---- //if(!path.exists()){ //判断目录是否存在 // path.mkdirs(); //创建目录 //} //if(!f.exists()){ //判断文件是否存在 // try{ // f.createNewFile(); //创建文件 // }catch(IOException e){ // e.printStackTrace(); // } //} } /** * 初始化UI界面 */ private void initializeViews(){ tv = (TextView)findViewById(R.id.tv_result); btn_newTable = (Button)findViewById(R.id.newTable); btn_addOne = (Button)findViewById(R.id.addOne); btn_query = (Button)findViewById(R.id.query); btn_editOne = (Button)findViewById(R.id.editOne); btn_deleteOne = (Button)findViewById(R.id.deleteOne); btn_deleteTable = (Button)findViewById(R.id.deleteTable); btn_newTable.setOnClickListener(new ClickEvent()); btn_addOne.setOnClickListener(new ClickEvent()); btn_query.setOnClickListener(new ClickEvent()); btn_editOne.setOnClickListener(new ClickEvent()); btn_deleteOne.setOnClickListener(new ClickEvent()); btn_deleteTable.setOnClickListener(new ClickEvent()); } class ClickEvent implements OnClickListener{ @Override public void onClick(View v) { try{ //[1]--如果是在默认的路径下创建数据库,那么实例化sqlitedb的操作如下 sqlitedb = myOpenHelper.getWritableDatabase(); //实例化数据库 //[2]--如果是在SD卡中创建数据库,那么实例化sqlitedb的操作如下 //sqlitedb = SQLiteDatabase.openOrCreateDatabase(f, null); if(v == btn_newTable){ //1.新建数据表 String TABLE_NAME = "andy"; String ID = "id"; String TEXT = "text"; String str_sql2 = "CREATE TABLE " + TABLE_NAME + "(" + ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + TEXT + " text );"; sqlitedb.execSQL(str_sql2); tv.setText("新建数据表成功!"); }else if(v == btn_addOne){ //2.插入一条记录 //----第1种插入数据的方法---- //ContentValues是一个哈希表HashMap,key值是对应数据表中字段名称, //value值是字段的值。可以通过ContentValues的put方法把数据存放到 //ContentValues对象中,然后把数据插入到相对应的数据表中。 ContentValues cv = new ContentValues(); cv.put(MySQLiteOpenHelper.TEXT, "新数据"); sqlitedb.insert(MySQLiteOpenHelper.TABLE_NAME, null, cv); //db.insert(String table, String nullColumnHack, ContentValues values);方法解说 //public long insert (String table, String nullColumnHack, ContentValues values) //该方法是向数据表中插入一条记录 //[1]参数table:需要插入操作的表名 //[2]参数nullColumnHack:默认null即可,若在插入一行数据时,若没有指定某列的值, // 则默认使用null值传入。 //[3]参数values:插入的数据 //----第2种插入数据的方法---- // String INSERT_DATA = // "INSERT INTO andy (id,text) values (1, '第2种插入数据的方法')"; // sqlitedb.execSQL(INSERT_DATA); tv.setText("添加新数据成功!"); }else if(v == btn_query){ //3.查询数据库 Cursor cur = sqlitedb.rawQuery("SELECT * FROM "+MySQLiteOpenHelper.TABLE_NAME, null); if(cur != null){ String temp = ""; int i = 0; while(cur.moveToNext()){ temp += cur.getString(0); //0代表数据列的第一列,即id temp += cur.getString(1); //1代表数据列的第二列,即text i++; temp += "/n"; //定义显示数据的格式,一行一个数据 } tv.setText(temp); } }else if(v == btn_editOne){ //4.修改一条记录 //----第1种方式修改数据---- ContentValues cv = new ContentValues(); cv.put(MySQLiteOpenHelper.TEXT, "更新后的数据"); sqlitedb.update("andy", cv, "id " + "=" + Integer.toString(1), null); //[1]参数table:需要操作的表名 //[2]参数values:ContentValues //[3]参数whereClause:更新的条件 //[4]参数whereArgs:更新条件对应的值 //----第2种方式修改数据---- // String UPDATA_DATA = // "UPDATE andy SET text='通过SQL语句来修改数据' WHERE id=1"; // sqlitedb.execSQL(UPDATA_DATA); tv.setText("修改数据成功!"); }else if(v == btn_deleteOne){ //5.删除一条记录 //----第1种方式删除数据---- sqlitedb.delete("andy", MySQLiteOpenHelper.ID + "= 1", null); //public int delete(String table, String whereClause, String[] whereArgs)解说 //[1]参数table:需要操作的表名 //[2]参数whereClause:删除的条件 //[3]参数whereArgs:删除条件对应的值 //----第2种方式删除数据---- //String DELETE_DATA = "DELETE FROM andy WHERE id=1"; //sqlitedb.execSQL(DELETE_DATA); tv.setText("删除数据成功!"); }else if(v == btn_deleteTable){ //6.删除数据表 sqlitedb.execSQL("DROP TABLE andy"); tv.setText("删除数据表成功!"); } }catch(Exception e){ tv.setText("操作失败"); }finally{ sqlitedb.close(); } } } }

 

 

MySQLiteOpenHelper辅助器类代码:

 

[c-sharp] view plain copy print ?
  1. package com.andyidea.sqlite;  
  2. import android.content.Context;  
  3. import android.database.sqlite.SQLiteDatabase;  
  4. import android.database.sqlite.SQLiteOpenHelper;  
  5. import android.util.Log;  
  6. /** 
  7.  * 此类继承了SQLiteOpenHelper抽象类,是一个辅助器类,需要  
  8.  * 一个构造函数和重写两个方法。 
  9.  * @author Andy 
  10.  */  
  11. public class MySQLiteOpenHelper extends SQLiteOpenHelper {  
  12.     public static final String DATABASE_NAME = "AndyDemo.db"//数据库名   
  13.     public static final int VERSION = 1;   //版本号   
  14.     public static final String TABLE_NAME = "andy";  //表名   
  15.     public static final String ID = "id";  
  16.     public static final String TEXT = "text";  
  17.       
  18.     public MySQLiteOpenHelper(Context context) {  
  19.         super(context, DATABASE_NAME, null, VERSION);  
  20.     }  
  21.     /** 
  22.      * 在数据库第一次生成的时候会调用这个方法,同时我们在这个方法里边生成数据库表 
  23.      */  
  24.     @Override  
  25.     public void onCreate(SQLiteDatabase db) {  
  26.         //创建数据表的操作   
  27.         String strSQL = "CREATE TABLE " + TABLE_NAME + "(" + ID    
  28.         + " INTEGER PRIMARY KEY AUTOINCREMENT," + TEXT + " text );";    
  29.           
  30.         db.execSQL(strSQL);  
  31.     }  
  32.     /** 
  33.      * 更新或者升级数据库的时候会自动调用这个方法,一般我们会在这个方法中 
  34.      * 删除数据表,然后再创建新的数据表操作。 
  35.      */  
  36.     @Override  
  37.     public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {  
  38.         Log.e("AndyDemo""onUpgrade");    
  39.     }  
  40. }  

package com.andyidea.sqlite; import android.content.Context; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import android.util.Log; /** * 此类继承了SQLiteOpenHelper抽象类,是一个辅助器类,需要 * 一个构造函数和重写两个方法。 * @author Andy */ public class MySQLiteOpenHelper extends SQLiteOpenHelper { public static final String DATABASE_NAME = "AndyDemo.db"; //数据库名 public static final int VERSION = 1; //版本号 public static final String TABLE_NAME = "andy"; //表名 public static final String ID = "id"; public static final String TEXT = "text"; public MySQLiteOpenHelper(Context context) { super(context, DATABASE_NAME, null, VERSION); } /** * 在数据库第一次生成的时候会调用这个方法,同时我们在这个方法里边生成数据库表 */ @Override public void onCreate(SQLiteDatabase db) { //创建数据表的操作 String strSQL = "CREATE TABLE " + TABLE_NAME + "(" + ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + TEXT + " text );"; db.execSQL(strSQL); } /** * 更新或者升级数据库的时候会自动调用这个方法,一般我们会在这个方法中 * 删除数据表,然后再创建新的数据表操作。 */ @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { Log.e("AndyDemo", "onUpgrade"); } }

 

 

当我们需要把数据库创建在SDCard中时,需要在AndroidManifest.xml文件中添加对SDCard操作的权限,如下:

 

[c-sharp] view plain copy print ?
  1. <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />  
  2.     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />  

<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

 

通过以上步骤的操作,对SQLite数据库的操作有了大概的认识。下面我们来看看程序运行的效果。

由于该Demo的代码比较多,需要该源码的请到资源中下载:http://download.csdn.net/detail/cjjky/4236087,谢谢。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值