我不确定这个问题是否在这里,但我想问你们所有人,他们真的可以给我一些如何优化这段代码的建议,以正确的方式运行得更好快点。我正在做的事情是我通过互联网下载数据作为JSON,解析它并将其插入sqlite数据库。如果json字符串不大,对我来说没有什么大问题,但是当我的json在某些情况下包含很多数组和对象时,我等待10-13分钟来下载/解析/插入数据库中的所有数据,这是太多的时间。
我展示的代码是某种测试代码,因为我试图实现InsertHelper
以查看速度是否会有一点差异,但结果现在是相同的。这是代码:
UserDatabaseHelper userDbHelper = RPCCommunicator.rpcUserDbHelper;
SQLiteDatabase db = userDbHelper.getWritableDatabase();
InsertHelper ih = new InsertHelper(db, "cards");
ih.prepareForInsert();
//ContentValues values = new ContentValues();
ContentValues valuess = new ContentValues();
try {
int objectid = ih.getColumnIndex("objectId");
ih.bind(objectid, objectId);
//values.put("objectId", objectId);
Log.d("", "ObjectId: " + objectId);
int objectoid = ih.getColumnIndex("objectOid");
ih.bind(objectoid, objectOid);
//values.put("objectOid", objectOid);
String jsonData = new String(cardBuffer, "UTF-8");
Log.d("JSONDATA", "JSONDATA VALID OR NOT : " + jsonData);
json = new JSONObject(jsonData);
JSONObject jsonObj = (JSONObject) new JSONTokener(jsonData).nextValue();
int collectionID = ih.getColumnIndex("collectionId");
int collectionId = Integer.parseInt(jsonObj.optString("collection_id","0"));
Log.d("Collection Id ", "Show Collection Id : " + collectionId);
if(collectionId!=0)
ih.bind(collectionID, collectionId);
//values.put("collectionId", collectionId);
int categoryID = ih.getColumnIndex("categoryId");
int categoryId = Integer.parseInt(jsonObj.optString("category_id", "0"));
Log.d("Category Id ", "Show Category Id : " + categoryId);
if(categoryId!=0)
ih.bind(categoryID, categoryId);
//values.put("categoryId", categoryId);
int dateCreated = ih.getColumnIndex("dateCreated");
String date = jsonObj.optString("date_created");
if(date!=null)
ih.bind(dateCreated, date);
//values.put("dateCreated", date);
int titlee = ih.getColumnIndex("title");
String title = jsonObj.optString("title");
Log.d("Title", "Show Title : " + title);
if(title!=null)
ih.bind(titlee, title);
//values.put("title", title);
// ... some other variables to get from JSON
JSONObject stats = jsonObj.optJSONObject("statistics");
if (jsonObj.has("statistics")) {
ContentValues values2 = new ContentValues();
InsertHelper ihr = new InsertHelper(db, "cardstats");
Iterator<Object> keys = stats.keys();
while (keys.hasNext()) {
ihr.prepareForInsert();
String key = (String) keys.next();
JSONObject obj = new JSONObject();
obj = stats.getJSONObject(key);
int paramId = Integer.parseInt(obj.optString("param_id"));
int cardIdTable = ihr.getColumnIndex("cardId");
ihr.bind(cardIdTable, objectId);
values2.put("cardId", objectId);
int statKey = ihr.getColumnIndex("statKeyId");
ihr.bind(statKey, paramId);
values2.put("statKeyId", paramId);
int catIdTable = ihr.getColumnIndex("catId");
int catId = Integer.parseInt(obj.optString("cat_id"));
ihr.bind(catIdTable, catId);
values2.put("catId", catId);
int paramtitle = ihr.getColumnIndex("title");
String paramTitle = obj.optString("param_title");
ihr.bind(paramtitle, paramTitle);
values2.put("title", paramTitle);
String cardstats = "SELECT cardId , statKeyId FROM cardstats WHERE cardId="+objectId+" AND statKeyId="+catId;
Cursor cardStats = userDbHelper.executeSQLQuery(cardstats);
if(cardStats.getCount()==0){
//userDbHelper.executeQuery("cardstats", values2);
ihr.execute();
} else {
for(cardStats.moveToFirst(); cardStats.moveToNext(); cardStats.isAfterLast()){
//int card = Integer.parseInt(cardStats.getString(cardStats.getColumnIndex("cardId")));
int statId = Integer.parseInt(cardStats.getString(cardStats.getColumnIndex("statKeyId")));
if(paramId != statId){
ihr.execute();
//userDbHelper.executeQuery("cardstats", values2);
} else {
userDbHelper.updateSQL("cardstats", values2, "cardId=?", new String[]{Integer.toString(objectId)});
}
}
}
cardStats.close();
//userDbHelper.executeQuery("cardstats", values2);
}
}// end if
String sql = "SELECT objectId FROM cards WHERE objectId = " + objectId;
Cursor cursor = userDbHelper.executeSQLQuery(sql);
if (cursor.getCount() == 0) {
ih.execute();
//userDbHelper.executeQuery("cards", values);
} else {
for (cursor.move(0); cursor.moveToNext(); cursor.isAfterLast()) {
int objectID = Integer.parseInt(cursor.getString(cursor.getColumnIndex("objectId")));
Log.d("","objectId : objectID - "+objectId+" "+objectID );
if (objectId != objectID) {
ih.execute();
//userDbHelper.executeQuery("cards", values);
} else if(objectId == objectID){
userDbHelper.updateSQL("cards", valuess, "objectId=?", new String[] {Integer.toString(objectId)});
}
}
}
cursor.close();
} catch (Exception e) {
e.printStackTrace();
Log.d("Error", ": " + e);
}
db.close();
return true;
}
* 修改:*
以下是我如何保存从互联网上获取的二进制数据(图像):
public static void saveToExternalStorage(String servername, int userId, String filename, byte[] buffer){
try {
File myDir=new File("/sdcard/.Stampii/Users/"+servername+"/"+userId+"/Storage");
myDir.mkdirs();
File file = new File(myDir, filename);
FileOutputStream fos = new FileOutputStream(file);
fos.write(buffer);
fos.flush();
fos.close();
} catch (FileNotFoundException e){
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
所以欢迎任何类型的建议/建议,这将有助于我改进这段代码并使其运行得更快。
提前致谢!
答案 0 :(得分:2)
即使您拥有大量HTTP流量(您似乎拥有),您仍然可以优化数据库的使用。
这个做出10000次插入的天真例子将向您展示我们在这里谈论的改进规模:
public class BombasticActivity extends Activity {
DBHelper mHelper;
SQLiteDatabase mDb;
InsertHelper mInsertHelper;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mHelper = new DBHelper(this);
mDb = mHelper.getWritableDatabase();
mInsertHelper = new InsertHelper(mDb, "table1");
}
@Override
protected void onStart() {
super.onStart();
AsyncTask.SERIAL_EXECUTOR.execute(new MeasureTime(new Insert(10000, mInsertHelper)));
AsyncTask.SERIAL_EXECUTOR.execute(new MeasureTime(new DoInTransaction(mDb, new Insert(10000, mInsertHelper))));
}
@Override
protected void onDestroy() {
super.onDestroy();
mInsertHelper.close();
mDb.close();
mHelper.close();
}
static class MeasureTime implements Runnable {
final Runnable mAction;
MeasureTime(Runnable action) {
mAction = action;
}
public void run() {
final String name = mAction.getClass().getSimpleName();
System.out.println("Starting action (" + name + ")");
long t0 = System.currentTimeMillis();
try {
mAction.run();
} finally {
t0 = System.currentTimeMillis() - t0;
System.out.println("Time to complete action (" + name + "): " + t0 + "ms");
}
}
}
static class DoInTransaction implements Runnable {
final Runnable mAction;
final SQLiteDatabase mDb;
DoInTransaction(SQLiteDatabase db, Runnable action) {
mAction = action;
mDb = db;
}
public void run() {
mDb.beginTransaction();
try {
mAction.run();
mDb.setTransactionSuccessful();
} finally {
mDb.endTransaction();
}
}
}
static class Insert implements Runnable {
final int mNumberOfInserts;
final InsertHelper mInsertHelper;
Insert(int numberOfInserts, InsertHelper insertHelper) {
mNumberOfInserts = numberOfInserts;
mInsertHelper = insertHelper;
}
public void run() {
Random rnd = new Random(0xDEADBEEF);
ContentValues values = new ContentValues();
for (int i = 0; i < mNumberOfInserts; i++) {
values.put("text1", String.valueOf(rnd.nextDouble()));
values.put("text2", String.valueOf(rnd.nextFloat()));
values.put("text3", String.valueOf(rnd.nextLong()));
values.put("int1", rnd.nextInt());
mInsertHelper.insert(values);
if (i % 200 == 0) {
System.out.println("Done " + i + " inserts");
}
}
}
}
}
class DBHelper extends SQLiteOpenHelper {
DBHelper(Context context) {
super(context.getApplicationContext(), "bombastic", null, 1);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE table1 (_id INTEGER PRIMARY KEY AUTOINCREMENT, text1 TEXT, text2 TEXT, text3 TEXT, int1 INTEGER)");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
在ICS设备上(如果启动线程或线程池而不是滥用AsyncTask.SERIAL_EXECUTOR
,可以在Gingerbread上运行)非事务版本需要将近4分钟才能完成(229484ms) )在事务中运行的版本只需要大约3秒(2975毫秒)。
所以很快就把它做,做很多更新 - 在交易中做。
要优化HTTP,您应该确保保持HTTP连接处于活动状态(保持活动状态)并下载更大的块。比您现在正在做的要大得多 - 如果可能的话,切换到支持从流中读取的JSON解析器,而不是在解析之前将整个事物加载到String
。
答案 1 :(得分:1)
您的案件涉及两项耗时的活动。
一个。下载数据包中的数据(假设它是HTTP)。对于单个数据包,它应该需要大约1-3秒,具体取决于网络延迟。 对于200 = 2X100 = 200秒~3分钟 如果您以不超过3-5次往返呼叫的方式下载整个数据,则可以节省大量秒数。
湾数据库插入 你需要做文件操作专门写文件操作需要时间。老实说,你不能在这里做太多优化
检查我的其他答案here