Populate ListView with two tables in database in Android Studio - android

I have two tables. tblsubject and tbltopics. I want to list all the subjects with the number of topics every subject.
getSubject()
public Cursor getAllSubject() {
String where = null;
Cursor c = db.query(true, DATABASE_TABLE, ALL_KEYS, where, null, null, null, null, null);
if (c != null) {
c.moveToFirst();
}
return c;
}
countTopics()
public int countTopics(long subjectid) {
String where = KEY_TOPICSUBJECTID + " = " + subjectid;
Cursor c = db.query(true, DATABASE_TABLE2, ALL_KEYS2,
where, null, null, null, null, null);
if (c != null) {
c.moveToFirst();
}
return c.getCount();
}
viewList() this is where i populate my listview
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
public void viewList() {
Cursor cursor = myDb.getAllSubject();
String[] fromFieldNames = new String[]{DBAdapter.KEY_SUBJECTID, DBAdapter.KEY_SUBJECT, DBAdapter.KEY_DATESUBJECT};
int[] toViewIds = new int[]{R.id.txtViewSubjectId, R.id.txtViewSubject, R.id.txtSubjectDateCreated};
SimpleCursorAdapter myCursorAdapter;
myCursorAdapter = new SimpleCursorAdapter(getBaseContext(), R.layout.activity_view_the_list, cursor, fromFieldNames, toViewIds, 0);
ListView myList = (ListView) findViewById(R.id.listView);
myList.setAdapter(myCursorAdapter);
}
My problem is how to add the number of topics every subject. I can display the Subjects. Thank you.

You can run a direct raw sql with an UNION from your tables. Something like this:
String select = "Select * FROM table1 UNION Select * FROM table2";
Cursor c = return db.rawQuery(select, new String[]{});

You can update your subject SQL statement with a subquery to return the topic count from the database. See https://thoughtbot.com/blog/back-to-basics-sql#sub-queries
On a separate note, I would recommend using your own custom AsyncTask and ArrayAdapter.
https://developer.android.com/guide/topics/ui/layout/recyclerview
This will make your UI more responsive and allow you customize the data access and rendering.
By using a custom adapter you can over ride the getView function to control the result and do additional fetches. For example, lazy loading images into the listview display.
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
if (v == null) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = inflater.inflate(R.layout.subjectitem, null);
}
if (position % 2 == 1) {
v.setBackgroundColor(Color.rgb(234, 234, 234));
} else {
v.setBackgroundColor(Color.WHITE);
}
YOURDATAOBJECT p = itemList.get(position);
TextView name = (TextView) v.findViewById(R.id.name);
TextView topcount = (TextView) v.findViewById(R.id.topcount);
//You can run our additional data fetches here and update the UI

Related

How to search the data in listview by more than one thing?

Right now, my app filters the data in a listview when somethings is entered into the editText, but it can only filter by one thing at a time. I want it to be able to filter by more than value. For example, if someone types in "chicken" it should filter the recipes by the word 'chicken'. But, if someone then types in "dinner", I want it to filter the recipes by both "chicken" and "dinner." Eventually, I want to make it so those values appear as checkboxes above the listview so they can be easily removed.
I can't figure out how to do this. I played around with loops at first but didn't really get anywhere.
public class SearchActivity extends NavDrawerActivity {
private DBHandler dbHelper;
private SimpleCursorAdapter dataAdapter;
ArrayList<String> filters = new ArrayList<String>();
//String[] filters;
FrameLayout frameLayout;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setContentView(R.layout.activity_main_activity3);
frameLayout = (FrameLayout) findViewById(R.id.activity_frame);
// inflate the custom activity layout
LayoutInflater layoutInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View activityView = layoutInflater.inflate(R.layout.activity_main_activity3, null, false);
// add the custom layout of this activity to frame layout.
frameLayout.addView(activityView);
dbHelper = new DBHandler(this, null, null, 1);
//dbHelper.open();
//Clean all data
dbHelper.deleteAllRecipes();
//Add some data
dbHelper.insertSomeRecipes();
//Generate ListView from SQLite Database
displayListView();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
private void displayListView() {
final Cursor cursor = dbHelper.fetchAllRecipes();
// The desired columns to be bound
String[] columns = new String[]{
//DBHandler.COLUMN_CODE,
DBHandler.COLUMN_NAME,
DBHandler.COLUMN_TYPE,
DBHandler.COLUMN_INGRED
};
// the XML defined views which the data will be bound to
int[] to = new int[]{
//R.id.code,
R.id.name,
R.id.type,
R.id.ingredient,
};
// create the adapter using the cursor pointing to the desired data
//as well as the layout information
dataAdapter = new SimpleCursorAdapter(
this, R.layout.recipeinfo,
cursor,
columns,
to,
0);
ListView listView = (ListView) findViewById(R.id.listView1);
// Assign adapter to ListView
listView.setAdapter(dataAdapter);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> listView, View view,
int position, long id) {
// Get the cursor, positioned to the corresponding row in the result set
Cursor cursor = (Cursor) listView.getItemAtPosition(position);
String recipeName = cursor.getString(cursor.getColumnIndexOrThrow("name"));
Intent n = new Intent(getApplicationContext(), RecipeActivity.class);
//n.putExtra("position", position);
n.putExtra("recipeName", recipeName);
startActivity(n);
}
});
//final GridView gridView = (GridView)findViewById(R.id.gridView);
final TextView tv = (TextView)findViewById(R.id.textView14);
final EditText myFilter = (EditText) findViewById(R.id.myFilter);
myFilter.setImeActionLabel("Filter",1);
myFilter.setPrivateImeOptions("actionUnspecified");
myFilter.setOnEditorActionListener(new TextView.OnEditorActionListener() {
#Override
public boolean onEditorAction(TextView textView, int id, KeyEvent keyEvent) {
if (id == 1 || id == EditorInfo.IME_NULL) {
String filter = textView.getText().toString();
dataAdapter.getFilter().filter(filter);
filters.add(filter);
tv.append(filter);
myFilter.setText("");
}
return false;
}
});
dataAdapter.setFilterQueryProvider(new FilterQueryProvider() {
public Cursor runQuery(CharSequence constraint) {
return dbHelper.fetchRecipesByName(constraint.toString());
}
});
}
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
// Then you start a new Activity via Intent
Intent intent = new Intent();
intent.setClass(this, RecipeActivity.class);
intent.putExtra("position", position);
// Or / And
intent.putExtra("id", id);
startActivity(intent);
}
}
fetchRecipesByName in DBHandler
public Cursor fetchRecipesByName(String inputText) throws SQLException {
SQLiteDatabase mDb = this.getWritableDatabase();
Log.w(TAG, inputText);
Cursor mCursor = null;
if (inputText == null || inputText.length () == 0) {
mCursor = mDb.query(SQLITE_TABLE, new String[] {COLUMN_ROWID,
COLUMN_NAME, COLUMN_TYPE, COLUMN_INGRED, COLUMN_IMGPATH},
null, null, null, null, null);
}
else {
mCursor = mDb.query(true, SQLITE_TABLE, new String[] {COLUMN_ROWID,
COLUMN_NAME, COLUMN_TYPE, COLUMN_INGRED, COLUMN_IMGPATH},
COLUMN_NAME + " like '%" + inputText + "%'" + " or " +
COLUMN_TYPE + " like '%" + inputText + "%'" + " or " +
COLUMN_INGRED + " like '%" + inputText + "%'",
null, null, null, null, null);
}
if (mCursor != null) {
mCursor.moveToFirst();
}
return mCursor;
}
What is the implementation of dbHelper.fetchReccipesByName()? I think, as of now, it queries the table only by one thing. You should change its logic and implement your complex need in this method (obviously, it should be an SQL query execution).
As a best practice, you should call listView.setFilterText() instead of dataAdapter.getFilter().filter(), because this method is supposed to run in secondary thread for the reason that DB queries are time consuming. If you call listView.setFilterText(), the framework will take care of threading and calls filter.filter() in secondary thread.
And finally, since you are searching by more than one keyword, but setFilterText() accepts only one CharSequence param, you should encode somehow many keywords into single String (say comma separated). And while querying you could decode the constraint to get the keywords.

Issue in Data filled in Spinner from Database

I have an External Database into assets folder. I have been successful into loading it on my Emulator and performing operations on it.
I also know how to fill data using queries in Spinner and ListView.
The main issue: I am running a query which gives me all data from the table. I store them in a Bean class. Now i have successfully filled one of the column data into a spinner.
BUT, when i open the spinner, i don't get Database values but object name into spinner
FOR e.g -- com.mypackageName.BeanPackage.BeanClass#411da123
I get the whole spinner full of this, not the Data which is in Database( e.g 13, 13/1) .
My Code :
Query in DBHelper Class :
public Cursor getBusNumbers() {
// date="21-10-2013";
String myPath = DB_PATH + DB_NAME;
db = SQLiteDatabase.openDatabase(myPath, null,
SQLiteDatabase.OPEN_READONLY);
return db.rawQuery("select * from table", null);
}
In My Main Activity :
Adapter code :
adapter = new Adapter(MainActivity.this,android.R.layout.simple_spinner_item, array);
route.setAdapter(adapter);
adapter.notifyDataSetChanged();
My GetView method:
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = ((LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE))
.inflate(layout, null);
}
final Bean item = items.get(position);
final TextView km = (TextView) convertView
.findViewById(android.R.id.text1);
km.setText(item.getRouteNumber());
km.setTextSize(22);
return convertView;
}
}
Method which fills the Array :
private void loadFieldDatabase() {
Cursor c = dbhelper.getBusNumbers();
if (c != null && c.getCount() > 0) {
c.moveToFirst();
for (int count = 0; count < c.getCount(); count++) {
Bean detail = new Bean();
detail.setRouteNumber(c.getString(c
.getColumnIndex("route_number")));
array.add(detail);
c.moveToNext();
}
c.close();
//dbhelper.close();
}
Here in your code your setting the Bean object into the Text view insted of which item you need to set that.
Try this code this may help you.
private void loadSpinnerCourse() {
// TODO Auto-generated method stub
List<String> lables = getAllCourse();
// Creating adapter for spinner
dataAdapterCourse = new ArrayAdapter<String>(getActivity(),
android.R.layout.simple_spinner_item, lables);
// Drop down layout style - list view with radio button
dataAdapterCourse
.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
// attaching data adapter to spinner
mLesson_course.setAdapter(dataAdapterCourse);
}
private List<String> getAllCourse() {
// TODO Auto-generated method stub
List<String> labels = new ArrayList<String>();
mCoureseIdList = new ArrayList<String>();
ExamDatabaseConnector dbConnector = new ExamDatabaseConnector(
getActivity());
dbConnector.open();
String selectQuery = "SELECT * FROM courses_stud";
Cursor cursor = dbConnector.database.rawQuery(selectQuery, null);
// looping through all rows and adding to list
if (cursor.moveToFirst()) {
do {
mCoureseIdList.add(cursor.getString(0));
labels.add(cursor.getString(1));
} while (cursor.moveToNext());
}
// closing connection
cursor.close();
dbConnector.database.close();
// returning lables
return labels;
}
Cursor cursor = db.getAllBhashat();
SpinnerArr = new String[cursor.getCount()+1];
SpinnerArr[0] = "<-SELECT->";
if(cursor.moveToNext()){
int i = 1;
do {
SpinnerArr[i] = cursor.getString(cursor
.getColumnIndex("LocalityTitle_E"));
i++;
} while (cursor.moveToNext());
}if (cursor != null && !cursor.isClosed()) {
cursor.close();
}
ArrayAdapter<String> adapter_sorCat = new ArrayAdapter<String>(
this, android.R.layout.simple_spinner_item, SpinnerArr);
Spinner.setAdapter(adapter_sorCat);
adapter_sorCat
.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
}

Fetching Contact detail Take A lot of time in android?

Hi am currently doing a project related to Contact ,Where I am fetching details from the contact*(Email,Number and Contactname)* and it does well.But the problem is it take a long time to fetch the contact details ( 1000+ contact including contact that sync from social network sites).so that I put a Asynchronous Task for this purpose ,and it does well but the problem is due to a long time to complete the fetching process ,when I press the back button it crash during the Asynchronous task .My problem does not crash why this fetching contact take a lot of time.Is there way to get the contact faster. My code to get contact detail is as given below
public void readContact() {
contactname = new ArrayList<String>();
contactnumber = new ArrayList<String>();
companyname_one = new ArrayList<String>();
contactemail = new ArrayList<String>();
people = getContentResolver().query(
ContactsContract.Contacts.CONTENT_URI, null, null, null,
PhoneLookup.DISPLAY_NAME);
while (people.moveToNext()) {
int nameFieldColumnIndex = people
.getColumnIndex(PhoneLookup.DISPLAY_NAME);
String contact = people.getString(nameFieldColumnIndex);
if (contact == null) {
contactname.add("No contact Set");
} else {
contactname.add(contact);
}
String szId = people.getString(people
.getColumnIndexOrThrow(ContactsContract.Contacts._ID));
cursor_one = getContentResolver().query(
ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
null,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID + "='"
+ szId + "'", null, null);
if (cursor_one.moveToNext()) {
String number = cursor_one.getString(cursor_one
.getColumnIndex(Phone.NUMBER));
contactnumber.add(number);
cursor_one.close();
} else {
contactnumber.add("no number");
cursor_one.close();
}
emails_value = getContentResolver().query(
Email.CONTENT_URI,
null,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID + "='"
+ szId + "'", null, null);
if (emails_value.moveToNext()) {
email_sorting = emails_value.getString(emails_value
.getColumnIndex(Email.DATA));
checkAll();
} else {
contactemail.add("no email");
emails_value.close();
}
}
people.close();
System.out.println("noz " + contactnumber);
System.out.println("name" + contactname);
System.out.println("email" + contactemail);
System.out.println("noz size " + contactnumber.size());
System.out.println("name size " + contactname.size());
System.out.println("contactemail size " + contactemail.size());
}
The checkAll() method is patter matching of email as below
public boolean checkAll() {
boolean chkAll = true;
Pattern p1 = Pattern.compile(".+#.+\\.[a-z]+");
Matcher m1 = p1.matcher(email_sorting.trim());
if (!m1.matches()) {
contactemail.add("no email");
contactemail_sort.add("no email");
emails_value.close();
chkAll = false;
} else {
contactemail.add(email_sorting);
contactemail_sort.add(email_sorting);
emails_value.close();
chkAll = true;
}
return chkAll;
}
Ok, I think I finally see the best way for this to work. Instead of pulling all of the contact information out before you create your adapter, you should create a custom CursorAdapter that accepts your people cursor and populates a custom view with your cursor_one query that is executed on a background thread. This should take advantage of the natural lazyloading of the ListView and make this work like you want.
If your using at least Android 3.0, you can use Loaders instead of using an AsyncTask.
I found an example of a custom cursor adapter here which is what I used to make my example. There are probably better ways to implement this in code, but this at least shows you which methods to override and what to put in them.
public class ContactListCursorAdapter extends SimpleCursorAdapter {
private Context context;
private int layout;
public ContactListCursorAdapter (Context context, int layout, Cursor c, String[] from, int[] to) {
super(context, layout, c, from, to);
this.context = context;
this.layout = layout;
}
// Used to populate new list items
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
Cursor c = getCursor();
final LayoutInflater inflater = LayoutInflater.from(context);
View v = inflater.inflate(layout, parent, false);
int nameCol = c.getColumnIndex(People.NAME);
String name = c.getString(nameCol);
/**
* Next set the name of the entry.
*/
TextView name_text = (TextView) v.findViewById(R.id.name_entry);
if (name_text != null) {
name_text.setText(name);
}
getDeatils(v,c);
return v;
}
// Used to bind a new item from the adapter to an existing view
#Override
public void bindView(View v, Context context, Cursor c) {
int nameCol = c.getColumnIndex(People.NAME);
String name = c.getString(nameCol);
/**
* Next set the name of the entry.
*/
TextView name_text = (TextView) v.findViewById(R.id.name_entry);
if (name_text != null) {
name_text.setText(name);
}
getDetails(v,c);
}
private void populateDetails(View v, Cursor c) {
// Start your AsyncTask or Loader to get the details.
// Be sure to populate the view with the results in the
// appropriate completion callback.
}
}
My suggestion would be to redefine how your structure works. For instance it is really quick to get the basic information about a contact, the display name and other meta data for instance. Show that in a list or whatever and then when they select or view a contact then load the rest of the information.
This will speed it up a lot. However if you must load everything about a contact at once then yes it will be very slow due to how many queries you need to execute.
Another suggestion would be to show them as the completed to the user. That way there is some progress and they can view it. Instead of just putting a dialog up that says "Loading Wait".

Android SQLite get data from database to an array

i want to get the value from the cursor without the SimpleCursorAdapter part.here is the code
public Cursor queueAll(){
String[] columns = new String[]{KEY_ID, KEY_CONTENT1, KEY_CONTENT2,KEY_CONTENT3};
Cursor cursor = sqLiteDatabase.query(MYDATABASE_TABLE, columns,
null, null, null, null, null);
return cursor;
}
and the activity side code
cursor = mySQLiteAdapter.queueAll();
from = new String[]{SQLiteAdapter.KEY_ID, SQLiteAdapter.KEY_CONTENT1, SQLiteAdapter.KEY_CONTENT2, SQLiteAdapter.KEY_CONTENT3};
int[] to = new int[]{R.id.id, R.id.text1, R.id.text2,R.id.text3};
cursorAdapter =
new SimpleCursorAdapter(this, R.layout.row, cursor, from, to);
listContent.setAdapter(cursorAdapter);
while(!cursor.isAfterLast())
{
String tilt = cursor.getString(cursor.getColumnIndex(SQLiteAdapter.KEY_CONTENT1));
String pkg = cursor.getString(cursor.getColumnIndex(SQLiteAdapter.KEY_CONTENT3));
if(tilt.equals("LEFT"))
{
Log.v("LEFT",pkg);
}
else if(tilt.equals("RIGHT"))
{
Log.v("RIGHT",pkg);
}
cursor.moveToNext();
}
i am getting the pkg value correct.but i want to get the values directly from the cursor while removing SimpleCursorAdapter part the code doesn't work.
any help would be appreciated :)
You can get values without declaring adapters. Adapters are need if you want to show the data in the list widgets. So your can be the following:
cursor = mySQLiteAdapter.queueAll();
if (cursor == null) {
//check if there are errors or query just return null
}
if (cursor.moveToFirst()) {
while(!cursor.isAfterLast())
{
String tilt = cursor.getString(cursor.getColumnIndex(SQLiteAdapter.KEY_CONTENT1));
String pkg = cursor.getString(cursor.getColumnIndex(SQLiteAdapter.KEY_CONTENT3));
if(tilt.equals("LEFT"))
{
Log.v("LEFT",pkg);
}
else if(tilt.equals("RIGHT"))
{
Log.v("RIGHT",pkg);
}
cursor.moveToNext();
}
}
First you must count how many rows are in your table. Then assign that count to variable and it use to create an array. For array size you can use that count variable. Then create a for loop and use that count variable for rounds. After create your query and assign values to your arrays. 100% worked!.
int sqlcount;
Cursor mFetch;
SQLiteDatabase mydb = openOrCreateDatabase("your database name", MODE_PRIVATE, null);
mydb.execSQL("create table if not exists customer(name varchar,email varchar)");
Cursor mCount = mydb.rawQuery("select count(*) from customer", null);
mCount.moveToFirst();
sqlcount = mCount.getInt(0);
mCount.close();
String cname[] = new String[sqlcount];
String cemail[] = new String[sqlcount];
for(int i=0;i<sqlcount;i++) {
mFetch= mydb.rawQuery("select name,email from customer", null);
mFetch.moveToPosition(i);
cname[i] = mFetch.getString(0);
cemail[i] = mFetch.getString(1);
}
mFetch.close();
Toast.makeText(MainActivity.this,String.valueOf(cname[0]),Toast.LENGTH_SHORT).show();
Toast.makeText(MainActivity.this,String.valueOf(cemail[1]),Toast.LENGTH_SHORT).show();

Iterate through rows from Sqlite-query

I have a table layout that I want to populate with the result from a database query. I use a select all and the query returns four rows of data.
I use this code to populate the TextViews inside the table rows.
Cursor c = null;
c = dh.getAlternative2();
startManagingCursor(c);
// the desired columns to be bound
String[] columns = new String[] {DataHelper.KEY_ALT};
// the XML defined views which the data will be bound to
int[] to = new int[] { R.id.name_entry};
SimpleCursorAdapter mAdapter = new SimpleCursorAdapter(this,
R.layout.list_example_entry, c, columns, to);
this.setListAdapter(mAdapter);
I want to be able to separate the four different values of KEY_ALT, and choose where they go. I want them to populate four different TextViews instead of one in my example above.
How can I iterate through the resulting cursor?
Cursor objects returned by database queries are positioned before the first entry, therefore iteration can be simplified to:
while (cursor.moveToNext()) {
// Extract data.
}
Reference from SQLiteDatabase.
You can use below code to go through cursor and store them in string array and after you can set them in four textview
String array[] = new String[cursor.getCount()];
i = 0;
cursor.moveToFirst();
while (!cursor.isAfterLast()) {
array[i] = cursor.getString(0);
i++;
cursor.moveToNext();
}
for (boolean hasItem = cursor.moveToFirst(); hasItem; hasItem = cursor.moveToNext()) {
// use cursor to work with current item
}
Iteration can be done in the following manner:
Cursor cur = sampleDB.rawQuery("SELECT * FROM " + Constants.TABLE_NAME, null);
ArrayList temp = new ArrayList();
if (cur != null) {
if (cur.moveToFirst()) {
do {
temp.add(cur.getString(cur.getColumnIndex("Title"))); // "Title" is the field name(column) of the Table
} while (cur.moveToNext());
}
}
Found a very simple way to iterate over a cursor
for(cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()){
// access the curosr
DatabaseUtils.dumpCurrentRowToString(cursor);
final long id = cursor.getLong(cursor.getColumnIndex(BaseColumns._ID));
}
I agree to chiranjib, my code is as follow:
if(cursor != null && cursor.getCount() > 0){
cursor.moveToFirst();
do{
//do logic with cursor.
}while(cursor.moveToNext());
}
public void SQLfunction() {
SQLiteDatabase db = getReadableDatabase();
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
String[] sqlSelect = {"column1","column2" ...};
String sqlTable = "TableName";
String selection = "column1= ?"; //optional
String[] selectionArgs = {Value}; //optional
qb.setTables(sqlTable);
final Cursor c = qb.query(db, sqlSelect, selection, selectionArgs, null, null, null);
if(c !=null && c.moveToFirst()){
do {
//do operations
// example : abcField.setText(c.getString(c.getColumnIndex("ColumnName")))
}
while (c.moveToNext());
}
}
NOTE: to use SQLiteQueryBuilder() you need to add
compile 'com.readystatesoftware.sqliteasset:sqliteassethelper:+'
in your grade file

Categories

Resources