I am developing a dictionary app. I have the following code which show 20 most recent history word.
public List<Bean> getHistoryWords() {
SQLiteDatabase db = initializer.getReadableDatabase();
String sql = "SELECT * FROM " + HISTORY_NAME +
" WHERE " + STATUS + " ORDER BY " + STATUS + " DESC LIMIT 20" ;
Cursor cursor = db.rawQuery(sql, null);
List<Bean> wordList = new ArrayList<Bean>();
while(cursor.moveToNext()) {
int id = cursor.getInt(0);
String english = cursor.getString(1);
String bangla = cursor.getString(2);
String status = cursor.getString(3);
wordList.add(new Bean(id, english, bangla, status));
}
cursor.close();
db.close();
return wordList;
}
I would like to provide an option for user to change the number of history item from LIMIT 20 to LIMIT 50 or LIMIT 100 through Preferences.
I follow this tutorial, but I was stuck in "5) Saving/reading data". I tried to put the SharedPreferences under getHistoryWords, but I got error cannot resolve getBaseContext.
public List<Bean> getHistoryWords() {
SharedPreferences SP = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
Where should I put the code?
There is a simplest way for it.
First, create YourAppName , that extends Application
Declare Context as static and init it on Application 's onCreate method,
public YourApp extends Application {
private static Context context;
public void onCreate() {
super.onCreate();
YourApp.context = getApplicationContext();
}
public static Context getAppContext() {
return YourApp.context;
}
}
declare YourApp in Manifest.xml
android:name="com.yourpackagename.app.YourApp" in application tag,
Now, you can get for Context, every where you need like this,
YourApp.getAppContext()
I hope this will help for you.
Related
As the title, I am trying to update a specific data stored in SQLiteDatabase, but it updates every item in it.
What I am trying is making a note taking app. So far it saves what I want to save properly but when I try to edit a note, the problem comes.
It changes all the saved notes when I press the edit button, including the note I wanted to edit.
The note is defined as MemoItem object i.e. MemoItem memoItem = new MemoItem(), and has following variables: String savedTime, memo, and category.
When I tap the note I want to edit it takes saved values successfully but yeah.
And just in case it is needed, here are the things that are declared in my SQLiteOpenHelper class:
public class MemoListDbHelper extends SQLiteOpenHelper {
public static final int DATABASE_VERSION = 1;
public static final String DATABASE_NAME = "MemoListDB.db";
public static class MemoEntry implements BaseColumns {
public static final String TABLE_NAME = "entry";
public static final String COLUMN_CATEGORY = "category";
public static final String COLUMN_SAVED_TIME = "savedTime";
public static final String COLUMN_MEMO = "memo";
}
private static final String SQL_CREATE_ENTRIES = "CREATE TABLE " + MemoEntry.TABLE_NAME + " (" +
MemoEntry._ID + " INTEGER PRIMARY KEY," +
MemoEntry.COLUMN_CATEGORY + " TEXT," +
MemoEntry.COLUMN_SAVED_TIME + " TEXT," +
MemoEntry.COLUMN_MEMO + " TEXT )";
}
I made a updateNote() method inside the Helper Class:
public void updateNote(MemoItem memoItem) {
if (memoItem == null) {
return;
}
SQLiteDatabase db = getReadableDatabase();
ContentValues values = new ContentValues();
values.put(MemoEntry.COLUMN_MEMO, memoItem.memo);
db.update(MemoEntry.TABLE_NAME, values, "_id=" + MemoEntry._ID, null);
}
And the edit button is inside a Fragment called MemoFragment.
The overridden onClick method has another method named updateMemoOnClick() in it, which I made.
When the button is clicked it will make a new MemoItem object that has category, memo, and saved time that user put in and pass the object to updateNote() method above:
private void updateMemoOnClick() {
MemoItem memoItem = new MemoItem();
memoItem.memo = memoEditText.getText().toString();
memoItem.category = selectedBodyPartTextView.getText().toString();
memoItem.startedTime = startTimeTextView.getText().toString();
memoListDbHelper.updateMemo(memoItem);
}
Why is my SQLite update() updating all the items the database has?
Can anyone please help? I have been on this problem for the half of the day already. Thanks in advance!
Here you making the mistake
db.update(MemoEntry.TABLE_NAME, values, "_id=" + MemoEntry._ID, null);
replace MemoEntry._ID with your row id . like memoItem.id
db.update(MemoEntry.TABLE_NAME, values, "_id=" + [row id should be here], null);
You can try different way to update
db.update(MemoEntry.TABLE_NAME, values, "_id=?", new String[]
{String.valueOf(memoItem._ID)});
OR
db.update(MemoEntry.TABLE_NAME, values, "_id='" + memoItem._ID+"'", null);
I'm assuming that you are displaying the memo entries in a recycler view, so in order to do that you need many MemoEntry objects. You do not need the memoItem object.
You can retrieve the list of entries through a method like this:
public ArrayList<MemoEntry> getMemoEntries(SQLiteDatabase db){
ArrayList<MemoEntry> entries = new ArrayList<>();
Cursor c;
c = db.rawQuery("SELECT * FROM " + ENTRY_TABLE, null)
if(c != null && c.moveToFirst()){
while(!c.isAfterLast()){
MemoEntry entry = new MemoEntry();
entry.setId(c.getInt(c.getColumnIndex(Memo_Entry._ID)));
entry.setCategory(c.getString(c.getColumnIndex(Memo_Entry.COLUMN_CATEGORY)));
entry.setMemo(c.getString(c.getColumnIndex(Memo_Entry.COLUMN_MEMO)));
entries.add(entry);
c.moveToNext();
}
c.close();
}
return entries;
When you go to edit an entry you can reference the objects id field.
Then you can use the below query once the user saves.
db.RawQuery("UPDATE " + MemoEntry.TABLE_NAME + " SET " + MemoEntry.COLUMN_MEMO + " = " MemoEntry.memo + " WHERE " + MemoEntry.COLUMN_ID+ " = " + memoEntry._id ,null);
I think the confusion here is that you are putting column names within the MemoEntry object?
It might also be a good idea to update the saved time.
ok I just followed an instruction that I should do this to retrieve sql data from database but it just cuts to there so far I have this inside my databasehelper class.
public void getIconResource(String tblName)
{
SQLiteDatabase db = this.getReadableDatabase();
String getresource = "Select * from " + tblName;
Cursor cursor = db.rawQuery(getresource,null); //null for conditions
if(cursor.moveToFirst())
{
do
{
int resource = cursor.getInt(3);
}
while (cursor.moveToNext());
}
db.close();
}
So somehow this does is it get all the values of my tables 4th column which contains an int... how do I retrieve the value in my MainActivity and save it in an array of integers?
just add everything in a ArrayList and return the arraylist
simply call the method in your main activty
public ArrayList<Integer> getIconResource(String tblName)
{
SQLiteDatabase db = this.getReadableDatabase();
String getresource = "Select * from " + tblName;
Cursor cursor = db.rawQuery(getresource,null); //null for conditions
ArrayList data= new ArrayList<>();
if(cursor.moveToFirst())
{
do
{
int resource = cursor.getInt(3);
data.add(resource);
}
while (cursor.moveToNext());
}
db.close();
}
return data;
}
Well, as you have it, the variable resource is scoped only to the while loop. Even if it wasn't it would constantly get overwritten on each loop iteration.
Instead, you should declare a collection higher up and Add each value to it during your while loop. You could also redefine your function to return the collection if integers.
public List<int> getIconResource(String tblName)
{
SQLiteDatabase db = this.getReadableDatabase();
List<int> myVals = new List<int>();
String getresource = "Select * from " + tblName;
Cursor cursor = db.rawQuery(getresource, null); //null for conditions
if (cursor.moveToFirst())
{
do
{
myVals.Add(cursor.getInt(3));
}
while (cursor.moveToNext());
}
db.close();
return myVals;
}
Also, as a note... string concatenation of a SQL query is a recipe for disaster. Look up SQL Injection and best practices to avoid it before continuing further. It is worth the time to get into good habits early on.
EDIT / ADDENDUM
Unless you also limit your result set returned from your table query, you will be getting every record. The function you have here really has no practical use and would likely cause more problems than any benefits it may have. I would suggest, as an example of a more usable function that returns a specific IconResource based on the IconId:
public int getIconResource(int iconId)
{
SQLiteDatabase db = this.getReadableDatabase();
String getresource = "select IconResource from IconTable where IconId = ?";
PreparedStatement pstmnt = db.prepareStatement(getresource);
pstrmnt.setString(1, iconId);
ResultSet rset = db.executeQuery();
int iconResource;
if (rset.next())
iconResource = rset.getInt("IconResource");
db.close();
return iconResource;
}
Of course, the above is making assumptions of your table structure.
Using the above, in your code elsewhere, you would simply call this function with the IconId and use the output however needed:
int iconResource = getIconResource(5); // returns the IconResource for IconId = 5
The above prevents any possible SQL Injection attacks by using a parameterized query and avoiding the use of dynamic concatenated strings sent to your SQL server.
You may try out the following code:
public List<Integer> getIconResource(String tblName)
{
List<Integer> list = new ArrayList<Integer>();
list.clear();
SQLiteDatabase db = this.getReadableDatabase();
String getresource = "Select * from " + tblName;
Cursor cursor = db.rawQuery(getresource,null); //null for conditions
if(cursor.moveToFirst())
{
do
{
int resource = cursor.getInt(3);
list.add(resource);
}
while (cursor.moveToNext());
}
db.close();
return list;
}
Then call this method in MainActivity and store the List in another Integer type list.
databasehelper dbhelper;
List<Integer> newList = dbhelper.getIconResource("Your tablename");
fot(int i = 0 ; i< newList.size() ; i++){
int yourValue = newList(i);
}
I want to display the String value of one of my data in my database inside a toast.
Here's what I've tried so far.
this is my main activity:
Button btnShow = (Button)findViewById(R.id.btnShow);
btnShow.setOnClickListener(new OnClickListener(){
#Override
public void onClick(View v) {
DBUser dbUser = new DBUser(EditUserActivity.this);
dbUser.newNumber();
//get the new value of the number from the DB
Cursor c = dbUser.newNumber();
String numberRetrieved = c.getString(c.getColumnIndex("number")).toString();
Toast.makeText(EditUserActivity.this,"Current Modem No. is:" + numberRetrieved, Toast.LENGTH_LONG).show();
c.close();
dbUser.close();
}
});
and this is my method in my Database class:
public Cursor newNumber() {
String query = "SELECT * FROM " + DATABASE_TABLE + " WHERE _id=1";
System.out.println(query);
Cursor cur = db.rawQuery(query, null);
cur.moveToFirst();
return cur;
}
Just so you know that my database exist and it definitely has some values in it.
But whenever I run this code my application always force closes!
Hope anyone can help me in it. thanks!
public static final String COL_2 = "DRIVERNO";
Please be sure your columns like this then put COL_2 value DRIVERNO in c.getColumnIndex("DRIVERNO")
Like this
String numberRetrieved = c.getString(c.getColumnIndex("DRIVERNO")).toString();
I hope your app will not crash again I will solve my problem from this solution.Thanks
In my application I have a content provider which uses a database for the content provided. When the database is created the first time it needs to be filled from the raw content of a Json file. My idea was that i trigger this filling of the database at onCreate of my SQLiteOpenHelper subclass. This works fine yet I am not sure how to handle the the communication between application and content provider when the app is running the first time. Basically i would like to show some sort of a splash screen while the database is filled. Yet how does the application get informed that
the content provider is busy filling the database when running the first time
the content provider is ready to go
Surely I could fill the database from the application by calling the content provider with each dataset yet I would prefer doing it within the sphere of the content provider so that the application does not have to handle the reading of the json file etc. Besides design preferences it would also enable the content provider to fill the database more efficiently because it would have the whole dataset at once. I have a feeling this is not possible yet I hope I miss some simple point.
Any suggestions how to achieve this would be highly appreciated.
Thanks
martin
When using a content Provider i would presume that your using a DBHelper class to manage the creation of the database. Below is the code from the android notes example project.
This shows how the DBHelper constructor is intelligent enough to determine if the database has been created before. In the createDatabase method i would subsequently call a method to pre-populate the database, from as you say a json file.
The problem is that this doesn't really allow you to communicate to the Activity that your database hasn't been initialised.
One thought could be that you use SharedPreferences to store the fact you've populated the database. You could then check the sharedPreference in the activity on startup, Call the content provider to populate the database and then store in the shared preference that you've done this task already.
Just be aware that i'm not sure if the sharedPreferences maintain the same state as the database if you for example erase the data from the android settings menu. You'd need to check that.
http://code.google.com/p/android-notes/source/browse/trunk/src/com/bitsetters/android/notes/DBHelper.java?r=10
public class DBHelper {
private static final String DATABASE_NAME = "notes";
private static final String TABLE_DBVERSION = "dbversion";
private static final String TABLE_NOTES = "notes";
private static final int DATABASE_VERSION = 1;
private static String TAG = "DBHelper";
Context myCtx;
private static final String DBVERSION_CREATE =
"create table " + TABLE_DBVERSION + " ("
+ "version integer not null);";
private static final String NOTES_CREATE =
"create table " + TABLE_NOTES + " ("
+ "id integer primary key autoincrement, "
+ "note text, "
+ "lastedit text);";
private static final String NOTES_DROP =
"drop table " + TABLE_NOTES + ";";
private SQLiteDatabase db;
/**
*
* #param ctx
*/
public DBHelper(Context ctx) {
myCtx = ctx;
try {
db = myCtx.openOrCreateDatabase(DATABASE_NAME, 0,null);
// Check for the existence of the DBVERSION table
// If it doesn't exist than create the overall data,
// otherwise double check the version
Cursor c =
db.query("sqlite_master", new String[] { "name" },
"type='table' and name='"+TABLE_DBVERSION+"'", null, null, null, null);
int numRows = c.getCount();
if (numRows < 1) {
CreateDatabase(db);
} else {
int version=0;
Cursor vc = db.query(true, TABLE_DBVERSION, new String[] {"version"},
null, null, null, null, null,null);
if(vc.getCount() > 0) {
vc.moveToFirst();
version=vc.getInt(0);
}
vc.close();
if (version!=DATABASE_VERSION) {
Log.e(TAG,"database version mismatch");
}
}
c.close();
} catch (SQLException e) {
Log.d(TAG,"SQLite exception: " + e.getLocalizedMessage());
} finally {
db.close();
}
}
private void CreateDatabase(SQLiteDatabase db)
{
try {
db.execSQL(DBVERSION_CREATE);
ContentValues args = new ContentValues();
args.put("version", DATABASE_VERSION);
db.insert(TABLE_DBVERSION, null, args);
db.execSQL(NOTES_CREATE);
// Populate with data
populateDataBaseFromFile();// There are probably better ways to do this.
setSharedPreferenceYouPopulatedDB();
} catch (SQLException e) {
Log.d(TAG,"SQLite exception: " + e.getLocalizedMessage());
}
}
Personally I wouldn't bother with the splash screen, unless you really needed to.
Another thought might be to:
Write in the db helper a method to determin if your tables exist. Return false if not.
In startup activity call ContentProvider with a request that calls the DBHelper test method.
If false then display splash screen and then call Content Provider to populate DB.
If true, then carry on as normal.
i'm working on a android app that will display Strings to the user, and the user then has the option to add one to a favorite list. I have searched and searched and cannot find the proper way of doing this. I did get one open source project, everything worked until the user removed a favorite. The database would clear the row of data, but when a new row is added, it would behave as if the deleted row still had data, leaving blanks in the favorite list.
this is my insert method
public long insertString(String newString)
{
ContentValues newStringValue = new ContentValues();
newStringValue.put(KEY_STRING, newString);
return db.insert(DATABASE_TABLE, null, newStringValue);
}
the long returned will always increment even if i use the remove method:
public boolean removeString(long _rowIndex)
{
return db.delete(DATABASE_TABLE, KEY_ID + "=" + _rowIndex, null) > 0;
}
if i try to remove the third index, and the user removed a question at the third index, the method returns false, is there a way to completely remove all rows with no data?
You should use a CursorAdapter or ResourceCursorAdapter and when you modify the data call cursor.requery() to refresh everything.
Maybe just encode String List as something like JSON, then save as long string (blob / clob)? I would use Jackson JSON processor, but there are many alternatives to choose from (Guice, or XStream if you prefer XML). I mean, assuming you don't really need relational aspects of data (no need to find users with specific list entry by querying) but just need to persist lists.
public static class OrderManager
{
private MyDBOpenHelper _db_Orders;
private static final String GET_Orders = “SELECT * FROM “+Order_TABLE_NAME ;
public OrderManager(Context context)
{
_db_Orders = new MyDBOpenHelper(context);
}
public boolean insert(String orderName, String orderStatus)
{
try
{
SQLiteDatabase sqlite = _db_Orders.getWritableDatabase();
/*
sqlite.execSQL(“INSERT INTO “+ Order_TABLE_NAME +
” (” + KEY_NAME +”, “+ KEY_STATUS + “)” +
” VALUES (‘” + orderName + “‘, ‘” + orderStatus + “‘)”);
*/
ContentValues initialValues = new ContentValues();
initialValues.put(KEY_NAME, orderName);
initialValues.put(KEY_STATUS, orderStatus);
sqlite.insert(Order_TABLE_NAME, null, initialValues);
}
catch(SQLException sqlerror)
{
Log.v(“Insert ERROR”, sqlerror.getMessage());
return false;
}
return true;
}
public ArrayList<Order> getOrders()
{
ArrayList<Order> orders = new ArrayList<Order>();
SQLiteDatabase sqliteDB = _db_Orders.getReadableDatabase();
Cursor crsr = sqliteDB.rawQuery(GET_Orders, null);
Log.v(“Select Query result”, String.valueOf(crsr.getCount()) );
crsr.moveToFirst();
for(int i=0; i < crsr.getCount(); i++)
{
orders.add(new Order(crsr.getString(0), crsr.getString(1)));
//Log.v(“DATA”, crsr.getString(0) + ” ” +crsr.getString(1));
crsr.moveToNext();
}
return orders;
}
}