今天心情有些不爽, 原来之前内存溢出的原因不是手机硬件的问题, 是我代码写的有问题==
开始模拟的场景是这样的== 连后台取大JSON串,解析-转成相应对象-存入数据库; 由于后台暂时没有数据,所以只能自己模拟测试数据; 那么我的策略是这样的: 连续new出来目标数据的对象数放置到一个list中,然后再将这个list异步插入到数据库中;看似没有问题, 但是一直以来我都忽略了一个非常重要的问题,大数据! 万一有300W条记录呢? 你要new300W个对象吗? 开玩笑······· 所以这几天难为我的小米2了,一直认为它不给力, 不到100W就内存溢出·· 现在想起来, 其实已经很够给力的了;
这300W个对象的内存占用可不是闹着玩的··········· 所以我只能换种思路;
1. 我不通过new对象的形式向数据库中插入对象,反正我最终要的是模拟数据, 我直接用db.exel();循环向里面插入数据不也是一样的吗? 这样一来那300W个对象不就可以不用创建了吗? 为什么自己没早些考虑这方面的问题、 经验教训呐
2. 今天去咨询了兄弟开发IOS那边, 给了我几个比较有参考性的意见:
可以将每次提交的记录数减少==少量多次, 将300W条记录每1000条记录提交一次; 那么就可以缓解写入的数据库压力;
看看模拟的对象占用的内存是否已经将栈空间填满, 其实我考虑到运行时内存这个概念了,但是水平不够,没能往下思考;
在线解析JSON大字符串这个策略是不科学的,一方面耗时,其二万一中途网络中断,要考虑到断点续传?所以只能剩下其中2中方式可行:1,第一次安装的时候就先带一个数据库文件放置SD卡上,用程序读这个SD卡内容;或者在线下载一个压缩包,本地解压,然后在读;2,当后续有增量数据产生时,如果数据量小,可以采用在线解析JSON然后添加到数据库中; 如果数据量较大,考虑分批获取数据=少量多次请求数据; 如果间隔时间的确较长,参考后台给的数据压缩规则, 实在不行就重新获取新数据包,覆盖之前的数据;
3. 考虑了下, 我还是要模拟下从程序中读取sd卡中的数据库文件比较靠谱;用可视化工具做了个简单的数据库文件, 然后copy到SD卡中,开始模拟读取;
按照惯例, 先爆几张过程图看看流程==通过SQLite Developer可视化工具生成DB文件:
数据库文件已经拷贝到SD卡根目录下===
运行效果== 此处我只是做了查询处理,添加功能暂时未做,可根据上图结构自行添加:
说说以下测试程序的构成:
1. 傻瓜式布局;
2.从外界获取的数据库文件存放至SD卡的根目录;
3.manifest文件添加读写权限;
4.写一个openHelper数据库操作帮助类;
5.按照数据库表结构建立相应的实体类(entity or bean);
6.activity的数据展现;
【布局】
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <EditText android:id="@+id/input" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="请输入要插入的数据"/> <EditText android:id="@+id/input_detail" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="输入数据的详细信息"/> <Button android:id="@+id/addBtn" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="点击添加"/> <EditText android:id="@+id/showContext" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="显示查询数据"/> <Button android:id="@+id/searchBtn" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="点击查询"/> <TextView android:id="@+id/show_textview" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="TextView" /> </LinearLayout>
【权限】
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
【openHelper帮助类】
package com.example.test_sqlite; import java.io.File; import java.util.ArrayList; import java.util.List; import com.example.test_sqlite.entity.MainData; import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; public class MyDBHelper extends SQLiteOpenHelper{ //数据库文件在SD卡中,此时必须用全限定名!! 默认路径在/data/data/databases/testDBinSD.sqlite, 但私密数据外界看不到-除非root。 private static final String SQL_NAME = "/sdcard/testDBinSD.sqlite";//数据库名称。//Environment.getExternalStorageDirectory().getPath() + "testDBinSD.sqlite";// private static final String MAIN_DATA_TABLE_NAME = "maindata";//表名。 private static final String MAIN_DATA_ID = "id";//表的4个字段 private static final String MAIN_DATA_NAME = "name"; private static final String MAIN_DATA_SEX = "sex"; private static final String MAIN_DATA_GRADE = "grade"; //构造方法 public MyDBHelper(Context context) { super(context, SQL_NAME, null, 1); } @Override public void onCreate(SQLiteDatabase db) { //建表 String mainDataSQL = "create table if not exists " + MAIN_DATA_TABLE_NAME + "(" + MAIN_DATA_ID + " varchar(20), " + MAIN_DATA_NAME + " varchar(20), " + MAIN_DATA_SEX + " varchar(20), " + MAIN_DATA_GRADE + " varchar(20));"; db.execSQL(mainDataSQL); } //读文件获取记录。 public List<MainData> getMainData() { String mainDataSQL = "select * from "+MAIN_DATA_TABLE_NAME+""; File name = new File(SQL_NAME); SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(name, null);//读SD卡数据库必须如此--用静态方法打开数据库。 Cursor cursor = db.rawQuery(mainDataSQL, null); List<MainData> dataList = new ArrayList<MainData>(); if (cursor != null) { while (cursor.moveToNext()) {//直到返回false说明表中到了数据末尾 MainData data = new MainData(); data.setId(cursor.getString(0)); data.setName(cursor.getString(1)); data.setSex(cursor.getString(2)); data.setGrade(cursor.getString(3)); dataList.add(data); } } cursor.close(); db.close(); return dataList; } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { } }
【实体类】
package com.example.test_sqlite.entity; public class MainData { private String id; private String name; private String sex; private String grade; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public String getGrade() { return grade; } public void setGrade(String grade) { this.grade = grade; } }
【activity数据查询-展现】
package com.example.test_sqlite; import java.util.List; import com.example.test_sqlite.entity.MainData; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; import android.app.Activity; public class MainActivity extends Activity implements OnClickListener { private MyDBHelper dbHelper;//SQLite帮助类 private EditText input; private EditText inputDetail; private Button addBtn; private EditText showContent; //最主要功能是下面的俩=== 点击查询--数据呈现。 private Button searchBtn; private TextView showText; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); dbHelper = new MyDBHelper(this); input = (EditText) findViewById(R.id.input); inputDetail = (EditText) findViewById(R.id.input_detail); addBtn = (Button) findViewById(R.id.addBtn); showContent = (EditText) findViewById(R.id.showContext); searchBtn = (Button) findViewById(R.id.searchBtn); showText = (TextView) findViewById(R.id.show_textview); addBtn.setOnClickListener(this); searchBtn.setOnClickListener(this); } @Override public void onClick(View v) { if(v.getId() == R.id.addBtn) { // handleInsertDB(); } else if(v.getId() == R.id.searchBtn) { handleSearchDB(); } } private void handleSearchDB() { //查询sql。返回记录集合。 List<MainData> dataList = dbHelper.getMainData(); StringBuilder sb = new StringBuilder(); for(MainData data : dataList) { sb.append(data.getId()).append("-").//循环将记录拼接起来方便显示。 append(data.getName()).append("-").append(data.getSex()). append("-").append(data.getGrade()).append("-\n").toString(); } showText.setText(sb);//显示结果。 } private void handleInsertDB() { } }
说明从SD卡中读取SQLite文件是可以实现的============
那么同事给我的那些建议是可行的, 明天去公司试试, 哦不对, 今上午~
要睡觉了, 已经吵着基友睡觉了·························为了写博客,影响不少人啊、