i want to run a search on a activity where a custom list is showing me the records of medicine. I haven't worked on SearchView.
My Medicine Database Code :
package com.example.sarhanaashir.wecare.Database_MedInfo;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
import java.util.ArrayList;
public class DatabaseHelperMed extends SQLiteOpenHelper
{
private static final String Database_Name = "WeCareDatabaseMed";
private static final int Database_Ver = 1;
public DatabaseHelperMed(Context context, String name, SQLiteDatabase.CursorFactory factory, int version)
{
super(context,Database_Name,null,Database_Ver);
}
#Override
public void onCreate(SQLiteDatabase sqLiteDatabase)
{
String query = "CREATE TABLE tbl_med(id INTEGER PRIMARY KEY AUTOINCREMENT,MedName TEXT,MedSymptom TEXT)";
sqLiteDatabase.execSQL(query);
}
#Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1)
{
sqLiteDatabase.execSQL("DROP TABLE IF EXISTS tbl_med");
this.onCreate(sqLiteDatabase);
}
public boolean addNewMedicine(MedicineRecord med_rec)
{
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put("MedName", med_rec.getMed_name() );
values.put("MedSymptom", med_rec.getMed_sym() );
db.insert("tbl_med", null, values);
db.close();
return true;
}
public ArrayList<MedicineRecord> getAllMed()
{
SQLiteDatabase db = this.getReadableDatabase();
ArrayList<MedicineRecord> medi = new ArrayList<>();
Cursor cursor = db.rawQuery("select * from tbl_med", null);
if (cursor.moveToFirst())
{
while (!cursor.isAfterLast())
{
String id = cursor.getString(0);
String name = cursor.getString(1);
String sympt = cursor.getString(2);
medi.add(new MedicineRecord(name,sympt));
cursor.moveToNext();
}
}
return medi;
}
public Cursor searchTasks(SQLiteDatabase db, String searchTxt)
{
Cursor cursor;
String q = "select * tbl_med from where MedSymptom Like '"+searchTxt+"%'";
cursor = db.rawQuery(q,null);
return cursor;
}
}
My Activity Where SearchView is :
package com.example.sarhanaashir.wecare.Database_MedInfo;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ListView;
import android.app.SearchManager;
import android.widget.SearchView;
import android.widget.SearchView.OnQueryTextListener;
import com.example.sarhanaashir.wecare.R;
import java.util.ArrayList;
public class Med_info extends AppCompatActivity {
private ArrayList<MedicineRecord> med_record;
private MedicineListAdapter adapter;
private ListView listView;
DatabaseHelperMed db;
SearchView searchView1;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_med_info);
inti();
searchView1 = (SearchView) findViewById(R.id.SVscrhMed);
searchView1.setOnQueryTextListener(new OnQueryTextListener()
{
#Override
public boolean onQueryTextSubmit(String qry)
{
return false;
}
#Override
public boolean onQueryTextChange(String newText)
{
return true;
}
});
}
private void inti()
{
db = new DatabaseHelperMed(Med_info.this,"WeCareDatabaseMed.db",null,1);
med_record = new ArrayList<>();
listView = (ListView) findViewById(R.id.Med_list);
adapter = new MedicineListAdapter(this, R.layout.med_rec_style, med_record);
listView.setAdapter(adapter);
fillmed();
}
private void fillmed()
{
med_record.clear();
med_record.addAll(db.getAllMed()); // Getting Medicine from database.
adapter.notifyDataSetChanged();
}
}
My Medicine Records are perfectly showing in my Custom List, the only thing i want is to put a searchView so that user can search the medicine from the list.
Try this code:
searchView1.setOnQueryTextListener(new OnQueryTextListener()
{
#Override
public boolean onQueryTextSubmit(String qry)
{
return false;
}
#Override
public boolean onQueryTextChange(String newText)
{
adapter.getFilter().filter(newText);
return true;
}
});
Try this code:
// DatabaseHelperMed //
final ArrayList<MedicineRecord> medicalRecords = new ArrayList<MedicineRecord>();
public ArrayList<MedicineRecord> getMedicine(String name) {
try {
medicalRecords.clear();
String selectQuery = "SELECT * FROM tbl_med "+" WHERE MedSymptom LIKE '%" + name + "%'";
SQLiteDatabase db = this.getWritableDatabase();
Cursor cursor = db.rawQuery(selectQuery, null);
if (cursor.moveToFirst()) {
do {
MedicineRecord medRec = new MedicineRecord();
medRec.setMed_name(cursor.getString(1));
medRec.setMed_sym(cursor.getString(2));
medicalRecords.add(medRec);
} while (cursor.moveToNext());
}
cursor.close();
db.close();
return medicalRecords;
} catch (Exception e) {
// TODO: handle exception
Log.e("get_all_contacts", "" + e);
}
return medicalRecords;
}
// SearchView
searchView1.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
#Override
public boolean onQueryTextSubmit(String query) {
return false;
}
#Override
public boolean onQueryTextChange(String newText) {
DatabaseHelperMed db ;
db = new DatabaseHelperMed(getApplicationContext());
ArrayList<MedicineRecord> medRecords = db.getMedicine(newText);
for (int i = 0; i < medRecords.size(); i++) {
String name = medRecords.get(i).getMed_name();
String symp = medRecords.get(i).getMed_sym();
}
return false;
}
});
Related
My Database program works so far with submit and show data function. But deletion and modify database function is not working. I have attached the code for EventsDB.java and EventDetail.java and their resource layout file. Basically there is no problem with submit and show data part. i haven done the modify part and deletion part just din work.Please help.
package com.cinrafood.teopeishen.databasedemo;
import android.content.Intent;
import android.database.SQLException;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
EditText etEvent,etEventDetail,etDate;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_activity);
etEvent=(EditText)findViewById(R.id.etEvent);
etEventDetail= (EditText)findViewById(R.id.etEventDetail);
etDate=(EditText)findViewById(R.id.etDate);
}
public void btnSubmit (View view)
{
try{
String event = etEvent.getText().toString();
String eventDetail = etEventDetail.getText().toString();
String date= etDate.getText().toString();
EventsDB db = new EventsDB(this);
db.open();
db.createEntry(event,eventDetail,date);
db.close();
Toast.makeText(MainActivity.this,"Successfully saved!!",Toast.LENGTH_LONG).show();
etDate.setText("");
etEventDetail.setText("");
etEvent.setText("");
}catch (SQLException e)
{
Toast.makeText(this, e.getMessage(), Toast.LENGTH_SHORT).show();
}catch (Exception e)
{
Toast.makeText(this,"Please fill up all field",Toast.LENGTH_LONG).show();
}
}
public void btnShowEvents (View view)
{
startActivity(new Intent(this,EventData.class));
}
}
package com.cinrafood.teopeishen.databasedemo;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import java.util.ArrayList;
public class EventsDB
{
public static final String KEY_ROWID ="_id";
public static final String KEY_EVENT="event_name";
public static final String KEY_EVENT_DESCRIPTIOM="event_description";
public static final String KEY_DATE="event_date";
private final String DATABASE_NAME="EventsDB";
private final String DATABASE_TABLE="EventsTable";
private final int DATABASE_VERSION=1;
private DBHelper ourHelper;
private final Context ourContext;
private SQLiteDatabase ourDatabase;
private ArrayList<Event> events;
public EventsDB(Context context)
{
ourContext= context;
}
private class DBHelper extends SQLiteOpenHelper
{
public DBHelper (Context context)
{
super(context,DATABASE_NAME,null,DATABASE_VERSION);
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS "+DATABASE_TABLE);
onCreate(db);
}
#Override
public void onCreate(SQLiteDatabase db) {
/*
CREATE TABLE EventsTable (_id INTEGER PRIMARY KEY AUTOINCREMENT,
event_name TEXT NOT NULL,event_description TEXT NOT NULL,
event_date DATE NOT NULL);
*/
String sqlCode="CREATE TABLE "+DATABASE_TABLE+" ("+
KEY_ROWID+" INTEGER PRIMARY KEY AUTOINCREMENT, "+
KEY_EVENT+" TEXT NOT NULL, "+
KEY_EVENT_DESCRIPTIOM+" TEXT NOT NULL, "+
KEY_DATE+" TEXT NOT NULL);";
db.execSQL(sqlCode);
}
}
public EventsDB open() throws SQLException
{
ourHelper = new DBHelper(ourContext);
ourDatabase=ourHelper.getWritableDatabase();
events= new ArrayList<Event>();
return this;
}
public void close()
{
ourHelper.close();
}
public long createEntry(String event_name, String event_description, String event_date)
{
ContentValues cv = new ContentValues();
cv.put(KEY_EVENT,event_name);
cv.put(KEY_EVENT_DESCRIPTIOM,event_description);
cv.put(KEY_DATE,event_date);
return ourDatabase.insert(DATABASE_TABLE,null,cv);
}
public ArrayList<Event> getData()
{
String [] columns = new String[]{KEY_ROWID,KEY_EVENT,KEY_EVENT_DESCRIPTIOM,KEY_DATE};
Cursor c = ourDatabase.query(DATABASE_TABLE,columns,null,null,null,null,null);
int iRowID = c.getColumnIndex(KEY_ROWID);
int iEvent = c.getColumnIndex(KEY_EVENT);
int iEventDescription = c.getColumnIndex(KEY_EVENT_DESCRIPTIOM);
int iDate = c.getColumnIndex(KEY_DATE);
for(c.moveToFirst();!c.isAfterLast();c.moveToNext())
{
Event event = new Event(c.getInt(iRowID),c.getString(iEvent),c.getString(iEventDescription),c.getString(iDate));
events.add(event);
}
return events;
}
public long deleteEntry (String rowID){
return ourDatabase.delete(DATABASE_TABLE,KEY_ROWID+"=?",new String[]{rowID});
}
public long updateEntry(String rowID, String event_name, String event_description, String event_date)
{
ContentValues cv = new ContentValues();
cv.put(KEY_EVENT,event_name);
cv.put(KEY_EVENT_DESCRIPTIOM,event_description);
cv.put(KEY_DATE,event_date);
return ourDatabase.update(DATABASE_TABLE,cv,KEY_ROWID+"=?",new String[]{rowID});
}
}
package com.cinrafood.teopeishen.databasedemo;
import android.content.Intent;
import android.database.SQLException;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
public class EventData extends AppCompatActivity {
ListView lvEvents;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_event_data);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
try{
EventsDB db = new EventsDB(this);
db.open();
lvEvents= (ListView)findViewById(R.id.lvEvents);
lvEvents.setAdapter(new CustomAdapter(db.getData(),getApplicationContext()));
db.close();
}catch (SQLException e)
{
Toast.makeText(this, e.getMessage(), Toast.LENGTH_SHORT).show();
}catch(Exception e){
Toast.makeText(this, e.getMessage(),Toast.LENGTH_LONG).show();
}
AdapterView.OnItemLongClickListener click = new AdapterView.OnItemLongClickListener() {
#Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
Intent intent = new Intent(EventData.this,EventDetail.class);
intent.putExtra("Location",position);
startActivity(intent);
return true;
}
};
lvEvents.setOnItemLongClickListener(click);
}
}
package com.cinrafood.teopeishen.databasedemo;
import android.database.SQLException;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import java.util.ArrayList;
public class EventDetail extends AppCompatActivity {
EditText etTitlePage,etEventDetailPage,etDatePage;
Button btnDeleteEvent;
int location;
ArrayList<Event> events;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_event_detail);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
etTitlePage=(EditText) findViewById(R.id.etTitlePage);
etEventDetailPage=(EditText) findViewById(R.id.etEventDetailPage);
etDatePage=(EditText) findViewById(R.id.etDatePage);
btnDeleteEvent=(Button)findViewById(R.id.btnDeleteEvent);
try{
EventsDB db = new EventsDB(this);
db.open();
events=db.getData();
location = getIntent().getIntExtra("Location",0);
etTitlePage.setText(events.get(location).getEvent_name());
etEventDetailPage.setText(events.get(location).getEvent_description());
etDatePage.setText(events.get(location).getEvent_date());
db.close();
}catch (SQLException e)
{
Toast.makeText(this, e.getMessage(), Toast.LENGTH_SHORT).show();
}catch(Exception e){
Toast.makeText(this, e.getMessage(),Toast.LENGTH_LONG).show();
}
btnDeleteEvent.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
try{
EventsDB db = new EventsDB(getApplicationContext());
db.open();
db.deleteEntry((location+1)+"");
db.close();
Toast.makeText(getApplicationContext(),"Successfully deleted!!",Toast.LENGTH_LONG).show();
}catch (SQLException e)
{
Toast.makeText(getApplicationContext(), e.getMessage(), Toast.LENGTH_SHORT).show();
}catch(Exception e){
Toast.makeText(getApplicationContext(), e.getMessage(),Toast.LENGTH_LONG).show();
}
}
});
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}
}
public Integer deleteContacts (Integer id) {
SQLiteDatabase db = this.getWritableDatabase();
return db.delete("contacts",
"id = ? ",
new String[] { Integer.toString(id) });
}
Actually you have passed position of the item in ListView to delete that item from database which is not correct. You have to pass the rowId of database primary key to complete the delete operation.
AdapterView.OnItemLongClickListener click = new AdapterView.OnItemLongClickListener() {
#Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
//Retrieve Event from adapter
Event event = lvEvents.getAdapter().getItem(position);
Intent intent = new Intent(EventData.this,EventDetail.class);
intent.putExtra("Location", event.getRowId()); // get rowId from event.
startActivity(intent);
return true;
}
};
And execute delete operation using that rowId
db.deleteEntry(location + "");
Here is my Code
When I retrieved data from Cursor manually it was fine result,
but when I create SimpleCursorAdapter and put a cursor into it, I gives me FATAL EXCEPTION
MainActivity
package com.example.dummy;
import android.app.Activity;
import android.database.Cursor;
import android.os.Bundle;
import android.support.v4.widget.SimpleCursorAdapter;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.ListView;
public class MainActivity extends Activity {
private static final String T = "Main";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Student s = new Student(this);
s.insert("Jeevan");
s.insert("Wahab");
s.insert("Majid");
Cursor c = s.getAllStudents();
ListView l = (ListView) findViewById(R.id.listView);
String[] from = {DbTable.NAME};
int[] to = {android.R.id.text1};
SimpleCursorAdapter adapter = new SimpleCursorAdapter(this,
android.R.layout.simple_list_item_1, c, from, to, 0);
l.setAdapter(adapter);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
Student Class
package com.example.dummy;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.util.Log;
public class Student {
private static final String T = "Student";
private DbTable dbHelper;
private SQLiteDatabase db;
public Student(Context context) {
dbHelper = new DbTable(context);
db = dbHelper.getWritableDatabase();
}
public long insert(String name) {
ContentValues cv = new ContentValues();
cv.put(DbTable.NAME, name);
long insert = 0;
try {
insert = db.insert(DbTable.TABLE, null, cv);
} catch (SQLiteException e) {
Log.d(T, "insert " + e.getLocalizedMessage());
}
return insert;
}
public Cursor getAllStudents(){
String[] columns = {DbTable.ID, DbTable.NAME};
Cursor c = db.query(DbTable.TABLE,
columns,
null, null, null, null, null);
if (c.moveToFirst() ) {
return c;
}
return c;
}
}
DbTable Class
where table is created
package com.example.dummy;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
public class DbTable extends SQLiteOpenHelper {
public static final String TABLE = "STUDENT";
public static final String ID = "ID";
public static final String NAME = "NAME";
private static final String T = "DATABASE TABLE";
private final String CREATE_TABLE = "CREATE TABLE "+TABLE
+ " ( '" + ID + "' INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "
+ "'"+NAME + "' VARCHAR NOT NULL );";
public DbTable(Context context) {
super(context, "MYDB", null, 1);
}
#Override
public void onCreate(SQLiteDatabase db) {
try{
db.execSQL(CREATE_TABLE);
Log.i(T, "database created");
}catch(SQLiteException e){
Log.d(T, "error onCreate "+e.getLocalizedMessage());
}
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
try{
db.execSQL("DROP TABLE IF NOT EXISTS "+TABLE);
onCreate(db);
Log.i(T, "onUpgrade ");
}catch(SQLiteException e){
Log.d(T, "onUpgrade "+e.getLocalizedMessage());
}
}
}
my database helper class is
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
public class DataHandlerDairy {
public static final String DATE = "date";
public static final String DAIRY = "dairy";
private static final String DATA_BASE_NAME = "mydairy";
private static final String TABLE_NAME = "table_dairy";
private static final int DATABASE_VERSION = 1;
private static final String TABLE_CREATE="create table table_dairy (date text primary key," + "dairy text not null);";
DataBaseHelper1 dbhelper1;
Context ct;
SQLiteDatabase db;
public DataHandlerDairy(Context ct)
{
this.ct=ct;
dbhelper1 = new DataBaseHelper1(ct);
}
private static class DataBaseHelper1 extends SQLiteOpenHelper
{
public DataBaseHelper1(Context ct)
{
super(ct,DATA_BASE_NAME,null, DATABASE_VERSION);
}
#Override
public void onCreate(SQLiteDatabase db) {
// TODO Auto-generated method stub
try
{
db.execSQL(TABLE_CREATE);
}
catch(SQLException e)
{
e.printStackTrace();
}
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS table_dairy ");
onCreate(db);
}
}
public DataHandlerDairy open()
{
db = dbhelper1.getWritableDatabase();
return this;
}
public void close()
{
dbhelper1.close();
}
public long insertData(String date,String dairy)
{
ContentValues content = new ContentValues();
content.put(DATE, date);
content.put(DAIRY, dairy);
return db.insertOrThrow(TABLE_NAME, null, content);
}
public Cursor returnData(String date1) throws SQLException
{
Cursor c = db.query(true, TABLE_NAME, new String[] { DATE, DAIRY}, DATE + "=" + date1, null, null, null, null, null);
if(c!=null)
{
c.moveToFirst();
}
return c;
}
}
when i try to retrive the data from the database I am getting an error.
I have used the database helper class in the following code.
import android.os.Bundle;
import android.app.Activity;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Typeface;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.TextView;
public class Read_Dairy extends Activity {
String date1;
TextView tv1,tv2;
ImageButton imgb1;
Button bt1;
DataHandlerDairy handler3;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_read__dairy);
tv1=(TextView) findViewById(R.id.readme);
imgb1=(ImageButton) findViewById(R.id.tick);
bt1=(Button) findViewById(R.id.ready);
tv2=(TextView) findViewById(R.id.love);
Bundle bundle = getIntent().getExtras();
date1 = bundle.getString("kanna");
bt1.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
String getdata=" ";
tv2.setText(date1);
String abcd=tv2.getText().toString();
handler3 = new DataHandlerDairy(getBaseContext());
handler3.open();
Cursor c = handler3.returnData(abcd);
if(c.moveToFirst())
{
do
{
getdata=c.getString(1);
}while(c.moveToNext());
}
handler3.close();
if(getdata==null)
{
tv1.setText("no data exists for this date");
}
else
{
tv1.setText(getdata);
}
}
});
imgb1.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
Intent ks = new Intent(Read_Dairy.this,PickYourDate.class);
startActivity(ks);
}
});
Typeface font = Typeface.createFromAsset(getAssets(), "Strato-linked.ttf");
tv1.setTypeface(font);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.activity_read__dairy, menu);
return true;
}
}
I am getting an error while using this and my StackTrace is
FATAL EXCEPTION: main
Process: simple.smile.my_dairy, PID: 4423
android.database.CursorIndexOutOfBoundsException: Index 0 requested, with a size of 0
at android.database.AbstractCursor.checkPosition(AbstractCursor.java:426)
at android.database.AbstractWindowedCursor.checkPosition(AbstractWindowedCursor.java:136)
at android.database.AbstractWindowedCursor.getString(AbstractWindowedCursor.java:50)
at simple.smile.my_dairy.Read_Dairy$1.onClick(Read_Dairy.java:71)
at android.view.View.performClick(View.java:4832)
at android.view.View$PerformClick.run(View.java:19839)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:211)
at android.app.ActivityThread.main(ActivityThread.java:5315)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:941)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:736)
Please tell me where the error is and how to rectify it.
getdata=c.getString(1) is not a good way. Instead use getdata=c.getString(c.getColumnIndex(DataHandlerDairy.DAIRY))
I am creating an android application that consists of a list view populated by the data from the database.
Here I need to delete the data from the database as well as the list view and refresh the list view.
I used both notifyOnDataSetChanged() and notifyOnDataSetInvalidated() but
it wont work for me please help me with this
package com.developer.milanandroid;
import android.app.ActionBar;
import android.app.Activity;
import android.database.Cursor;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.util.TypedValue;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.LinearLayout;
import android.widget.SimpleCursorAdapter;
import android.widget.TextView;
import android.widget.Toast;
import com.gc.materialdesign.widgets.Dialog;
import com.milan.emptylayout.EmptyLayout;
import com.milan.lib.progressgenarator.lib.ProgressGenerator;
import com.milan.lib.progressgenarator.lib.ProgressGenerator.OnCompleteListener;
import com.milan.swipemenulistview.SwipeMenu;
import com.milan.swipemenulistview.SwipeMenuCreator;
import com.milan.swipemenulistview.SwipeMenuItem;
import com.milan.swipemenulistview.SwipeMenuListView;
import com.milan.swipemenulistview.SwipeMenuListView.OnMenuItemClickListener;
import com.processbutton.lib.milan.ActionProcessButton;
public class DatabaseListView extends Activity implements OnCompleteListener {
MediaPlayer media_player;
ActionProcessButton fetch_database;
SwipeMenuListView database_results;
LoginDataBaseAdapter logindatabase_adapter;
SimpleCursorAdapter cursoradapter;
Cursor cursor;
TextView username_txt,password_txt;
String user_name_string,password_string;
String text;
Dialog dialog;
private EmptyLayout empty_layout;
View.OnClickListener emptyClickListener;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.databaselistview);
View.OnClickListener mErrorClickListener = new OnClickListener() {
#Override
public void onClick(View v) {
fetch_database.setText("Checking...");
empty_layout.showLoading();
ProgressGenerator pg = new ProgressGenerator(DatabaseListView.this);
pg.start(fetch_database);
}
};
emptyClickListener = new OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(DatabaseListView.this, "Try again button clicked", Toast.LENGTH_LONG).show();
}
};
ActionBar actionbar = getActionBar();
actionbar.hide();
View v;
LinearLayout linear = (LinearLayout)findViewById(R.id.linearLayout1);
username_txt = (TextView)linear.getChildAt(0);
password_txt = (TextView)linear.getChildAt(0);
user_name_string = username_txt.getText().toString();
password_string = password_txt.getText().toString();
fetch_database = (ActionProcessButton)findViewById(R.id.Button_Fetch_from_Database);
database_results = (SwipeMenuListView)findViewById(R.id.listview_database);
final ProgressGenerator progressGenerator = new ProgressGenerator(DatabaseListView.this);
logindatabase_adapter = new LoginDataBaseAdapter(DatabaseListView.this);
empty_layout = new EmptyLayout(DatabaseListView.this, database_results);
empty_layout.setErrorButtonClickListener(mErrorClickListener);
fetch_database.setMode(ActionProcessButton.Mode.PROGRESS);
fetch_database.setOnClickListener(new View.OnClickListener() {
#SuppressWarnings("deprecation")
#Override
public void onClick(View v) {
progressGenerator.start(fetch_database);
fetch_database.setText("Checking...");
fetch_database.setEnabled(false);
empty_layout.showLoading();
media_player = MediaPlayer.create(DatabaseListView.this, R.raw.retrievingfromdatabase);
media_player.start();
String[] from = {LoginDataBaseAdapter.USER_NAME,LoginDataBaseAdapter.USER_PASSWORD};
int[] to = {R.id.txt_username,R.id.txt_pasword};
cursor = logindatabase_adapter.feching_Data();
cursoradapter = new SimpleCursorAdapter(DatabaseListView.this, R.layout.listcell, cursor, from, to);
cursoradapter.notifyDataSetChanged();
//registerForContextMenu(database_results);
}
});
SwipeMenuCreator swipe_list_view = new SwipeMenuCreator() {
#Override
public void create(SwipeMenu menu) {
SwipeMenuItem open_swipemenu = new SwipeMenuItem(DatabaseListView.this);
open_swipemenu.setBackground(new ColorDrawable(Color.rgb(0x9B,0x33,0xF0)));
open_swipemenu.setWidth(dp2px(90));
open_swipemenu.setIcon(R.drawable.databasedelete);
menu.addMenuItem(open_swipemenu);
}
};
database_results.setMenuCreator(swipe_list_view);
database_results.setOnMenuItemClickListener(new OnMenuItemClickListener() {
#Override
public boolean onMenuItemClick(final int position, SwipeMenu menu, int index) {
switch(index) {
case 0:
dialog = new Dialog(DatabaseListView.this, "Delete Record", "Do you want to delete Record from database");
dialog.setCancelable(false);
dialog.setOnAcceptButtonClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
cursor = (Cursor) database_results.getItemAtPosition(position);
final int item_id = cursor.getInt(cursor.getColumnIndex(LoginDataBaseAdapter.ID));
cursor.getString(cursor.getColumnIndex(LoginDataBaseAdapter.USER_NAME));
cursor.getString(cursor.getColumnIndex(LoginDataBaseAdapter.USER_PASSWORD));
logindatabase_adapter.deleteEntry(item_id);
//database_results.removeViewAt(position);
//cursoradapter.notifyDataSetChanged();
database_results.invalidateViews();
}
});
dialog.show();
}
return false;
}
});
}
protected int dp2px(int dp) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp,
getResources().getDisplayMetrics());
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.database_list_view, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
public void onComplete() {
if(cursor!=null && cursor.getCount()>0){
database_results.setAdapter(cursoradapter);
fetch_database.setEnabled(false);
fetch_database.setText("SUCCESS");
}
else{
/*fetch_database.setEnabled(false);
fetch_database.setText("OOPS");
fetch_database.setBackgroundColor(Color.parseColor("#ffb74d"));
final Dialog dialog_database = new Dialog(DatabaseListView.this, "Database Records", "No Records was found in the database");
dialog_database.setOnAcceptButtonClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
dialog_database.cancel();
}
});
dialog_database.show();*/
fetch_database.setText("OOPS");
fetch_database.setBackgroundColor(Color.parseColor("#ffb74d"));
empty_layout.showError();
}
}
}
This is my LoginDatabase adpater:
package com.developer.milanandroid;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.view.View;
public class LoginDataBaseAdapter
{
//Database name
static final String DATABASE_NAME = "MilanloginRegistration.db";
static final int DATABASE_VERSION = 1;
public static final int NAME_COLUMN = 1;
// TODO: Create public field for each column in your table.
// SQL Statement to create a new database.
public static final String TABLE_NAME="MilanLoginregistration";
public static final String ID="_id";
public static final String USER_NAME="USERNAME";
public static final String USER_PASSWORD ="PASSWORD";
static final String DATABASE_CREATE = "create table "+ TABLE_NAME +
"( " +ID+" integer primary key autoincrement,"+"USERNAME text not null,"+USER_PASSWORD+" text not null); ";
// Variable to hold the database instance
public SQLiteDatabase db;
// Context of the application using the database.
private final Context context;
// Database open/upgrade helper
private DataBaseHelper dbHelper;
public LoginDataBaseAdapter(Context _context)
{
context = _context;
dbHelper = new DataBaseHelper(context, DATABASE_NAME, null, DATABASE_VERSION);
}
public LoginDataBaseAdapter open() throws SQLException
{
db = dbHelper.getWritableDatabase();
return this;
}
public void close()
{
db.close();
}
public SQLiteDatabase getDatabaseInstance()
{
return db;
}
public LoginDataBaseAdapter opentoRead() throws android.database.SQLException{
dbHelper = new DataBaseHelper(context, DATABASE_NAME, null, DATABASE_VERSION);
db = dbHelper.getReadableDatabase();
return this;
}
public LoginDataBaseAdapter opentoWrite() throws android.database.SQLException{
dbHelper = new DataBaseHelper(context, DATABASE_NAME, null, DATABASE_VERSION);
db = dbHelper.getWritableDatabase();
return this;
}
public void Close(){
dbHelper.close();
}
public void insertEntry(String username,String password)
{
ContentValues newValues = new ContentValues();
newValues.put("USERNAME",username);
newValues.put("PASSWORD",password);
// Insert the row into your table
db.insert("MilanLoginregistration",null,newValues);
///Toast.makeText(context, "Reminder Is Successfully Saved", Toast.LENGTH_LONG).show();
}
public int deleteAll(){
return db.delete(TABLE_NAME, null, null);
}
public void deleteEntry(int id){
//String id=String.valueOf(ID);
db.delete(TABLE_NAME, ID+"="+id, null);
// Toast.makeText(context, "Number fo Entry Deleted Successfully : "+numberOFEntriesDeleted, Toast.LENGTH_LONG).show();
}
public Cursor queue_all(){
String[] columns = new String[]{ID,"USERNAME","PASSWORD"};
Cursor cursor_queue_all =db.query(TABLE_NAME, columns, null, null, null, null, null);
return cursor_queue_all;
}
public Cursor feching_Data(){
String[] columns = {ID,USER_NAME,USER_PASSWORD};
db = dbHelper.getWritableDatabase();
Cursor cursor = db.query(TABLE_NAME, columns,null,null,null,null,null);
return cursor;
}
public String getSinlgeEntry(String userName)
{
Cursor cursor=db.query("MilanLoginregistration", null, " USERNAME=?", new String[]{userName}, null, null, null);
if(cursor.getCount()<1) // UserName Not Exist
{
cursor.close();
return "NOT EXIST";
}
cursor.moveToFirst();
String password= cursor.getString(cursor.getColumnIndex("PASSWORD"));
//cursor.close();
return password;
}
public String checkSinlgeEntry(String userName)
{
Cursor cursor=db.query("MilanLoginregistration", null, " USERNAME=?", new String[]{userName}, null, null, null);
if(cursor.getCount()>=1) // UserName Exist
{
cursor.close();
return "NOT EXIST";
}
// cursor.close();
return "";
}
public void updateEntry(String user_name,String pasword)
{
// Define the updated row content.
ContentValues updatedValues = new ContentValues();
// Assign values for each row.
updatedValues.put("USERNAME", user_name);
updatedValues.put("PASSWORD",pasword);
String where="USERNAME = ?";
db.update("MilanLoginregistration",updatedValues, where, new String[]{user_name});
}
/*public void Display(View v){
Cursor c = db.rawQuery("select * from MilanloginRegistration", null);
admin_settings_child.text_fetched_database_results.setText("");
c.moveToFirst();
do{
String username = c.getString(c.getColumnIndex("USERNAME"));
String password = c.getString(1);
admin_settings_child.text_fetched_database_results.append("USERNAME::-->"+username+"PASSWORD::-->"+password+"\n");
}while(c.moveToNext());
}*/
}
Kindly post the code of your adapter as well. in the above code you are deleting the data from other adapter and notifying other adapter for data set changed. i.e in following lines I can't see where cursoradapter is actually being updated.
logindatabase_adapter.deleteEntry(item_id);
cursoradapter.notifyDataSetChanged();
cursoradapter.notifyDataSetInvalidated();
also you can try this.
listview.getAdapter().notifyDataSetChanged();
For proper implementing datasetchanged functionality you need to create custom adapter other wise you just setlist adapter every time your data is being changed.i.e
listeview.setAdapter(modifiedAdapter);
listview.getAdapter.notifyDataSetChanged();
Edit 1:
as you are using simple cursor adapter you need to add following lines after deleting the entry:
logindatabase_adapter.deleteEntry(item_id);
cursor = logindatabase_adapter.feching_Data();
//database_results.removeViewAt(position);
cursoradapter = new SimpleCursorAdapter(DatabaseListView.this, R.layout.listcell, cursor, from, to);
database_results.setAdapter(cursoradapter);
database_results.getAdapter().notifyDataSetChanged();
Use the notifyDataSetChanged() method on the adapter like this:
final ArrayAdapter adapter = ((ArrayAdapter) getListAdapter());
runOnUiThread(new Runnable() {
public void run() {
adapter.notifyDataSetChanged();
}
});
i follow this tutorial http://vimaltuts.com/android-tutorial-for-beginners/android-sqlite-database-example just tell me how do i add one more field in this code to take images as input and display?
please help me
import android.app.Activity;
import android.app.AlertDialog;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
public class AddEditCountry extends Activity {
private long rowID;
private EditText nameEt;
private EditText capEt;
private EditText codeEt;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.add_country);
nameEt = (EditText) findViewById(R.id.nameEdit);
capEt = (EditText) findViewById(R.id.capEdit);
codeEt = (EditText) findViewById(R.id.codeEdit);
Bundle extras = getIntent().getExtras();
if (extras != null)
{
rowID = extras.getLong("row_id");
nameEt.setText(extras.getString("name"));
capEt.setText(extras.getString("cap"));
codeEt.setText(extras.getString("code"));
}
Button saveButton =(Button) findViewById(R.id.saveBtn);
saveButton.setOnClickListener(new OnClickListener() {
public void onClick(View v)
{
if (nameEt.getText().length() != 0)
{
AsyncTask saveContactTask =
new AsyncTask()
{
#Override
protected Object doInBackground(Object... params)
{
saveContact();
return null;
}
#Override
protected void onPostExecute(Object result)
{
finish();
}
};
saveContactTask.execute((Object[]) null);
}
else
{
AlertDialog.Builder alert = new
AlertDialog.Builder(AddEditCountry.this);
alert.setTitle(R.string.errorTitle);
alert.setMessage(R.string.errorMessage);
alert.setPositiveButton(R.string.errorButton, null);
alert.show();
}
}
});
}
private void saveContact()
{
DatabaseConnector dbConnector = new DatabaseConnector(this);
if (getIntent().getExtras() == null)
{
dbConnector.insertContact(nameEt.getText().toString(),
capEt.getText().toString(),
codeEt.getText().toString());
}
else
{
dbConnector.updateContact(rowID,
nameEt.getText().toString(),
capEt.getText().toString(),
codeEt.getText().toString());
}
}
}
import android.os.AsyncTask;
import android.os.Bundle;
import android.app.ListActivity;
import android.content.Intent;
import android.database.Cursor;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.CursorAdapter;
import android.widget.ListView;
import android.widget.SimpleCursorAdapter;
import android.widget.AdapterView.OnItemClickListener;
public class CountryList extends ListActivity {
public static final String ROW_ID = "row_id";
private ListView conListView;
private CursorAdapter conAdapter;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
conListView=getListView();
conListView.setOnItemClickListener(viewConListener);
// map each name to a TextView
String[] from = new String[] { "name" };
int[] to = new int[] { R.id.countryTextView };
conAdapter = new SimpleCursorAdapter(CountryList.this, R.layout.country_list,
null, from, to);
setListAdapter(conAdapter); // set adapter
}
#Override
protected void onResume()
{
super.onResume();
new GetContacts().execute((Object[]) null);
}
#Override
protected void onStop()
{
Cursor cursor = conAdapter.getCursor();
if (cursor != null)
cursor.deactivate();
conAdapter.changeCursor(null);
super.onStop();
}
private class GetContacts extends AsyncTask
{
DatabaseConnector dbConnector = new DatabaseConnector(CountryList.this);
#Override
protected Cursor doInBackground(Object... params)
{
dbConnector.open();
return dbConnector.getAllContacts();
}
#Override
protected void onPostExecute(Cursor result)
{
conAdapter.changeCursor(result); // set the adapter's Cursor
dbConnector.close();
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu)
{
super.onCreateOptionsMenu(menu);
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.country_menu, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item)
{
Intent addContact = new Intent(CountryList.this, AddEditCountry.class);
startActivity(addContact);
return super.onOptionsItemSelected(item);
}
OnItemClickListener viewConListener = new OnItemClickListener()
{
public void onItemClick(AdapterView arg0, View arg1, int arg2,long arg3)
{
Intent viewCon = new Intent(CountryList.this, ViewCountry.class);
viewCon.putExtra(ROW_ID, arg3);
startActivity(viewCon);
}
};
}
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.database.Cursor;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.widget.TextView;
public class ViewCountry extends Activity {
private long rowID;
private TextView nameTv;
private TextView capTv;
private TextView codeTv;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.view_country);
setUpViews();
Bundle extras = getIntent().getExtras();
rowID = extras.getLong(CountryList.ROW_ID);
}
private void setUpViews() {
nameTv = (TextView) findViewById(R.id.nameText);
capTv = (TextView) findViewById(R.id.capText);
codeTv = (TextView) findViewById(R.id.codeText);
}
#Override
protected void onResume()
{
super.onResume();
new LoadContacts().execute(rowID);
}
private class LoadContacts extends AsyncTask
{
DatabaseConnector dbConnector = new DatabaseConnector(ViewCountry.this);
#Override
protected Cursor doInBackground(Long... params)
{
dbConnector.open();
return dbConnector.getOneContact(params[0]);
}
#Override
protected void onPostExecute(Cursor result)
{
super.onPostExecute(result);
result.moveToFirst();
// get the column index for each data item
int nameIndex = result.getColumnIndex("name");
int capIndex = result.getColumnIndex("cap");
int codeIndex = result.getColumnIndex("code");
nameTv.setText(result.getString(nameIndex));
capTv.setText(result.getString(capIndex));
codeTv.setText(result.getString(codeIndex));
result.close();
dbConnector.close();
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu)
{
super.onCreateOptionsMenu(menu);
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.view_country_menu, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item)
{
switch (item.getItemId())
{
case R.id.editItem:
Intent addEditContact =
new Intent(this, AddEditCountry.class);
addEditContact.putExtra(CountryList.ROW_ID, rowID);
addEditContact.putExtra("name", nameTv.getText());
addEditContact.putExtra("cap", capTv.getText());
addEditContact.putExtra("code", codeTv.getText());
startActivity(addEditContact);
return true;
case R.id.deleteItem:
deleteContact();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
private void deleteContact()
{
AlertDialog.Builder alert = new AlertDialog.Builder(ViewCountry.this);
alert.setTitle(R.string.confirmTitle);
alert.setMessage(R.string.confirmMessage);
alert.setPositiveButton(R.string.delete_btn,
new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dialog, int button)
{
final DatabaseConnector dbConnector =
new DatabaseConnector(ViewCountry.this);
AsyncTask deleteTask =
new AsyncTask()
{
#Override
protected Object doInBackground(Long... params)
{
dbConnector.deleteContact(params[0]);
return null;
}
#Override
protected void onPostExecute(Object result)
{
finish();
}
};
deleteTask.execute(new Long[] { rowID });
}
}
);
alert.setNegativeButton(R.string.cancel_btn, null).show();
}
}
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
public class DatabaseConnector {
private static final String DB_NAME = "WorldCountries";
private SQLiteDatabase database;
private DatabaseOpenHelper dbOpenHelper;
public DatabaseConnector(Context context) {
dbOpenHelper = new DatabaseOpenHelper(context, DB_NAME, null, 1);
}
public void open() throws SQLException
{
//open database in reading/writing mode
database = dbOpenHelper.getWritableDatabase();
}
public void close()
{
if (database != null)
database.close();
}
public void insertContact(String name, String cap, String code)
{
ContentValues newCon = new ContentValues();
newCon.put("name", name);
newCon.put("cap", cap);
newCon.put("code", code);
open();
database.insert("country", null, newCon);
close();
}
public void updateContact(long id, String name, String
cap,String code)
{
ContentValues editCon = new ContentValues();
editCon.put("name", name);
editCon.put("cap", cap);
editCon.put("code", code);
open();
database.update("country", editCon, "_id=" + id, null);
close();
}
public Cursor getAllContacts()
{
return database.query("country", new String[] {"_id",
"name"},
null, null, null, null, "name");
}
public Cursor getOneContact(long id)
{
return database.query("country", null, "_id=" + id, null,
null, null, null);
}
public void deleteContact(long id)
{
open();
database.delete("country", "_id=" + id, null);
close();
}
}
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.database.sqlite.SQLiteOpenHelper;
public class DatabaseOpenHelper extends SQLiteOpenHelper {
public DatabaseOpenHelper(Context context, String name,
CursorFactory factory, int version) {
super(context, name, factory, version);
}
#Override
public void onCreate(SQLiteDatabase db) {
String createQuery = "CREATE TABLE country (_id integer primary key
autoincrement,name, cap, code);";
db.execSQL(createQuery);
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
You can easily add field of BLOB type in sql, and put images like set of bytes:
//while writing to db:
ByteArrayOutputStream outStr = new ByteArrayOutputStream();
image.compress(CompressFormat.PNG, 100, outStr);
byte[] blob = outStr.toByteArray();
contentValues.put("image", blob);
//while reading from cursor:
byte[] blob = cursor.getBlob("image");
Bitmap image = BitmapFactory.decodeByteArray(blob, 0, blob.length);