Duplicate contacts in resultant List View using cursor adapter - android

I am creating simple contact application where i want to display only name and number in the list view.
I used cursor adapter to load the contact name and number alone in the list of columns(FROM string array) in Simple Cursor Adapter. However my output lists out contact email id and duplicate names. Here is my code. Please help me to figure out where i went wrong to extract name and number alone.
import android.app.ListActivity;
import android.app.LoaderManager.LoaderCallbacks;
import android.content.CursorLoader;
import android.content.Intent;
import android.content.Loader;
import android.database.Cursor;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.SimpleCursorAdapter;
import android.widget.Toast;
public class ListViewLoader extends ListActivity implements
LoaderCallbacks<Cursor> {
SimpleCursorAdapter mAdapter;
static final String[] PROJECTION = new String[] {
ContactsContract.Data._ID, ContactsContract.Data.DISPLAY_NAME,
ContactsContract.CommonDataKinds.Phone.NUMBER };
static final String SELECTION = "((" + ContactsContract.Data.DISPLAY_NAME
+ " NOTNULL) AND (" + ContactsContract.Data.DISPLAY_NAME
+ " != '' ) AND ("
+ ContactsContract.CommonDataKinds.Phone.HAS_PHONE_NUMBER
+ " != 0 ))";;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ProgressBar progressBar = new ProgressBar(this);
progressBar.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT));
progressBar.setIndeterminate(true);
getListView().setEmptyView(progressBar);
ViewGroup root = (ViewGroup) findViewById(android.R.id.content);
root.addView(progressBar);
String[] fromColumns = { ContactsContract.Data.DISPLAY_NAME,
ContactsContract.CommonDataKinds.Phone.NUMBER };
int[] toViews = { android.R.id.text1, android.R.id.text2 };
mAdapter = new SimpleCursorAdapter(this,
android.R.layout.simple_list_item_2, null, fromColumns,
toViews, 0);
setListAdapter(mAdapter);
getLoaderManager().initLoader(0, null, this);
}
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
return new CursorLoader(this, ContactsContract.Data.CONTENT_URI,
PROJECTION, SELECTION, null, null);
}
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
mAdapter.swapCursor(data);
}
public void onLoaderReset(Loader<Cursor> loader) {
mAdapter.swapCursor(null);
}
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
}
}
My Output that lists out email ids which i do not want to get populated:
A
a#gmail.com
B
b#gmail.com
C
c#gmail.com
D
d#gmail.com
A
(000)000-000
B
(111)111-111
(Since I do not have enough reputation, I am unable to upload my output image. Sorry for that)

Related

Alphabetize and sort a String[] Array (from Contacts) in a Fragment

I have read for hours and hours to figure out how to sort and alphabetize a String[], but since I am pulling from my phone's Contacts and this whole ListView is a Fragment, there is nothing that really addresses my situation. I must use a CursorAdapter in my String[] and some alphabetize tutorials use other adapters, so I couldn't figure it out.
If you know of a very simple way to sort/alphabetize my String[] using the code I already have (considering all the particulars that come with using a ListView, Fragment, and pulling from Contacts), I would be very grateful. Currently this code works, but it pulls contacts that are not sorted.
Thanks for your suggestions.
ContactsFragment.java
package com.example.practiceapp.addressbook;
import java.util.ArrayList;
import java.util.Arrays;
import android.app.ListFragment;
import android.app.LoaderManager.LoaderCallbacks;
import android.content.CursorLoader;
import android.content.Loader;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.provider.ContactsContract.Contacts;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CursorAdapter;
import android.widget.ListView;
import android.widget.SimpleCursorAdapter;
import com.example.practiceapp.R;
/*
* Taken from http://stackoverflow.com/questions/18199359/how-to-display-contacts-in-a-listview-in-android-for-android-api-11
*/
public class ContactsFragment extends ListFragment implements
LoaderCallbacks<Cursor>{
private CursorAdapter mAdapter;
public ListView listView;
// Name should be displayed in the text1 TextView in item layout
public static String[] from = { ContactsContract.Contacts.DISPLAY_NAME_PRIMARY };
private static final int[] TO = { android.R.id.text1 };
private android.content.Context context;
ArrayList<String> elements;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// create adapter once
context = getActivity();
int layout = android.R.layout.simple_list_item_1;
Cursor c = null; // there is no cursor yet
int flags = 0; // no auto-requery! Loader requeries.
Arrays.sort(from);
// put List in adapter
mAdapter = new SimpleCursorAdapter(context, layout, c, from, TO, flags);
}
// columns requested from the database
private static final String[] PROJECTION = {
Contacts._ID,
ContactsContract.Contacts.DISPLAY_NAME_PRIMARY
};
// Empty public constructor, required by the system
public ContactsFragment() {}
// A UI Fragment must inflate its View (all fragments must override onCreateView)
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the fragment layout
View view = inflater.inflate(R.layout.contact_list_view,
container, false);
listView = (ListView) view.findViewById(R.id.list);
return view;
}
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
// and tell loader manager to start loading
getLoaderManager().initLoader(0, null, this);
listView.setAdapter(mAdapter);
listView.setFastScrollEnabled(true);
}
#Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
// load from the "Contacts table"
Uri contentUri = Contacts.CONTENT_URI;
// no sub-selection, no sort order, simply every row
// projection says we want just the _id and the name column
return new CursorLoader(getActivity(),
contentUri,
PROJECTION,
null,
null,
null
);
}
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
// Once cursor is loaded, give it to adapter
mAdapter.swapCursor(data);
}
#Override
public void onLoaderReset(Loader<Cursor> loader) {
// Delete the reference to the existing Cursor,
// so it can recycle it
mAdapter.swapCursor(null);
}
}
The last parameter to the CursorLoader constructor is the sort order. It uses the same syntax as a normal SQL ORDER BY clause.

How to delete row in listview with SimpleCursorAdapter using button

I added a delete button in my ListView row and am trying to find a way to make the delete button work inside of my ListView. I can have my code delete the item from the database, I just need help finding where and how to attach a click event to the row's delete button.
I tried creating a custom cursor adapter, but ran into tons of errors when using my application. Any help is greatly appreciated!
Here's my code:
ListRecipients.java
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.Color;
import android.os.Bundle;
import android.support.v4.widget.SimpleCursorAdapter;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
public class ListRecipients extends Activity
{
ListView list;
Cursor cursor;
SimpleCursorAdapter adapter;
//CursorAdapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.list);
DbHelper dbhelper = new DbHelper(getApplicationContext());
SQLiteDatabase db = dbhelper.getWritableDatabase();
String[] from = new String[] { DbHelper.NAME, DbHelper.PHONE, DbHelper.MESSAGE };
String[] column = new String[] {DbHelper.ID, DbHelper.NAME, DbHelper.PHONE, DbHelper.MESSAGE };
int[] toViewIDs = new int[] { R.id.text_list_name, R.id.text_list_phoneNum, R.id.text_list_message };
cursor = db.query(DbHelper.TABLE_NAME, column, null, null, null, null, null);
adapter = new SimpleCursorAdapter(this, R.layout.list_item, cursor, from, toViewIDs, 0);
//adapter = new CursorAdapter(this, cursor);
list = (ListView)findViewById(R.id.listview_list);
list.setAdapter(adapter);
cursor.moveToFirst();
while (cursor.moveToNext())
{
String name = cursor.getString(cursor.getColumnIndex(DbHelper.NAME));
String phone = cursor.getString(cursor.getColumnIndex(DbHelper.PHONE));
String message = cursor.getString(cursor.getColumnIndex(DbHelper.MESSAGE));
Toast.makeText(getApplicationContext(), "Name = " + name + "\nPhone = " + phone + "\nMessage = " + message, Toast.LENGTH_SHORT).show();
}
}
}
CustomCursorAdapter.java
import android.content.Context;
import android.database.Cursor;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.CursorAdapter;
import android.widget.Toast;
public class UserCustomAdapter extends CursorAdapter {
Cursor cursor;
LayoutInflater inflater;
Context context;
public UserCustomAdapter(Context context, Cursor cursor) {
super(context, cursor);
this.cursor = cursor;
this.context = context;
inflater = LayoutInflater.from(context);
}
#Override
public void bindView(View view, Context context, final Cursor cursor) {
final String itemId = cursor.getString(cursor.getColumnIndex("ID"));
Button btnDeleteRecipient = (Button) view.findViewById(R.id.btn_list_delete);
btnDeleteRecipient.setOnClickListener(new OnClickListener() {
public void onClick(View arg0) {
Log.i("ListRecipient", "Delete clicked");
//deleteRecordWithId(itemId);
cursor.requery();
notifyDataSetChanged();
}
});
}
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
View v = inflater.inflate(R.layout.list_item, null);
return v;
}
}
This Idea is Old,
Try to implement Listview with check box and put only a single delete button wherever you like.
When user select multiple check box then get all checked item and then delete that rows only.
here you can find complete example .

Adapter doesn´t show the corrects Strings

I´m developing an android app and I want to display some data from a database in a ListView with a Title and Subtitle. I did an adapter extending SimpleCursorAdapter and it´s working but it shows the 2 first fields and no what I choose in the method BindView. I´m trying to find the error but I can´t, probably it´s something really stupid but that errors is really hard to find by yourself :-)
So that's the code of the adapter:
package com.apeirons.apeironsdatabasemanager;
import android.content.Context;
import android.database.Cursor;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.SimpleCursorAdapter;
import android.widget.TextView;
public class MyListAdapter extends SimpleCursorAdapter {
//private Context context;
LayoutInflater inflater;
#SuppressWarnings("deprecation")
public MyListAdapter(Context context, int layout, Cursor c, String[] from,
int[] to) {
super(context, R.layout.consult, c, from, to);
inflater = LayoutInflater.from(context);
}
public void bindview (View view, Context context, Cursor cursor){
TextView titulo = (TextView)view.findViewById(R.id.Titulo);
titulo.setText(cursor.getString(cursor.getColumnIndex("name")));
TextView subtitulo = (TextView)view.findViewById(R.id.SubTitulo);
subtitulo.setText(cursor.getString(cursor.getColumnIndex("kind_place")));
subtitulo.append(cursor.getString(cursor.getColumnIndex("score")));
}
#Override
public View newView (Context context, Cursor cursor, ViewGroup parent){
View v = inflater.inflate(R.layout.entrys, parent, false);
return v;
}
}
And here is where I use the adapter:
package com.apeirons.apeironsdatabasemanager;
import android.app.Activity;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.util.Log;
import android.widget.ListView;
public class Consult extends Activity {
private ListView list;
private SQLiteDatabase db;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.consult);
list = (ListView)findViewById(R.id.list);
this.getIntent();
ApeironsSQLiteHelper apeironsdb = new ApeironsSQLiteHelper(this, "DBApeirons.DB", null, 1);
db = apeironsdb.getReadableDatabase();
String[] campos = new String[]{"_id", "name", "kind_place", "score"};
Cursor c = db.query("Apeirons", campos, null, null, null, null, null);
int cuenta = c.getCount();
c.moveToFirst();
Log.d("CONSULTA", Integer.toString(cuenta));
Log.d("CURSOR", c.getString(c.getColumnIndex("score")));
String[] from = new String[]{"name", "kind_place", "score"};
int [] to = new int[] {R.id.Titulo, R.id.SubTitulo};
//#SuppressWarnings("deprecation")
MyListAdapter myadapter = new MyListAdapter (this,
R.layout.entrys, c, from, to);
list.setAdapter(myadapter);
}
}
Really thank you for your help.
You are not overriding the bindView method of SimpleCursorAdapter, but defining a new method bindview (not the capitalisation!) which is called nowhere.
Because your new method is public in a public class, you won't be warned by the compiler that it is unused.
If you had used the #Override annotation, your compiler would have warned you that you don't actually override a method...

Why does it say the constructor is undefined?

I am making an android app for my group project and getting the following error:
The constructor GradesDataSource(AddGradesFragment) is undefined
This is the code containing the error:
package com.petroc.nationaldiploma;
import java.util.ArrayList;
import java.util.List;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Spinner;
import com.actionbarsherlock.app.SherlockFragment;
public class AddGradesFragment extends SherlockFragment {
private GradesDataSource datasource;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
datasource = new GradesDataSource(this);
Spinner spinner;
View view = inflater.inflate(R.layout.fragment_add_grades, container,
false);
spinner = (Spinner) view.findViewById(R.id.spinner);
List<String> list = new ArrayList<String>();
list.add("Pass");
list.add("Merit");
list.add("Distinction");
ArrayAdapter<String> dataAdapter = new ArrayAdapter<String>(
getActivity(), android.R.layout.simple_spinner_item, list);
dataAdapter
.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(dataAdapter);
spinner = (Spinner) view.findViewById(R.id.spinner);
spinner.setOnItemSelectedListener(new CustomOnItemSelectedListener());
// EditText editText = (EditText)
// view.findViewById(R.id.editModuleText1);
return view;
}
}
This is the GradesDataSource class:
package com.petroc.nationaldiploma;
import java.util.ArrayList;
import java.util.List;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
public class GradesDataSource {
// Database fields
private SQLiteDatabase database;
private MySQLiteHelper dbHelper;
private String[] allColumns = { MySQLiteHelper.COLUMN_ID,
MySQLiteHelper.COLUMN_GRADE, MySQLiteHelper.COLUMN_MODULE };
public GradesDataSource(Context context) {
dbHelper = new MySQLiteHelper(context);
}
public void open() throws SQLException {
database = dbHelper.getWritableDatabase();
}
public void close() {
dbHelper.close();
}
public Grade createGrade(String grade, String module) {
ContentValues values = new ContentValues();
values.put(MySQLiteHelper.COLUMN_GRADE, grade);
values.put(MySQLiteHelper.COLUMN_MODULE, module);
long insertId = database.insert(MySQLiteHelper.TABLE_GRADES, null,
values);
Cursor cursor = database.query(MySQLiteHelper.TABLE_GRADES,
allColumns, MySQLiteHelper.COLUMN_ID + " = " + insertId, null,
null, null, null);
cursor.moveToFirst();
Grade newGrade = cursorToGrade(cursor);
cursor.close();
return newGrade;
}
public void deleteGrade(Grade grade) {
long id = grade.getId();
System.out.println("Grade deleted with id: " + id);
database.delete(MySQLiteHelper.TABLE_GRADES, MySQLiteHelper.COLUMN_ID
+ " = " + id, null);
}
public List<Grade> getAllGrades() {
List<Grade> grades = new ArrayList<Grade>();
Cursor cursor = database.query(MySQLiteHelper.TABLE_GRADES,
allColumns, null, null, null, null, null);
cursor.moveToFirst();
while (!cursor.isAfterLast()) {
Grade grade = cursorToGrade(cursor);
grades.add(grade);
cursor.moveToNext();
}
// Make sure to close the cursor
cursor.close();
return grades;
}
private Grade cursorToGrade(Cursor cursor) {
Grade grade = new Grade();
grade.setId(cursor.getLong(0));
grade.setGrade(cursor.getString(1));
return grade;
}
}
why am I getting this error? I used this tutorial: http://www.vogella.com/articles/AndroidSQLite/article.html
the resulting app worked fine and I am now adding this code to the app for my group project
Change this line:
datasource = new GradesDataSource(this);
to
datasource = new GradesDataSource(getActivity());
You are passing a reference to the Fragment for which there is no constructor. You want to pass in the context of the Host Activity which is obtained via the getActivity() method.
Instead of
datasource = new GradesDataSource(this);
you should use
datasource = new GradesDataSource(getActivity());

NullPointerException in onLoaderFinished using SimpleCursorAdapter

I have switched from a ResourceCursorAdapter where I used newView and bindView to a SimpleCursorAdapter where I am using only the getView method.
Now I have an error in onLoaderFinished. Although it gives me NullPointerException on adapter.swapCursor(cursor) both my adapter and cursor object are NOT null. I will post all of my code below. Any help is greatly appreciated (not got much hair left to pull out).
import android.annotation.SuppressLint;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import android.support.v4.widget.ResourceCursorAdapter;
import android.util.Log;
import android.util.SparseBooleanArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.Window;
import android.widget.CheckBox;
import android.widget.ListView;
import android.widget.TextView;
public class ContactSelect extends FragmentActivity implements LoaderManager.LoaderCallbacks<Cursor> {
private static final int LOADER_ID = 1;
private MyAdapter adapter;
private ListView list;
private View row;
private SparseBooleanArray checkedState = new SparseBooleanArray();
#SuppressLint({ "NewApi", "NewApi" })
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
setContentView(R.layout.activity_contact_select);
adapter = new MyAdapter(this, R.layout.contacts_select_row, null, null, null, 0);
getSupportLoaderManager().initLoader(LOADER_ID, null, this);
list = (ListView)findViewById(R.id.list);
list.setAdapter(adapter);
list.setEmptyView(findViewById(R.id.empty));
}
#SuppressLint("NewApi")
public Loader<Cursor> onCreateLoader(int arg0, Bundle arg1) {
final String projection[] = new String[]{ContactsContract.Contacts._ID, ContactsContract.Contacts.DISPLAY_NAME};
final Uri uri = ContactsContract.Contacts.CONTENT_URI;
final String selection = ContactsContract.Contacts.HAS_PHONE_NUMBER + "=1" +
" AND " + ContactsContract.Contacts.IN_VISIBLE_GROUP + " =1";
final String order = ContactsContract.Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC";
final CursorLoader loader = new CursorLoader(this, uri, projection, selection, null, order);
return loader;
}
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
for(int i=0;i<cursor.getCount();i++){
checkedState.put(i, false);
}
adapter.swapCursor(cursor);
}
public void onLoaderReset(Loader<Cursor> loader) {
adapter.swapCursor(null);
}
private class MyAdapter extends SimpleCursorAdapter implements OnClickListener{
private CheckBox markedBox;
private TextView familyText;
private Context context;
private Cursor cursor;
public MyAdapter(Context context, int layout, Cursor c, String[] from,
int[] to, int flags) {
super(context, layout, c, from, to, flags);
this.context = context;
this.cursor = getCursor();
}
#Override
public View getView(int position, View view, ViewGroup group) {
final LayoutInflater li = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
row = li.inflate(R.layout.contacts_select_row, group, false);
view.setTag(cursor.getPosition());
view.setOnClickListener(this);
familyText = (TextView)view.findViewById(R.id.contacts_row_family_name);
markedBox = (CheckBox)view.findViewById(R.id.contacts_row_check);
familyText.setText(cursor.getString(cursor.getColumnIndexOrThrow(ContactsContract.Contacts.DISPLAY_NAME)));
boolean currentlyChecked = checkedState.get(cursor.getPosition());
markedBox.setChecked(currentlyChecked);
setProgressBarIndeterminateVisibility(false);
return super.getView(position, view, group);
}
public void onClick(View view) {
int rowId = (Integer)view.getTag();
Log.d("OnClick", String.valueOf(rowId));
boolean currentlyChecked = checkedState.get(rowId);
markedBox.setChecked(!currentlyChecked);
checkedState.put(rowId, !currentlyChecked);
Log.d("checkedState", "checkedState(" + rowId + ") = " + checkedState.get(rowId));
}
}
}
A call of the swapCursor method of the SimpleCursorAdapter class will trigger a function which maps the column names from the String array provided to the constructor(the 4th parameter) to an array of integers representing the columns indexes. As you pass null in the constructor of MyAdapter for the String array representing the columns names from the cursor, this will throw a NullPointerException later when the swapCursor will try to make the mapping(the NullPointerException should appear in a method findColumns, which is the actual method that uses the column names String array).
The solution is to pass a valid String array, you may also want to do this for the int array representing the ids for the views in which to place the data:
String[] from = {ContactsContract.Contacts.DISPLAY_NAME};
int[] to = {R.id.contacts_row_family_name, R.id.contacts_row_check};
adapter = new MyAdapter(this, R.layout.contacts_select_row, null, from, to, 0);
I don't know what you are trying to do but your implementation of the getView method is not quite right:
You do the normal stuff for the getView method(creating layouts, searching views, binding data) and then you simply return the view from the superclass(?!?), you'll probably just see the default layout with nothing in it.
The way you wrote the getView method is not very efficient, you may want to look into view recycling and the view holder pattern.
cursor.getPosition() will not do what you want as you don't move the cursor to the correct position. By default cursors based adapters will do this for you in the getView method, but, as you overrode the method it's your job to move the cursor's position.
You should leave the getView method and use the two methods newView and bindView as they offer a better separation of the logic.
adapter = new MyAdapter(this, R.layout.contacts_select_row, null, null, null, 0);
and your MyAdapter class you are passing null cursor
public MyAdapter(Context context, int layout, Cursor c, String[] from,
int[] to, int flags) {
super(context, layout, c, from, to, flags);
this.context = context;
this.cursor = getCursor();
}

Categories

Resources