Search code examples
javaandroidandroid-recyclerviewandroid-sqlite

Sqlite query not showing hindi words from precreated database?


My Database Adapter Class

public class DatabaseAdapter {

    // Declare a DatabaseHelper object reference
    DatabaseHelper helper;
    // Declare a SQLiteDatabase object reference.
    SQLiteDatabase db;
    // SQLiteDatabase class has methods to create, delete, execute SQL commands and perform other common database
    // management tasks.
    // Define an ArrayList of Term object.
    ArrayList<Term> termsList = new ArrayList<Term>();
    // What is Term?
    // You'll create a Term class to contain and model the information and make it more easy to implement.
    // Define the constructor for DatabaseAdapter
    public DatabaseAdapter(Context context){
        // Instantiate helper
        helper = new DatabaseHelper(context);
        // Call getWritableDatabase() method on helper. This is going to give you an object of SQLiteDatabase. Store that in db.
        db = helper.getWritableDatabase();
        // Now, this SQLiteDatabase object, db, is going to represent the database you have and you are going to use that object
        // to perform the different queries that you want to do, for example, insert, update or delete from database.
    }

    // Define a method to close the database
    public void close() {
        helper.close();
    }

    public int deleteData(long id) {
        // Define the whereArgs String array
        String whereArgs[] = {""+id};
        // Call delete() method on db
        return db.delete(DatabaseHelper.TABLE_NAME, DatabaseHelper.KEY_ID + "=?", whereArgs);
        // delete() returns the number of rows deleted as an integer.
    }

    public int updateTermFullForm(long id, String meaning) {
        // To update the database, you need to create an object of the class called ContentValues that acts like a map, inside which you can
        // put your key-value pairs.
        // Here, what is expected is the name of the key that you give here is the name of the column in your table
        // and the value you want to put inside the column goes in the second parameter.
        ContentValues contentValues = new ContentValues();
        contentValues.put(DatabaseHelper.KEY_MEANING, meaning);
        // You need to create whereArgs[] array. whereArgs[] is just an array that contains the values that are substituted inside the
        // question mark (?) of whereClause at run-time, when you are executing the query.
        // whereArgs[] is going to contain the values for against you want to compare.
        String whereArgs[] = {""+id};
        // Call update() method on db
        return db.update(DatabaseHelper.TABLE_NAME, contentValues, DatabaseHelper.KEY_ID + "=?", whereArgs);
        // update() returns the number of rows affected as an integer.
        // The plain sql statement for this can be:
        // UPDATE ct SET full_form="New Value" WHERE _id=2

    }

    public long insertTerm(String words, String meaning) {
        // Define a new ContentValues object
        ContentValues contentValues = new ContentValues();
        // Add term and fullForm into that
        contentValues.put(DatabaseHelper.KEY_WORDS, words);
        contentValues.put(DatabaseHelper.KEY_MEANING, meaning);
        // Call insert() method on db object and return
        return db.insert(DatabaseHelper.TABLE_NAME, null, contentValues);
    }

    // Next, define a method that returns an ArrayList of specific Term objects where the term starts with the String in parameter.
    public ArrayList<Term> getSomeTerms(String termStartsWith){
        // Call query() method on db and store the returned cursor.
        Cursor cursor = db.query(DatabaseHelper.TABLE_NAME, new String[]{DatabaseHelper.KEY_ID, DatabaseHelper.KEY_WORDS,
                                     DatabaseHelper.KEY_MEANING}, DatabaseHelper.KEY_WORDS + " like '"
                                 + termStartsWith + "%'",null,null,null,null);
        // Here, % is a wildcard character which indicates 0 or any number of characters. So, there can be any number of characters
        // after “A”, or "B" or "S" etc.
        // The plain sql statement for this can be:
        // SELECT * FROM ct WHERE terms LIKE 'A%';
        // Use a while loop to traverse the database and populate the ArrayList of Term objects
        while (cursor.moveToNext()){
            // Get the database column index or position by passing the column name
            int index1 = cursor.getColumnIndex(DatabaseHelper.KEY_ID);
            // Now, get the value of id for that cell
            long id = cursor.getInt(index1);
            // Do the same thing to get values from other two columns
            int index2 = cursor.getColumnIndex(DatabaseHelper.KEY_WORDS);
            String words = cursor.getString(index2);
            int index3 = cursor.getColumnIndex(DatabaseHelper.KEY_MEANING);
            String meaning = cursor.getString(index3);
            // Create a Term object from database values
            Term term = new Term(id, words, meaning);
            // Add the Term object to termsList
            termsList.add(term);
        }
        // return termList
        return termsList;
    }


    // For managing all the operations related to the database, a helper class has been provided by Android
    // and it is called SQLiteOpenHelper.
    // It takes care of opening the database if it exists, creating it if it does not exists, and upgrading it as necessary.
    // So, inside DatabaseAdapter you'll create a static inner class that extends SQLiteOpenHelper.
    private static class DatabaseHelper extends SQLiteOpenHelper{

        // Define some private static final String variables to store information related to the database
        private static final String DATABASE_NAME ="Test.db";
        // Database name must be unique within an app, not across all the apps.
        private static final String TABLE_NAME = "words";
        // When you do change the structure of the database change the version number from 1 to 2
        private static final int DATABASE_VERSION = 7;
        static final String KEY_ID = "id";
        static final String KEY_WORDS = "words";
        static final String KEY_MEANING = "meaning";
        
        private Context context;

        // Define the constructor
        public DatabaseHelper(Context context){
            super(context, DATABASE_NAME, null, DATABASE_VERSION);
            // Store the context received from constructor into this class's context variable
            this.context = context;
        }

        // Since, you're not creating or upgrading the database since you're using a pre-created database file
        // copied to the right location, you don't need to write any code inside onCreate() or onUpgrade().

        @Override
        public void onCreate(SQLiteDatabase db) {

        }

        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

        }
    }
} 

My PreCreate Database Class

public class PreCreateDB {
    static String destPath;
    static String destPathwithFilename;
    // Lets define copyDB() method
    public static void copyDB(Context context){
        // Defile two String variables containing path upto "database" folder and "CTDB" file respectively
        destPath = "/data/data/" + context.getPackageName() + "/databases";
        destPathwithFilename = destPath+"/Test.db";
        // Create two File objects from those Strings
        File fPath = new File(destPath);
        File fPathWithName = new File(destPathwithFilename);
        // Now, the question is, why we created two separate File objects?
        // It's because in some devices databases folder will be automatically created by Android system.
        // In some other devices it won't be there by default.
        // So, we need to check if it's not present in the device.
        if(!fPath.exists()){
            // If true, you'll create the databases folder
            fPath.mkdirs();
            // And then copy the CTDB Database file from assets folder to databases folder.
            // You'll define a method named rawCopy that takes an InputStream and an OutputStream.
            // This method will copy the file.
            try {
                rawCopy(context.getAssets().open("Test.db"), new FileOutputStream(destPath+"/Test.db"));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    public static void rawCopy(InputStream inputStream, OutputStream outputStream) throws IOException {
        // To copy 1k bytes at a time, create a byte array of size 1024
        byte[] buffer = new byte[1024];
        // Declare an integer variable to store the total number of bytes read from the buffer.
        int length;
        // If you call read() method on inputStream object and pass buffer as parameter, it will read 1024 bytes at a time.
        // It returns -1 if there is no more data because the end of the stream has been reached.
        // Using this information you use a while loop to read from the inputStream and write to the outputStream.
        // This copies the database file CTDB from assets folder to data/data/[package-name]/databases folder.
        while((length = inputStream.read(buffer)) > 0){
            outputStream.write(buffer, 0, length);
        }
        // Close the input and output streams once you're done
        inputStream.close();
        outputStream.close();
    }

    public static void resetDB(Context context) {
        // Call rawCopy() inside try block
        try {
            rawCopy(context.getAssets().open("Test.db"), new FileOutputStream(destPathwithFilename));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

MY Show Term Class

public class ShowTerm extends AppCompatActivity {
    // Declare a DatabaseAdapter object reference
    static DatabaseAdapter databaseAdapter;
    // Declare a RecyclerView object reference
    static RecyclerView rvTerms;
    // Declare an Adapter object reference
    TermsAdapter termsAdapter;
    // Declare a LayoutManager object reference
    RecyclerView.LayoutManager layoutManager;
    // Define an ArrayList of type Term
    static ArrayList<Term> termsList = new ArrayList<>();
    


    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.show_term);
        
        // Get the received String from Intent
        String termStartsWith = getIntent().getStringExtra("termStartsWith");
        // Instantiate DatabaseAdapter class and pass this for the Context
        databaseAdapter = new DatabaseAdapter(this);
        // Call getSomeTerms() on databaseAdapter object and store the returned ArrayList in
        // termsList
        termsList = databaseAdapter.getSomeTerms(termStartsWith);
        // Obtain a handle for the RecyclerView
        rvTerms = findViewById(R.id.rvTerms);
        // You may use this setting to improve performance if you know that changes
        // in content do not change the layout size of the RecyclerView
        rvTerms.setHasFixedSize(true);
        // Instantiate the linear layout manager
        layoutManager = new LinearLayoutManager(this);
        // Set the layout with RecyclerView
        rvTerms.setLayoutManager(layoutManager);
        // Create an instance of TermsAdapter. Pass context, termsList and the
        // RecyclerView to the constructor
        termsAdapter = new TermsAdapter(this, termsList, rvTerms);
        // Finally, attach the adapter with the RecyclerView
        rvTerms.setAdapter(termsAdapter);
    }
    
   }

My Bengali + Hindi Mix Sqlite Database

MainActivity Ui

This Sqlite query giving blank results for Hindi words but English words are showning Properly

My MainActivity Class

public class MainActivity extends AppCompatActivity {
    // Store the text to be shared in a String
    String shareBody = "Download CTD App now and know about all the important Computer Terms and their Full Forms: \n" +
    "https://play.google.com/store/apps/details?id=com.sandipbhattacharya.computertermsdictionary";
    

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        // Create a class containing static methods to copy the database file
        // from assets folder into: data/data/package-name/databases folder, from where the app can access it.
        // Lets name it PreCreateDB.
        // From MainActivity, call the copyDB method of PreCreateDB and pass "this" for Context
        PreCreateDB.copyDB(this);
    }

    public void show(View view) {
        // We have set a text with every button. This text simply contains an alphabet.
        // Get the clicked Button's text and store in a String variable
        String termStartsWith = ((Button) view).getText().toString().trim();
        // Create an Intent to go to another Activity where you can show all the Terms that start with a letter termStartsWith contains
        Intent intent = new Intent(this, ShowTerm.class);
        // Set termStartsWith with the Intent object as Extra
        intent.putExtra("termStartsWith", termStartsWith);
        // Start the Activity with the Intent
        startActivity(intent);
        // Create the ShowTerm class.
    }

    
    public void reset(View view) {
        // You'll use Android AlertDialog to ask the user about his/her choice to continue or discontinue the reset operation.
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setMessage("Resetting will delete all your personal data. Proceed?");
        builder.setCancelable(true);
        builder.setPositiveButton("Yes",
            new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int id) {
                    // Here, you call a method and pass MainActivity.this as context,
                    // to replace the database file from assets folder to databases folder.
                    PreCreateDB.resetDB(MainActivity.this); 
                }
            });
        builder.setNegativeButton("No",
            new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int id) {
                    dialog.cancel();
                }
            });
        AlertDialog alertDialog = builder.create();
        alertDialog.show(); 
    } 

    public void addNew(View view) {
        // You'll use an Intent to go to AddNew Activity
        Intent intent = new Intent(this, AddNew.class);
        startActivity(intent);
    } 

    public void rate(View view) {
        // Create an Intent that opens a URL in Google Play
        Intent intent = new Intent(Intent.ACTION_VIEW);
        intent.setData(Uri.parse("https://play.google.com/store/apps/details?id=" + getPackageName()));
        // As you configure this intent, pass "com.android.vending" into Intent.setPackage() so that users see your app's details
        // in the Google Play Store app instead of a chooser. Make sure your emulator has pre-installed Play Store app.
        intent.setPackage("com.android.vending");
        // Start the Activity
        try {
            startActivity(intent);
        }catch (ActivityNotFoundException e) {
            Toast.makeText(this, "Couldn't launch Play Store", Toast.LENGTH_LONG).show();
        }
    }

    public void shareApp(View view) {
        // Create a send Intent
        Intent sendIntent = new Intent(Intent.ACTION_SEND);
        // Set the Sharing Type
        sendIntent.setType("text/plain");
        // Pass your sharing content using the putExtra() method of the Intent
        sendIntent.putExtra(Intent.EXTRA_SUBJECT, "Share CTD App");
        sendIntent.putExtra(Intent.EXTRA_TEXT, shareBody);
        // Next, instruct Android system to let the user choose their sharing medium
        startActivity(Intent.createChooser(sendIntent, "Share using"));
        // This will pass the sendIntent along with a title to be displayed at the top of the chooser.
        // When the user chooses an application from the list, your share content will be passed to that application,
        // where he/she will be able to edit the content before sending it if they wish to do so.
    }
}

Please Help me because im beginner in android development and it is very important for my dictionary app 🙏


Solution

  • Solved the problem, in Sqlite database your table creation rules are also important when using external database.