在写蓝牙Contacts的时候,遇到一个问题,多联系人(最少1000+)插入导致应用程序死掉,因为我们写的蓝牙不是设备的标准蓝
牙,自己焊接的,协议都是不同的,数据传递虽然都是一样的方式,但是驱动和连接协议有别于标准蓝牙,这里就不细说了,
直接切入主题,解决这个蓝牙跟车机设备联系人同步的问题
先前有几个客户反馈说,在测试我们蓝牙应用的时候,说联系人超1000+的时候,或者超了300+,都会导致程序死掉,或者上传很慢,因为先前蓝牙应用
是其他同事写的,不知道这个情况,之后一个朋友(袁工)说建议采用事物处理,我今天亲测了,确实事物跟单事物插入的效果真是天差地别啊!好明
显!!
首先说说事物,直截了当的说吧,每一个语句就是一个事物,然后频繁的操作 SQLite 会导致应用缓不过来,而我们可以把要做的操作全部归纳到一个事
物里面去,需要我们调用三个函数
SQLiteDatabase db:
db.beginTransaction(); // 开启事务
db.setTransactionSuccessful();// 设置事物标志为成功,当结束事物时就会提交事物
db.endTransaction();//事物结束
SQLiteOpenHelper Demo:
package com.example.uploadphonebook; import android.content.Context; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import android.util.Log; public class PhoneBookeHelper extends SQLiteOpenHelper{ @SuppressWarnings("unused") private Context mContext; private static PhoneBookeHelper mPhoneBookeHelper; public static final String DB_NAME = "phonebook"; public static final String ID = "_id"; public static final String NAME = "name"; public static final String NUMBER = "number"; private static final int VERSION = 1; private static final String BOOK_TABLE_NAME = "contacts"; public static final String CREATE_TABLE = String .format("create table if not exists %s (%s integer primary key autoincrement, %s text, %s text)", BOOK_TABLE_NAME, ID,NAME, NUMBER); private PhoneBookeHelper(Context context) { super(context, DB_NAME, null, VERSION); this.mContext = context; Log.d("BlueTooth_Navi_Call", "SQLiteatabase is Create..."); } public static PhoneBookeHelper getPhoneBook(Context context){ if(mPhoneBookeHelper==null){ mPhoneBookeHelper = new PhoneBookeHelper(context); Log.d("BlueTooth_Navi_Call", "mPhoneBookeHelper is null..."); } Log.d("BlueTooth_Navi_Call", "mPhoneBookeHelper is not null..."); return mPhoneBookeHelper; } @Override public void onCreate(SQLiteDatabase db) { db.execSQL(CREATE_TABLE); Log.d("BlueTooth_Navi_Call", "SQLite Database Table is Create..."); } @Override public void onUpgrade(SQLiteDatabase arg0, int arg1, int arg2) { } public void insertContacts(){ Log.d("BlueTooth_Navi_Call", "SQLite Database Start is insert..."); SQLiteDatabase db = getWritableDatabase(); db.beginTransaction();// 开启事务 try { for(int i = 0;i<=10000;i++){ String name = "Tom"+i; String number = "185"+Math.random()*100000000; String url = "insert into contacts (name,number) values(?,?)"; db.execSQL(url, new String[]{name,number}); Log.d("BlueTooth_Navi_Call", "******************************"+name +" "+ number+"******************************"); } db.setTransactionSuccessful();// 设置事物标志为成功,当结束事物时就会提交事物 } finally{ db.endTransaction(); } db.close(); Log.d("BlueTooth_Navi_Call", "SQLite Database end for insert..."); } }
插入Demo:
package com.example.uploadphonebook; import android.os.Bundle; import android.os.Handler; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.app.Activity; public class MainActivity extends Activity implements OnClickListener{ private PhoneBookeHelper mPhoneBookeHelper; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button upload = (Button)findViewById(R.id.Upload); upload.setOnClickListener(this); mPhoneBookeHelper = PhoneBookeHelper.getPhoneBook(this); } @Override public void onClick(View view) { Log.d("BlueTooth_Navi_Call", "UploadPhoneBook is Start..."); mHandler.sendEmptyMessage(0); // new Thread(new Runnable() { // @Override // public void run() { // mPhoneBookeHelper.insertContacts(); // Log.d("BlueTooth_Navi_Call", "UploadPhoneBook is Successful"); // Toast.makeText(getApplicationContext(), "UploadPhoneBook is Successful", Toast.LENGTH_SHORT).show(); // } // }).start(); } private Handler mHandler = new Handler(){ public void handleMessage(android.os.Message msg) { int code = msg.what; switch (code) { case 0: mPhoneBookeHelper.insertContacts(); break; } } }; }
大家需要注意的是,在Activity里新建线程的时候,它是不能直接访问Activity里的UI组件的,需要用Handler或者AsynTask来处理,否者会抛出Exception:
java.lang.RuntimeException: Can‘t create handler inside thread that has not called Looper.prepare()
所以我在按钮事件里调用sendEmptyMessage()函数,执行插入操作
经测试,插入1000+, 耗时0.9s,而单事物耗时将近7s
10000+,耗时12左右,单事物2分09s
所以效果是很明显的,下面看看实测对比图:
单事物插入,1000+测试:
for(int i = 0;i<=1000;i++){ String name = "Tom"+i; String number = "185"+Math.random()*100000000; String url = "insert into contacts (name,number) values(?,?)"; db.execSQL(url, new String[]{name,number}); Log.d("BlueTooth_Navi_Call", "******************************"+name +" "+ number+"******************************"); }
归纳事物,1000+测试:
db.beginTransaction();// 开启事务 try { for(int i = 0;i<=1000;i++){ String name = "Tom"+i; String number = "185"+Math.random()*100000000; String url = "insert into contacts (name,number) values(?,?)"; db.execSQL(url, new String[]{name,number}); Log.d("BlueTooth_Navi_Call", "******************************"+name +" "+ number+"******************************"); } db.setTransactionSuccessful();// 设置事物标志为成功,当结束事物时就会提交事物 } finally{ db.endTransaction(); } db.close(); Log.d("BlueTooth_Navi_Call", "SQLite Database end for insert...");
1000+ 耗时-对比图:
10000+ 测试代码同上,就是多了一个0而已,耗时对比图:
效果是不是很明显?误差不是很大估计也就1s左右~