I have some activities that call a Service that uses a custom ContentProvider to insert/update/delete entries in a table. Now all these operations work but the activities do not receive any result from them. What I want now is to also implement the query operation but in this case I want the results to get back to the caller Activity. How do I do that?
The ContentProvider itself works as I was using it synchronously, so its code doesn't matter.
Here's the Service:
public class TaskService extends IntentService {
private static final String TAG = TaskService.class.getSimpleName();
//Intent actions
public static final String ACTION_INSERT = TAG + ".INSERT";
public static final String ACTION_UPDATE = TAG + ".UPDATE";
public static final String ACTION_DELETE = TAG + ".DELETE";
public static final String ACTION_QUERY = TAG + ".QUERY";
public static final String EXTRA_VALUES = TAG + ".ContentValues";
public static void queryTasks(Context context, ContentValues values) {
Intent intent = new Intent(context, TaskService.class);
intent.setAction(ACTION_QUERY);
intent.putExtra(EXTRA_VALUES, values);
context.startService(intent);
}
public static void insertNewTask(Context context, ContentValues values) {
Intent intent = new Intent(context, TaskService.class);
intent.setAction(ACTION_INSERT);
intent.putExtra(EXTRA_VALUES, values);
context.startService(intent);
}
public static void updateTask(Context context, Uri uri, ContentValues values) {
Intent intent = new Intent(context, TaskService.class);
intent.setAction(ACTION_UPDATE);
intent.setData(uri);
intent.putExtra(EXTRA_VALUES, values);
context.startService(intent);
}
public static void deleteTask(Context context, Uri uri) {
Intent intent = new Intent(context, TaskService.class);
intent.setAction(ACTION_DELETE);
intent.setData(uri);
context.startService(intent);
}
public TaskService() {
super(TAG);
}
#Override
protected void onHandleIntent(Intent intent) {
if (ACTION_INSERT.equals(intent.getAction())) {
ContentValues values = intent.getParcelableExtra(EXTRA_VALUES);
performInsert(values);
} else if (ACTION_UPDATE.equals(intent.getAction())) {
ContentValues values = intent.getParcelableExtra(EXTRA_VALUES);
performUpdate(intent.getData(), values);
} else if (ACTION_DELETE.equals(intent.getAction())) {
performDelete(intent.getData());
} else if (ACTION_QUERY.equals(intent.getAction())) {
performQuery(intent.getData());
}
}
private void performInsert(ContentValues values) {
if (getContentResolver().insert(DatabaseContract.CONTENT_URI, values) != null) {
Log.d(TAG, "Inserted new task");
} else {
Log.w(TAG, "Error inserting new task");
}
}
private void performQuery(Uri uri, ContentValues values) {
//TODO
}
private void performUpdate(Uri uri, ContentValues values) {
int count = getContentResolver().update(uri, values, null, null);
Log.d(TAG, "Updated " + count + " task items");
}
private void performDelete(Uri uri) {
int count = getContentResolver().delete(uri, null, null);
Log.d(TAG, "Deleted "+count+" tasks");
}
The query() method of course returns a Cursor. How do I send this Cursor back to the Activity?
Related
I try to Unit test my db in Android library, here's how I do it. Providers are definied in Manifest. I run it with RobolectricTestRunner
#RunWith(CustomRobolectricTestRunner.class)
public class FileDatabaseTest {
private ContentResolver contentResolver;
#Before
public void setUp() {
Robolectric.buildContentProvider(FileIndexContentProvider.class);
contentResolver = RuntimeEnvironment.application.getContentResolver();
FileDatabase fileDatabase = mock(FileDatabase.class);
Mockito.doAnswer(new Answer() {
public Object answer(InvocationOnMock invocation) {
return null;
}
}).when(fileDatabase).close();
}
public void insertFileIndex() {
ContentValues contentValues = new ContentValues();
contentValues.put(FileContract.FileIndexTable.FILE_PATH, "path");
contentValues.put(FileContract.FileIndexTable.FILENAME, "filename");
contentValues.put(FileContract.FileIndexTable.STATUS, FileIndexEntry.FileStatus.ACTIVE.toString());
contentValues.put(FileContract.FileIndexTable.CREATE_DATE, System.currentTimeMillis());
contentResolver.insert(FileContract.FileIndexTable.CONTENT_URI, contentValues);
}
#Test
public void testInsertFile() {
insertFileIndex();
Cursor cursor = contentResolver.query(FileContract.FileIndexTable.CONTENT_URI,
FileContract.FileIndexTable.PROJECTION, null, null, null, null);
assertNotNull(cursor);
assertEquals(cursor.getCount(), 1);
cursor.moveToFirst();
FileIndexEntry fileIndexEntry = new FileIndexEntry(cursor);
assertThat(fileIndexEntry.filename, equalTo("filename"));
}
}
Cursor that gets returned by query is null. This happens in all tests that work on db.
public class FileIndexContentProvider extends ContentProviderBase {
private static final UriMatcher URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH);
private static final int FILE_INDEX = 100;
private static final int FILE_INDEX_ID = 101;
static {
URI_MATCHER.addURI(FileContract.AUTHORITY, FileIndexTable.TABLE_NAME, FILE_INDEX);
URI_MATCHER.addURI(FileContract.AUTHORITY, FileIndexTable.TABLE_NAME + "/*", FILE_INDEX_ID);
}
/**
* Static method to obtain table name from a Uri.
*/
public static String tableForUri(Uri uri) {
final int match = URI_MATCHER.match(uri);
switch (match) {
case FILE_INDEX:
case FILE_INDEX_ID:
return FileIndexTable.TABLE_NAME;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
}
#Override
public boolean onCreate() {
databaseHelper = new FileDatabase(getContext());
return true;
}
#Override
public String getTableForUri(Uri uri) {
return tableForUri(uri);
}
#Override
public String getType(#NonNull Uri uri) {
final int match = URI_MATCHER.match(uri);
switch (match) {
case FILE_INDEX:
return FileIndexTable.CONTENT_TYPE;
case FILE_INDEX_ID:
return FileIndexTable.CONTENT_ITEM_TYPE;
default:
throw new UnsupportedOperationException("Unknown uri: " + uri);
}
}
}
Here is the ContentProvider code. It tested well in an app, but when I started moving it into library issues started.
public class SettingsActivity extends AppCompatActivity {
private Context context;
private DogDatabaseHelper dbHelper;
private ListView mListView;
private ArrayList<String> names = new ArrayList<String>();
private AdapterForNames namesAdapter;
#Override
public void onCreate(Bundle savedInstance){
super.onCreate(savedInstance);
setContentView(R.layout.settings);
mListView = (ListView)findViewById(R.id.listforall);
context = this;
namesAdapter = new AdapterForNames(this,names);
mListView.setAdapter(namesAdapter);
DogDatabaseHelper dbHelper = new DogDatabaseHelper(getApplicationContext());
SQLiteDatabase db = dbHelper.getWritableDatabase();
Cursor cursor = db.rawQuery("select name from dog",null);
if(cursor != null && cursor.moveToFirst()){
do{
names.add(cursor.getString(cursor.getColumnIndex("name")));
namesAdapter.notifyDataSetChanged();
}while (cursor.moveToNext());
}
mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
Intent intent = new Intent(SettingsActivity.this,SetupActivity.class);
intent.putExtra("name",names.get(position));
startActivity(intent);
}
});
}
public class AdapterForNames extends ArrayAdapter<String> {
private ArrayList<String> names;
AdapterForNames(Context context, ArrayList<String> names){
super(context,R.layout.settingsname,names);
this.names = names;
}
public void refresh(ArrayList<String> names){
this.names= names;
notifyDataSetChanged();
}
#Override
public View getView(int position, View convertView, ViewGroup parent){
LayoutInflater setLayout = LayoutInflater.from(getContext());
View customView = setLayout.inflate(R.layout.settingsname,parent,false);
String setItem = names.get(position);
TextView nameText = (TextView)customView.findViewById(R.id.settingsname);
nameText.setText(setItem);
return customView;
}
}
public class SetupActivity extends AppCompatActivity {
private Context context;
static String extra = "values";
ListView mListView;
private String name;
final String[] setItems = {"name","birthday","size","sex"};
#Override
public void onCreate(Bundle savedInstance){
super.onCreate(savedInstance);
setContentView(R.layout.setuplist);
mListView = (ListView)findViewById(R.id.listview);
context = this;
Intent intent =getIntent();
name = intent.getStringExtra("name");
setResult(RESULT_OK,intent);
showView();
}
private void showView(){
DogDatabaseHelper dbHelper= new DogDatabaseHelper(getApplicationContext());
SQLiteDatabase db = dbHelper.getWritableDatabase();
Cursor cursor = db.rawQuery("select * from dog where name = ?",new String[]{name});
//Cursor cursor = db.query("Dog",null,null,null,null,null,null,null);
if(cursor.moveToFirst()){
String name = cursor.getString(cursor.getColumnIndex("name"));
String birthday = cursor.getString(cursor.getColumnIndex("birthday"));
String size = cursor.getString(cursor.getColumnIndex("size"));
String sex = cursor.getString(cursor.getColumnIndex("sex"));
final String[] setValues = {name,birthday,size,sex};
ListAdapter listAdapter = new CustomAdapter(this,setItems,setValues);
mListView.setAdapter(listAdapter);
mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
String setupItemValue = setValues[position];
String setupItem = setItems[position];
Intent intent;
if(setupItem.equals("name")){
intent = new Intent(SetupActivity.this,ChangeName.class);
intent.putExtra(extra,setupItemValue);
startActivityForResult(intent,1);
} else if(setupItem.equals("birthday")){
intent = new Intent(SetupActivity.this,ChangeBirthday.class);
intent.putExtra(extra,setupItemValue);
startActivityForResult(intent,2);
}else if(setupItem.equals("size")){
intent = new Intent(SetupActivity.this,ChangeType.class);
intent.putExtra(extra,setupItemValue);
startActivityForResult(intent,3);
}else{
intent = new Intent(SetupActivity.this,ChangeSex.class);
intent.putExtra(extra,setupItemValue);
startActivityForResult(intent,4);
}
}
});
}
cursor.close();
}
private void updateView(){
DogDatabaseHelper dbHelper= new DogDatabaseHelper(getApplicationContext());
SQLiteDatabase db = dbHelper.getWritableDatabase();
Cursor cursor = db.query("Dog",null,null,null,null,null,null,null);
if(cursor.moveToFirst()){
String name = cursor.getString(cursor.getColumnIndex("name"));
String birthday = cursor.getString(cursor.getColumnIndex("birthday"));
String size = cursor.getString(cursor.getColumnIndex("size"));
String sex = cursor.getString(cursor.getColumnIndex("sex"));
final String[] setValues = {name,birthday,size,sex};
ListAdapter listAdapter = new CustomAdapter(this,setItems,setValues);
mListView.setAdapter(listAdapter);
mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
String setupItemValue = setValues[position];
String setupItem = setItems[position];
Intent intent;
if(setupItem.equals("name")){
intent = new Intent(SetupActivity.this,ChangeName.class);
intent.putExtra(extra,setupItemValue);
startActivityForResult(intent,1);
} else if(setupItem.equals("birthday")){
intent = new Intent(SetupActivity.this,ChangeBirthday.class);
intent.putExtra(extra,setupItemValue);
startActivityForResult(intent,2);
}else if(setupItem.equals("size")){
intent = new Intent(SetupActivity.this,ChangeType.class);
intent.putExtra(extra,setupItemValue);
startActivityForResult(intent,3);
}else{
intent = new Intent(SetupActivity.this,ChangeSex.class);
intent.putExtra(extra,setupItemValue);
startActivityForResult(intent,4);
}
}
});
}
cursor.close();
}
#Override
protected void onActivityResult(int requestCode,int resultCode,Intent data){
DogDatabaseHelper dbHelper= new DogDatabaseHelper(getApplicationContext());
SQLiteDatabase db = dbHelper.getWritableDatabase();
Cursor cursor = db.query("Dog",null,null,null,null,null,null,null);
switch (requestCode){
case 1:
if (resultCode == RESULT_OK){
ContentValues cv = new ContentValues();
cv.put("name",data.getStringExtra("return_name"));
db.update("dog",cv,"id=?",new String[]{"1"});
}
break;
case 2:
if(resultCode == RESULT_OK){
ContentValues cv = new ContentValues();
cv.put("birthday",data.getStringExtra("return_birthday"));
db.update("dog",cv,"id=?",new String[]{"1"});
}
break;
case 3:
if(resultCode == RESULT_OK){
ContentValues cv = new ContentValues();
cv.put("size",data.getStringExtra("return_type"));
db.update("dog",cv,"id=?",new String[]{"1"});
}
break;
case 4:
if(resultCode == RESULT_OK){
ContentValues cv = new ContentValues();
cv.put("sex",data.getStringExtra("return_sex"));
db.update("dog",cv,"id=?",new String[]{"1"});
}
break;
}
db.close();
updateView();
}
}
public class DogDatabaseHelper extends SQLiteOpenHelper {
public static final String CREATE_DOG = "create table dog ("
+ "id integer primary key autoincrement,"
+ "name text,"
+ "birthday text,"
+ "size text,"
+ "sex text,"
+ "count integer)";
private Context context;
public DogDatabaseHelper(Context context){
super(context,"Dog.db",null,1);
this.context = context;
}
#Override
public void onCreate(SQLiteDatabase db){
db.execSQL(CREATE_DOG);
}
#Override
public void onUpgrade(SQLiteDatabase db,int oldVersion,int newVersion){
db.execSQL("drop table if exists Dog");
onCreate(db);
}
public ArrayList<String> getAllNames(){
SQLiteDatabase db = this.getReadableDatabase();
ArrayList<String> names = new ArrayList<String>();
Cursor cursor = db.query("Dog",null,null,null,null,null,null);
if(cursor.moveToFirst()){
do{
String name = cursor.getString(cursor.getColumnIndex("name"));
names.add(name);
}while (cursor.moveToNext());
}
cursor.close();
return names;
}
}
I can get data from database and I'm able to update data after clicking the name in the ListView, but when I return to this Activity, I don't know how to update the ListView, cause notifyDataSetChanged() didn't work.
Have no idea what went wrong, Anyone can help?
Use startActivityForResult() instead of startActivity() to start your SetupActivity:
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
Intent intent = new Intent(SettingsActivity.this, SetupActivity.class);
intent.putExtra("name", names.get(position));
startActivityForResult(intent, REQUEST_SETUP);
// REQUEST_SETUP is just a private int constant in SettingsActivity
}
Override onActivityResult() in SettingsActivity:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if(resultCode == RESULT_OK) {
switch (requestCode) {
case REQUEST_SETUP:
dataChanged();
break;
// other request codes (if any)
}
}
}
The dataChanged() method:
private void dataChanged() {
// fetch the new data from the DB into your ArrayList
names.clear();
names.addAll(dbHelper.getAllNames());
// update the ListView with the new data
namesAdapter.notifyDataSetChanged();
}
The getAllNames() method in DogDatabaseHelper:
public ArrayList<String> getAllNames() {
SQLiteDatabase db = this.getReadableDatabase();
ArrayList<String> names = new ArrayList<>();
Cursor cursor = db.query(TABLE_DOG, new String[]{COLUMN_NAME},
null, null, null, null, null, null);
if (cursor.moveToFirst()) {
do {
String name = cursor.getString(cursor.getColumnIndex(COLUMN_NAME)));
names.add(name);
} while (cursor.moveToNext());
}
cursor.close();
return names;
}
And finally, when you finished your stuff in SetupActivity and inserted/updated the data in the DB, set the result to RESULT_OK and return to SettingsActivity by calling finish():
setResult(RESULT_OK);
finish();
NOTE: for better performance, you could pass the ID(s) of the inserted/updated record(s) from SetupActivity to SettingsActivity in the Intent, so instead of querying all rows by calling getAllNames(), you could just fetch the modified record(s).
I think the easiest and quicker way for you would be to put all this code:
DogDatabaseHelper dbHelper = new DogDatabaseHelper(getApplicationContext());
SQLiteDatabase db = dbHelper.getWritableDatabase();
Cursor cursor = db.rawQuery("select name from dog",null);
// Edit: to reload all data you must first clear the list
names.clear();
if (cursor != null && cursor.moveToFirst()) {
do {
names.add(cursor.getString(cursor.getColumnIndex("name")));
} while (cursor.moveToNext());
// Note: move this out of the bucle to avoid calling it in every iteration
namesAdapter.notifyDataSetChanged();
}
in your MainActivity's onResume() method, so every time you come back you refresh the data.
EDIT: since reloading the data each time the activity calls onResume, I would suggest you also use a flag for the MainActivity to know if there have been changes. Something like:
#Override
protected void onResume() {
super.onResume();
if (thereWereChanges) {
realoadDataSet();
}
}
I have a DatabaseConnector class where I want to check if the database is empty and then show an alert and a click on it will close the activity.
This is my DatabaseConnector class
public class DatabaseConnector {
// Declare Variables
private static final String DB_NAME = "MyNotes";
private static final String TABLE_NAME = "tablenotes";
private static final String TITLE = "title";
private static final String ID = "_id";
private static final String NOTE = "note";
private static final int DATABASE_VERSION = 2;
private SQLiteDatabase database;
private DatabaseHelper dbOpenHelper;
public static final String MAINCAT = "maincat";
public static final String SUBCAT = "subcat";
public DatabaseConnector(Context context) {
dbOpenHelper = new DatabaseHelper(context, DB_NAME, null,
DATABASE_VERSION);
}
// Open Database function
public void open() throws SQLException {
// Allow database to be in writable mode
database = dbOpenHelper.getWritableDatabase();
}
// Close Database function
public void close() {
if (database != null)
database.close();
}
// Create Database function
public void InsertNote(String title, String note , String maincat, String subcat) {
ContentValues newCon = new ContentValues();
newCon.put(TITLE, title);
newCon.put(NOTE, note);
newCon.put(MAINCAT, maincat);
newCon.put(SUBCAT, subcat);
open();
database.insert(TABLE_NAME, null, newCon);
close();
}
// Update Database function
public void UpdateNote(long id, String title, String note) {
ContentValues editCon = new ContentValues();
editCon.put(TITLE, title);
editCon.put(NOTE, note);
open();
database.update(TABLE_NAME, editCon, ID + "=" + id, null);
close();
}
// Delete Database function
public void DeleteNote(long id) {
open();
database.delete(TABLE_NAME, ID + "=" + id, null);
close();
}
// List all data function
//String selection = dbOpenHelper.MAINCAT + " = 'quiz'"
// +" AND " + dbOpenHelper.SUBCAT + " = 'test'";
// public Cursor ListAllNotes() {
// return database.query(TABLE_NAME, new String[] { ID, TITLE }, null,
// null, null, null, TITLE);
// }
public Cursor ListAllNotes(String selection) {
return database.query(TABLE_NAME, new String[] { ID, TITLE }, selection,
null, null, null, TITLE);
}
// Capture single data by ID
public Cursor GetOneNote(long id) {
return database.query(TABLE_NAME, null, ID + "=" + id, null, null,
null, null);
}
And here is the ListActivity wherein I want to close the Activity with an alert
public class dbMainactivty extends ListActivity {
// Declare Variables
public static final String ROW_ID = "row_id";
private static final String TITLE = "title";
private ListView noteListView;
private CursorAdapter noteAdapter;
#SuppressWarnings("deprecation")
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Tracker t = ((AnalyticsSampleApp)this.getApplication()).getTracker(TrackerName.APP_TRACKER);
t.setScreenName("dbMainactivty");
t.send(new HitBuilders.AppViewBuilder().build());
// Locate ListView
noteListView = getListView();
// setContentView(R.layout.list_note);
//noteListView = (ListView) findViewById(R.id.listview);
// Prepare ListView Item Click Listener
noteListView.setOnItemClickListener(viewNoteListener);
// Map all the titles into the ViewTitleNotes TextView
String[] from = new String[] { TITLE };
int[] to = new int[] { R.id.ViewTitleNotes };
// Create a SimpleCursorAdapter
noteAdapter = new SimpleCursorAdapter(dbMainactivty.this,
R.layout.list_note, null, from, to);
// Set the Adapter into SimpleCursorAdapter
setListAdapter(noteAdapter);
}
// Capture ListView item click
OnItemClickListener viewNoteListener = new OnItemClickListener() {
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
long arg3) {
// Open ViewNote activity
Intent viewnote = new Intent(dbMainactivty.this, ViewNote.class);
// Pass the ROW_ID to ViewNote activity
viewnote.putExtra(ROW_ID, arg3);
startActivity(viewnote);
}
};
#Override
protected void onResume() {
super.onResume();
// Execute GetNotes Asynctask on return to MainActivity
new GetNotes().execute((Object[]) null);
GoogleAnalytics.getInstance(dbMainactivty.this).reportActivityStart(this);
}
#Override
protected void onStop() {
Cursor cursor = noteAdapter.getCursor();
// Deactivates the Cursor
if (cursor != null)
cursor.deactivate();
noteAdapter.changeCursor(null);
super.onStop();
GoogleAnalytics.getInstance(dbMainactivty.this).reportActivityStop(this);
}
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
Intent i = null;
switch (item.getItemId()) {
case R.id.action_rate:
String webpage = "http://developer.android.com/index.html";
Intent intent2 = new Intent(Intent.ACTION_VIEW, Uri.parse(webpage));
startActivity(intent2);
overridePendingTransition(R.anim.slide_in, R.anim.slide_out);
case R.id.action_share:
i = new Intent();
i.setAction(Intent.ACTION_SEND);
//i.putExtra(Intent.EXTRA_TEXT, feed.getItem(pos).getTitle().toString()+ " to know the answer download http://developer.android.com/index.html");
i.setType("text/plain");
startActivity(i);
return true;
}
return super.onOptionsItemSelected(item);
};
// GetNotes AsyncTask
private class GetNotes extends AsyncTask<Object, Object, Cursor> {
DatabaseConnector dbConnector = new DatabaseConnector(dbMainactivty.this);
#Override
protected Cursor doInBackground(Object... params) {
// Open the database
dbConnector.open();
return dbConnector.ListAllNotes("maincat LIKE 'quiz' AND subcat LIKE 'test'");
}
#Override
protected void onPostExecute(Cursor result) {
noteAdapter.changeCursor(result);
// Close Database
dbConnector.close();
}
}
#Override
protected void onStart() {
super.onStart();
ConnectivityManager conMgr = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
if (conMgr.getActiveNetworkInfo() == null) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage(
"Please check your Internet Connection.")
.setTitle("tilte")
.setCancelable(false)
.setPositiveButton("Exit",
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog,
int id) {
//loader.cancel(true);
finish();
}
});
AlertDialog alert = builder.create();
alert.show();
} else {
Cursor cursor = noteAdapter.getCursor();
if(cursor != null && cursor.getCount() > 0){
cursor.moveToFirst();
//do your action
//Fetch your data
GoogleAnalytics.getInstance(dbMainactivty.this).reportActivityStart(this);
Toast.makeText(getBaseContext(), "Yipeee!", Toast.LENGTH_SHORT).show();
}
else {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage(
"oops nothing pinned yet! ....")
.setTitle("title")
.setCancelable(false)
.setPositiveButton("Exit",
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog,
int id) {
//loader.cancel(true);
finish();
}
});
AlertDialog alert = builder.create();
alert.show();
Toast.makeText(getBaseContext(), "No records yet!", Toast.LENGTH_SHORT).show();
}
}
}
}
I am trying to check
cursor != null && cursor.getCount()>0 and if it turns false then show the alert that
nothing has been pinned yet
Should show up however even though if the cursor returns data the alert still shows up.
First step, take a look at the lifecycle of your activity: http://www.android-app-market.com/wp-content/uploads/2012/03/Android-Activity-Lifecycle.png
As you can see onResume() is called after onStart() which means that checking the cursor on the onStart() can not work.
Secondly you are starting an AsyncTask (GetNotes) on the onResume() method which means you are running a parallel thread at this point and can't check for the result after calling new GetNotes().execute((Object[]) null);
Your problem is you need to check the emptiness of your cursor (cursor != null && cursor.getCount()>0) AFTER the data is loader which mean after the AsyncTask has completed. In other words, move the check for emptiness on your cursor inside the onPostExecute(Cursor result) method.
In my Android app,i am retreiving phone contacts through cursor. Then i want to add all these contacts in database as follows:
public class SettingsActivity extends Activity {
ToggleButton tb_hide;
ToggleButton tb_unhide;
TextView tv_add_contacts;
TextView tv_restore_contacts;
DbManager manager;
Context context;
String[] privateContacts;
Uri queryUri;
String selectIds = "";
String ContactId[];
String ContactNames[];
String ContactNumbers[];
public static String[] wholContactData;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.settings_activity);
try{
context = this;
findView();
queryUri = ContactsContract.Contacts.CONTENT_URI;
//String selected_data = ContactsContract.Contacts.DISPLAY_NAME + " IS NOT NULL";
Cursor Cursor = getContentResolver().query
(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null,null,null, null);
privateContacts=showEvents(Cursor);
wholContactData=new String[privateContacts.length];
tv_add_contacts.setOnClickListener(new OnClickListener(){
#Override
public void onClick(View v) {
addcontacts();
}
});
tv_restore_contacts.setOnClickListener(new OnClickListener(){
#Override
public void onClick(View v) {
for(int i=0;i<privateContacts.length;i++){
selectIds = selectIds + " | " + privateContacts[i];
wholContactData[i]=privateContacts[i];
}
try{
addAllContacts(wholContactData);
}
catch(Exception ex)
{
Log.e("ERROR in adding all contacts", ex.toString());
}
Toast.makeText(getApplicationContext(),""+selectIds, 3000).show();
}});
}
catch(Exception ex){
Log.e("Add all contacts ERROR", ex.toString());
}
}
private void addAllContacts(final String[] selectedItems) {
try{
manager.open();
manager.Insert_phone_contact(selectedItems);
manager.close();
}
catch(Exception ex)
{
Log.e("ERROR", ex.toString());
}
}
protected String[] showEvents(Cursor cursor) {
ContactId= new String[cursor.getCount()];
ContactNames = new String[cursor.getCount()];
ContactNumbers = new String[cursor.getCount()];
int i=0;
while (cursor.moveToNext()) {
ContactId[i] = i+"";
ContactNames[i] = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
ContactNumbers[i] = Util.getContactNumber(ContactNames[i], context);
i++;
}
return ContactNames;
}
private void findView() {
TextView tv_hide = (TextView)findViewById(R.id.tv_hide);
TextView tv_hide_desc = (TextView)findViewById(R.id.tv_hide_desc);
tv_add_contacts = (TextView)findViewById(R.id.tv_add_contacts);
TextView tv_add_contacts_desc = (TextView)findViewById(R.id.tv_add_contacts_desc);
tv_restore_contacts = (TextView)findViewById(R.id.Tv_restore_contacts);
TextView tv_restore_contacts_desc = (TextView)findViewById(R.id.tv_restore_contacts_desc);
tb_hide = (ToggleButton)findViewById(R.id.tb_hide);
tb_hide.setOnClickListener(new OnClickListener(){
#Override
public void onClick(View v) {
HideUnhideIcon();
}});
}
private void HideUnhideIcon() {
if(tb_hide.isChecked()){
PackageManager pm = getPackageManager();
ComponentName com_name = new ComponentName("com.android.discrete.main",
"com.android.discrete.main.SplashScreen");
pm.setComponentEnabledSetting(com_name,
PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP);
Toast.makeText(getApplicationContext(), "Your app is hidden now, Dial provided security code to get into discrete app.", 3000).show();
}
else if(tb_hide.isChecked()==false){
PackageManager pm = getPackageManager();
ComponentName com_name = new ComponentName("com.android.discrete.main",
"com.android.discrete.main.SplashScreen");
pm.setComponentEnabledSetting(com_name,
PackageManager.COMPONENT_ENABLED_STATE_ENABLED
,
PackageManager.DONT_KILL_APP );
}
}
private void addcontacts() {
final ProgressDialog myPd_ring=ProgressDialog.show(this, "Phone Contacts", "Loading please wait..", true);
myPd_ring.setCancelable(true);
new Thread(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
try
{
movetoPrivateContacts();
}catch(Exception e){}
myPd_ring.dismiss();
}
}).start();
}
private void moveToLogActivity() {
Intent i = new Intent(this, LogActivity.class);
startActivity(i);
finish();
}
private void movetoPrivateContacts() {
Intent intent = new Intent(this,privateContacts.class);
startActivity(intent);
}
#Override
public void onBackPressed() {
Intent i = new Intent(getApplicationContext(),MainActivity.class);
startActivity(i);
}
}
Database code is as follows:
public void Insert_phone_contact(String [] contact){
try{
SQLiteDatabase DB = this.getWritableDatabase();
ContentValues cv = new ContentValues();
for(int i=0;i<contact.length;i++){
// put all values in ContentValues
if (contact[i] !=null){
cv.put(CONTACT_NAME, ""+contact[i]);
DB.insert(TABLE_CONTACTS, null, cv);
}// insert in db
}
DB.close(); // call close
}
catch(Exception ex){
Log.e("Error in phone contact insertion", ex.toString());
}
}
i want to add all contacts to database when i click "tv_restore_contacts" .But i am getting NullPointerException. I don't know where i am wrong?
logcat Error stack is java.lang.NullPointerException.
Use the following code to grab the contacts & return them to a list datatype to save them whole list in a db or open a DB connection inside the method and do sql insert statements on each contact object you wish to store. N/B The Contacts API is deprecated be sure to use ContactsContract Api.
Private void getDetails(){
Uri uri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;
ContentResolver cr = getContentResolver();
Cursor cur = cr.query(ContactsContract.Contacts.CONTENT_URI,null, null, null, null);
String[] projection = new String[] {ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME,
ContactsContract.CommonDataKinds.Phone.NUMBER };
Cursor names = getContentResolver().query(uri, projection, null, null, null);
int indexName = names.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME);
int indexNumber = names.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER);
names.moveToFirst();
do {
String name = names.getString(indexName);
Log.e("Name new:", name);
String number = names.getString(indexNumber);
Log.e("Number new:","::"+number);
} while (names.moveToNext());
}
I am trying to track phone call states and log. I need phone numbers, name(if it is a saved contact) and time of the call and duration. The problem is that getContentResolver() method cannot be called, its commented in code.
public class PhoneStateBroadcastReciever extends BroadcastReceiver {
Context m_context;
String m_number = null;
String m_startTime = null;
String m_endTime = null;
SharedPreferences m_sharedPrefs;
Editor editor;
static String PREFS_NUMBER;
static String PREFS_START_TIME;
static String PREFS_END_TIME;
#Override
public void onReceive(Context context, Intent intent) {
m_sharedPrefs = m_context.getSharedPreferences("MyPrefs", 0);
editor = m_sharedPrefs.edit();
Bundle bundle = intent.getExtras();
if (bundle == null)
return;
String state = bundle.getString(TelephonyManager.EXTRA_STATE);
if ((state != null) &&
(state.equalsIgnoreCase(TelephonyManager.EXTRA_STATE_RINGING))) {
Log.i("TAG", "incoming call");
Uri contactUri = intent.getData();
String[] projection = { Phone.DISPLAY_NAME };
//i cannot use getContentResolver()
Cursor cursor = getContentResolver()..query(contactUri, projection, null,
null, null);
int columnName = cursor.getColumnIndex(Phone.DISPLAY_NAME);
String contactName = cursor.getString(columnName);
m_number = bundle.getString(TelephonyManager.EXTRA_INCOMING_NUMBER);
editor.putString(PREFS_NUMBER, m_number);
editor.commit();
} else if(state == null) {
Log.i("TAG", "outgoing call");
Uri contactUri = intent.getData();
String[] projection = { Phone.DISPLAY_NAME };
//i cannot use getContentResolver()
Cursor cursor = getContentResolver()..query(contactUri, projection, null,
null, null);
int columnName = cursor.getColumnIndex(Phone.DISPLAY_NAME);
String contactName = cursor.getString(columnName);
m_number = bundle.getString(TelephonyManager.EXTRA_INCOMING_NUMBER);
editor.putString(PREFS_NUMBER, m_number);
editor.commit();
} else if(state.equalsIgnoreCase(TelephonyManager.EXTRA_STATE_OFFHOOK)) {
Log.i("TAG", "off hook");
Time dtstart = new Time(Time.getCurrentTimezone());
dtstart.setToNow();
m_startTime = dtstart.format("%k:%M:%S");
editor.putString(PREFS_START_TIME, m_startTime);
editor.commit();
} else if(state.equalsIgnoreCase(TelephonyManager.EXTRA_STATE_IDLE)) {
Log.i("TAG", "on idle");
Time dtend = new Time(Time.getCurrentTimezone());
dtend.setToNow();
m_endTime = dtend.format("%k:%M:%S");
editor.putString(PREFS_END_TIME, m_endTime);
editor.commit();
}
}
this is the service class:
public class TrackerService extends Service {
PhoneStateBroadcastReciever receiver;
#Override
public void onCreate() {
receiver = new PhoneStateBroadcastReciever();
IntentFilter filter = new IntentFilter();
filter.addAction(android.telephony.TelephonyManager.ACTION_PHONE_STATE_CHANGED);
registerReceiver(receiver, filter);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(this, "starting service", Toast.LENGTH_SHORT).show();
return Service.START_NOT_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
#Override
public void onDestroy() {
unregisterReceiver(receiver);
Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show();
}
}
Use the Context to invoke the contentResolver(). Something like that:
context.getContentResolver()....