如何在分配的内存中优化android应用程序

时间:2016-03-14 12:33:08

标签: android android-database

我正在开发一个Android应用程序。在其中我使用SQLiteDatabase。这个数据库有很多数据,当我启动应用程序时,它分配大约85mb的RAM,这太多了。

我正在寻求帮助来优化这一点。欢迎任何帮助,指出改进,任何明显的问题,甚至是减少问题的来源。

作为来源,请检查Android Studio上LogCat中的“已分配内存:”Allocated memory image

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

注意:请查看此代码并说明我的问题在哪里?!请不要给我负面的意见,请帮助我!

1 个答案:

答案 0 :(得分:0)

您的代码存在一些明显的问题,但也许您应该在消除问题的情况下进行更多调查。

DataBase类使用Singleton Pattern,因为创建DataBase对象非常昂贵。

完成游标后关闭游标。不要打开你的游标。 实际上不需要关闭数据库,您可以使用应用程序Context(而不是您的活动Context)创建实例,并在您的应用程序的生命周期中使用它,但我认为您完成后应该关闭Cursor

还有一些其他优化,例如您只能使用TypeFace类的一个对象,而不是为菜单的每个项目创建一个。

我看到你使用字节数组来存储图像,因为我不知道你是如何使用它们的,我无法确定,但我想你会遇到一些麻烦他们,也许你可以粘贴你的适配器代码。

最后一件事是您可以使用Eclipse MATLeakCanary来检测内存泄漏。