我正在开发一个Android应用程序。在其中我使用SQLiteDatabase
。这个数据库有很多数据,当我启动应用程序时,它分配大约85mb的RAM,这太多了。
我正在寻求帮助来优化这一点。欢迎任何帮助,指出改进,任何明显的问题,甚至是减少问题的来源。
作为来源,请检查Android Studio上LogCat
中的“已分配内存:”Allocated memory image
数据库代码:
public class DataBase extends SQLiteOpenHelper {
private static String DB_PATH = "";
private static String DB_NAME = "Dastansara";
private static int DB_VERSION = 1;
private SQLiteDatabase sqLiteDatabase;
private final Context myContext;
/**
* Constructor
* Takes and keeps a reference of the passed context in order to access to the application assets and resources.
*
* @param context
*/
public DataBase(Context context) {
super(context, DB_NAME, null, DB_VERSION);
if (android.os.Build.VERSION.SDK_INT >= 17) {
DB_PATH = context.getApplicationInfo().dataDir + "/databases/";
} else {
DB_PATH = "/data/data/" + context.getPackageName() + "/databases/";
}
this.myContext = context;
}
@Override
public void onCreate(SQLiteDatabase db) {
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
/**
* Creates a empty database on the system and rewrites it with your own database.
*/
public void createDataBase() throws IOException {
boolean dbExist = checkDataBase();
SQLiteDatabase sqLiteDatabase = null;
if (dbExist) {
// do nothing - database alerdy exist
} else {
sqLiteDatabase = this.getReadableDatabase();
sqLiteDatabase.close();
try {
copyDataBase();
} catch (IOException e) {
throw new Error("Error copying database");
}
}
}
/**
* Check if the database already exist to avoid re-copying the file each time you open the application.
*
* @return true if it exists, false if it doesn't
*/
public boolean checkDataBase2() {
SQLiteDatabase checkDB = null;
try {
String myPATH = DB_PATH + DB_NAME;
checkDB = SQLiteDatabase.openDatabase(myPATH, null, SQLiteDatabase.OPEN_READONLY);
} catch (SQLiteException e) {
/// database does't exist yet
}
if (checkDB != null) {
checkDB.close();
}
return checkDB != null ? true : false;
}
public boolean checkDataBase() {
File dbFile = new File(DB_PATH+DB_NAME);
return dbFile.exists();
}
/**
* Open DataBase
*
* @throws SQLException
*/
public void openDataBase() throws SQLException {
String myPATH = DB_PATH + DB_NAME;
sqLiteDatabase = SQLiteDatabase.openDatabase(myPATH, null, SQLiteDatabase.OPEN_READONLY);
}
public DataBase writeDataBase() throws android.database.SQLException{
DataBase dataBase = new DataBase(myContext);
sqLiteDatabase = dataBase.getWritableDatabase();
return this;
}
/**
* Close DataBase
*/
public void closeDataBase() {
sqLiteDatabase.close();
}
/**
* Copies your database from your local assets-folder to the just created empty database in the
* system folder, from where it can be accessed and handled.
* This is done by transfering bytestream.
*/
public void copyDataBase() throws IOException {
//Open your local db as the input stream
InputStream myInput = myContext.getAssets().open(DB_NAME);
// Path to the just created empty db
String myPath = DB_PATH + DB_NAME;
//Open the empty db as the output stream
OutputStream myOutput = new FileOutputStream(myPath);
byte[] buffer = new byte[1024];
int length;
//transfer bytes from the inputfile to the outputfile
while ((length = myInput.read(buffer)) != -1) {
if (length > 0){
myOutput.write(buffer, 0, length);
}
}
//Close the streams
myOutput.flush();
myOutput.close();
myInput.close();
}
public Cursor getCat1_Datas(SQLiteDatabase sqLiteDatabase) {
try {
String query = "SELECT * FROM tbl_Book WHERE Cat_ID = ?";
Cursor cursor = sqLiteDatabase.rawQuery(query, new String[] {"1"});
if (cursor != null) {
cursor.moveToNext();
}
return cursor;
} catch (SQLException e) {
Log.e("Data Adapter", "getTestData >>" + e.toString());
throw e;
}
}
public Cursor getCat2_Datas(SQLiteDatabase sqLiteDatabase) {
try {
String query = "SELECT * FROM tbl_Book WHERE Cat_ID = ?";
Cursor cursor = sqLiteDatabase.rawQuery(query, new String[] {"2"});
if (cursor != null) {
cursor.moveToNext();
}
return cursor;
} catch (SQLException e) {
Log.e("Data Adapter", "getTestData >>" + e.toString());
throw e;
}
}
public Cursor getCat3_Datas(SQLiteDatabase sqLiteDatabase) {
try {
String query = "SELECT * FROM tbl_Book WHERE Cat_ID = ?";
Cursor cursor = sqLiteDatabase.rawQuery(query, new String[] {"3"});
if (cursor != null) {
cursor.moveToNext();
}
return cursor;
} catch (SQLException e) {
Log.e("Data Adapter", "getTestData >>" + e.toString());
throw e;
}
}
public Cursor getCat4_Datas(SQLiteDatabase sqLiteDatabase) {
try {
String query = "SELECT * FROM tbl_Book WHERE Cat_ID = ?";
Cursor cursor = sqLiteDatabase.rawQuery(query, new String[] {"4"});
if (cursor != null) {
cursor.moveToNext();
}
return cursor;
} catch (SQLException e) {
Log.e("Data Adapter", "getTestData >>" + e.toString());
throw e;
}
}
public Cursor getAllCats_Datas(SQLiteDatabase sqLiteDatabase) {
try {
String query = "SELECT * FROM tbl_Book";
Cursor cursor = sqLiteDatabase.rawQuery(query, null);
if (cursor != null) {
cursor.moveToNext();
}
return cursor;
} catch (SQLException e) {
Log.e("Data Adapter", "getTestData >>" + e.toString());
throw e;
}
}
@Override
public synchronized void close() {
if (sqLiteDatabase != null) {
sqLiteDatabase.close();
}
super.close();
}
}
第一个片段代码:
public class Cat1_fragment_recycler extends Fragment {
DataProvider dataProvider;
DataBase dataBase;
private SQLiteDatabase sqLiteDatabase;
Cursor cursor;
ListView listView;
private SuperRecyclerView recycler;
fragment_RecyclerAdapter adapter;
SwipeableRecyclerViewTouchListener swipeTouchListener;
@Override
public View onCreateView(final LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.recycler__page,
container, false);
adapter = new fragment_RecyclerAdapter(getContext());
dataBase = new DataBase(getContext());
sqLiteDatabase = dataBase.getReadableDatabase();
cursor = dataBase.getAllCats_Datas(sqLiteDatabase);
recycler = (SuperRecyclerView) rootView.findViewById(R.id.recyclerView);
//recycler.setHasFixedSize(true);
recycler.setLayoutManager(new LinearLayoutManager(getActivity()));
ScaleInAnimationAdapter alphaAdapter = new ScaleInAnimationAdapter(adapter);
SlideInBottomAnimationAdapter scaleAdapter = new SlideInBottomAnimationAdapter(alphaAdapter);
scaleAdapter.setInterpolator(new OvershootInterpolator());
recycler.setAdapter(scaleAdapter);
if (cursor.moveToFirst()) {
do {
String title, id, description, fav, cat_id;
byte[] image;
id = cursor.getString(0);
cat_id = cursor.getString(1);
title = cursor.getString(2);
description = cursor.getString(3);
image = cursor.getBlob(4);
fav = cursor.getString(5);
dataProvider = new DataProvider(id,cat_id, title,description, image, fav);
adapter.add(dataProvider);
} while (cursor.moveToNext());
}
dataBase.close();
return rootView;
}
}
主要活动代码:
public class MainActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener {
private Toolbar toolbar;
private DrawerLayout mDrawerLayout;
private ViewPager viewPager;
private TabLayout tabLayout;
private DataBase dataBase;
private Cat1_frag_AsyncTask task;
private NavigationView mNaviView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
dataBase = new DataBase(this);
try {
dataBase.createDataBase();
} catch (IOException e) {
e.printStackTrace();
}
toolbar = (Toolbar) findViewById(R.id.main_toolbar);
setSupportActionBar(toolbar);
TextView toolbar_text = (TextView) findViewById(R.id.toolbar_title);
toolbar_text.setText(R.string.app_name_fa);
final ActionBar actionBar = getSupportActionBar();
actionBar.setTitle("");
actionBar.setHomeAsUpIndicator(R.drawable.ic_menu_driver);
actionBar.setDisplayHomeAsUpEnabled(true);
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
if (navigationView != null) {
setupDrawerContent(navigationView);
}
viewPager = (ViewPager) findViewById(R.id.main_viewPager);
if (viewPager != null) {
setupViewPager(viewPager);
}
tabLayout = (TabLayout) findViewById(R.id.main_tabs);
if (tabLayout != null) {
tabLayout.setupWithViewPager(viewPager);
}
mNaviView = (NavigationView) findViewById(R.id.nav_view);
mNaviView.setNavigationItemSelectedListener(this);
//// Navigation Drawer custom font
Menu menu_mNaviView = mNaviView.getMenu();
for (int i = 0; i < menu_mNaviView.size(); i++) {
MenuItem mi = menu_mNaviView.getItem(i);
applyFontToMenuItem(mi);
}
}
private void applyFontToMenuItem(MenuItem mi) {
Typeface font = Typeface.createFromAsset(getAssets(), "fonts/vazir.ttf");
SpannableString mNewTitle = new SpannableString(mi.getTitle());
mNewTitle.setSpan(new CodeSaz_CustomTypefaceSpan("", font), 0, mNewTitle.length(), Spannable.SPAN_INCLUSIVE_INCLUSIVE);
mi.setTitle(mNewTitle);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_main_page, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
mDrawerLayout.openDrawer(GravityCompat.START);
case R.id.action_recyclerView:
startActivity(new Intent(getApplicationContext(), Swipe_Recycler.class));
}
return super.onOptionsItemSelected(item);
}
@Override
public boolean onNavigationItemSelected(MenuItem item) {
if (item.getItemId() == R.id.action_recyclerView) {
startActivity(new Intent(this, Recycler_Page.class));
return true;
}
return false;
}
private void setupViewPager(ViewPager viewPager) {
Main_frag_adapter mainFragAdapter = new Main_frag_adapter(getSupportFragmentManager());
mainFragAdapter.addFragment(new Cat1_fragment_recycler(), "آموزنده");
mainFragAdapter.addFragment(new Cat1_fragment_recycler(), "عاشقانه");
mainFragAdapter.addFragment(new Cat1_fragment_recycler(), "بزرگان");
mainFragAdapter.addFragment(new Cat1_fragment_recycler(), "متفرقه");
viewPager.setAdapter(mainFragAdapter);
}
private void setupDrawerContent(NavigationView navigationView) {
navigationView.setNavigationItemSelectedListener(
new NavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(MenuItem menuItem) {
menuItem.setChecked(true);
mDrawerLayout.closeDrawers();
return true;
}
});
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
private void forceRTLIfSupported() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
getWindow().getDecorView().setLayoutDirection(View.LAYOUT_DIRECTION_RTL);
}
}
}
如何在Allocated内存中设置?请帮我说一下在应用程序中使用数据库的优化方式。 tnx all&lt; 3
注意:请查看此代码并说明我的问题在哪里?!请不要给我负面的意见,请帮助我!
答案 0 :(得分:0)
您的代码存在一些明显的问题,但也许您应该在消除问题的情况下进行更多调查。
对DataBase
类使用Singleton Pattern,因为创建DataBase
对象非常昂贵。
完成游标后关闭游标。不要打开你的游标。
实际上不需要关闭数据库,您可以使用应用程序Context
(而不是您的活动Context
)创建实例,并在您的应用程序的生命周期中使用它,但我认为您完成后应该关闭Cursor
。
还有一些其他优化,例如您只能使用TypeFace
类的一个对象,而不是为菜单的每个项目创建一个。
我看到你使用字节数组来存储图像,因为我不知道你是如何使用它们的,我无法确定,但我想你会遇到一些麻烦他们,也许你可以粘贴你的适配器代码。
最后一件事是您可以使用Eclipse MAT和LeakCanary来检测内存泄漏。