How to update ListView from AsyncTask? - android

I am loading images by using AsyncTask and for updating ListView I am using notifyDataSetChanged() method.
But notifyDataSetChanged() doesn't change anything in the ListView onProgressUpdate().
I don't want to use cursor.requery because it is deprecated method.
Why notifyDataSetChanged() is not working for me?
public class News extends BasicActivity implements OnItemClickListener{
private SQLiteDatabase db = null;
private ListView lvNews;
private TaskImgSm taskImgSm = null;
private NewsListAdapter adapter;
private Cursor cur;
boolean pause = false;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.news);
db = SQLiteDatabase.openDatabase(((MyApp) getApplication()).getDbPath(), null, SQLiteDatabase.OPEN_READWRITE);
lvNews = (ListView) findViewById(R.id.list_news);
lvNews.setOnItemClickListener(this);
listFilling();
if (taskImgSm != null && taskImgSm.getStatus() != AsyncTask.Status.FINISHED) taskImgSm.cancel(true);
taskImgSm = new TaskImgSm();
taskImgSm.execute();
}
private void listFilling() {
cur = db.query("news", new String[] { "_id", "id_news", "title", "date", "img_url", "img_sm" }, null, null, null, null, null);
startManagingCursor(cur);
adapter = new NewsListAdapter(this, cur, db);
lvNews.setAdapter(adapter);
adapter.notifyDataSetChanged();
}
class TaskImgSm extends AsyncTask<Void, String, Void> {
Cursor curs;
#Override
protected void onPreExecute() {
super.onPreExecute();
curs = db.query("news", new String[] { "_id", "id_news", "img_url", "img_sm" }, null, null, null, null, null);
startManagingCursor(curs);
}
#Override
protected Void doInBackground(Void... unused) {
curs.moveToFirst();
while (curs.isAfterLast() == false) {
if (curs.getBlob(curs.getColumnIndex("img_sm")) == null) {
String imgUrl = curs.getString(curs.getColumnIndex("img_url"));
String idNews = curs.getString(curs.getColumnIndex("id_news"));
updateImg(imgUrl, idNews, "img_sm");
publishProgress();
}
curs.moveToNext();
}
return (null);
}
private void updateImg(String img_URL, String whereId, String imgColumn) {
try {
DefaultHttpClient mHttpClient = new DefaultHttpClient();
HttpGet mHttpGet = new HttpGet();
mHttpGet.setURI(new URI(img_URL));
HttpResponse mHttpResponse = mHttpClient.execute(mHttpGet);
if (mHttpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
HttpEntity entity = mHttpResponse.getEntity();
if (entity != null) {
// insert to database
ContentValues values = new ContentValues();
values.put(imgColumn, EntityUtils.toByteArray(entity));
db.update("news", values, "id_news=" + whereId, null);
}
}
} catch (URISyntaxException e) {e.printStackTrace();
} catch (ClientProtocolException e) {e.printStackTrace();
} catch (IOException e) {e.printStackTrace();}
}
#Override
protected void onProgressUpdate(String... item) {
if (pause == false) {
adapter.notifyDataSetChanged();
}
}
#Override
protected void onPostExecute(Void unused) {}
}
#Override
protected void onPause() {
pause = true;
super.onPause();
}
#Override
protected void onResume() {
pause = false;
adapter.notifyDataSetChanged();
super.onResume();
}
#Override
protected void onDestroy() {
if (taskImgSm != null && taskImgSm.getStatus() != AsyncTask.Status.FINISHED) taskImgSm.cancel(true);
super.onDestroy();
}
}

The reason it's not working is because notifyDataSetChanged() only tells the ListView that the data in the adapter has changed. Since that data hasn't changed (because you haven't queried the database again), then the ListView won't show any updates. You need to execute the query again and update the data in the adapter, then call notifyDatasetChanged().

Why don't use a ContentProvider.
With a ContentProvider you can update your table with the notifyChange(uri) method
Tutorial for that here http://thinkandroid.wordpress.com/2010/01/13/writing-your-own-contentprovider/

I think you may want to update the ImageView in a ListView in the onPostExecute() method. This is how I accomplished something similar to what you are doing : Multithreading For Performance

Related

onStartLoading gets called multiple times

I'm having an issue with Android Loaders.
I have an activity populated from internet data, and I have a bookmarks option to store and load them locally.
I'm implementing a recyclerView displaying the items.
When I change the sorting criteria the adapter gets cleared and repopulated with new data, and when I choose to see the bookmarked items a local query is started to the ContentProvider.
Now, I'm having issues with the bookmarked data, since I get multiple copies of the same item in my adapter.
I've done some logging and I noted that the loader is called multiple times when loading locally (adding the same items each time), but I can't see why.
Note that this occurs also when I get back to the activity, but does not occur when I start the app with the bookmarks preference.
If I start from bookmarks, select a bookmark and go back, multiple calls are done, too.
Can anyone help me? Here's the code:
In MainActivity this method is called at the end of onCreate
private void loadPosters() {
Log.d(TAG,"Loading posters");
if (mPagesLoaded < MAX_PAGES) {
Bundle args = new Bundle();
args.putInt("page",mPagesLoaded+1);
getSupportLoaderManager().restartLoader(LOADER_ID,args,this);
}
}
My loader code:
public Loader<ArrayList<Movie>> onCreateLoader(int id, final Bundle args) {
return new AsyncTaskLoader<ArrayList<Movie>>(this) {
ArrayList<Movie> mData;
#Override
protected void onStartLoading() {
Log.d(TAG,"Start Loading");
super.onStartLoading();
if (mData!=null){
deliverResult(mData);
}else{
if (mPagesLoaded == 0) {
mProgressBar.setVisibility(View.VISIBLE);
}
mErrorTextView.setVisibility(View.INVISIBLE);
forceLoad();
}
}
#Override
public ArrayList<Movie> loadInBackground() {
Log.d(TAG,"Load in background");
if (args.size() == 0) {
return null;
}
int page = args.getInt("page");
NetworkUtils networker = new NetworkUtils(getApplicationContext());
String criterion = getSharedPreferences(getString(R.string.movie_preferences), Context.MODE_PRIVATE).getString("sorting", "popular");
if (!(criterion.equals(getString(R.string.pref_bookmarked)))) {
URL request = networker.buildMoviesUrl(page, criterion);
try {
String JSONResponse = networker.getResponseFromHttpUrl(request);
ArrayList<Movie> res = fetchMoviesFromJson(JSONResponse);
mPagesLoaded++;
return res;
} catch (IOException | JSONException e) {
e.printStackTrace();
}
return null;
}
else{
Log.d(TAG,"Local Loading");
Cursor cursor = getContentResolver().query(MovieContract.MovieEntry.CONTENT_URI,null,null,null,null);
if (cursor!=null){
Log.d(TAG,"Cursor is not null");
ArrayList<Movie> res = fetchMoviesFromCursor(cursor);
cursor.close();
return res;
}
return null;
}
}
#Override
public void deliverResult(ArrayList<Movie> data) {
mData = data;
mProgressBar.setVisibility(View.INVISIBLE);
super.deliverResult(data);
}
};
}
My onLoadFinished callback:
#Override
public void onLoadFinished(Loader<ArrayList<Movie>> loader, ArrayList<Movie> movies) {
Log.d(TAG,"Load finished");
mProgressBar.setVisibility(View.INVISIBLE);
if (movies != null) {
mPostersAdapter.addMovies(movies);
Log.d(TAG,mPostersAdapter.getItemCount() + " items loaded");
showPosters();
} else {
showErrorMessage();
}
}
And my SharedPreferences code:
private void initSharedPreferences() {
mSharedPrefs = getApplicationContext().getSharedPreferences("movie_preferences", MODE_PRIVATE);
mOnSharedPreferenceChangeListener = new SharedPreferences.OnSharedPreferenceChangeListener() {
#Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
Log.d(TAG, "Shared preferences for " + key + "changed. Pref: " + sharedPreferences.getString(key, null));
mPagesLoaded = 0;
mPostersAdapter.clear();
loadPosters();
}
};
mSharedPrefs.registerOnSharedPreferenceChangeListener(mOnSharedPreferenceChangeListener);
}
I had to call destoryLoader() on loader Manager, to solve this. Not sure if this is the right way..

How to know that contact is deleted/updated/added and which contact has been newly added

I am using a content observer to know that there is a change made to contact phonebook of the device but I am not getting the exact task done like whether the contact has been added, deleted or updated and what is the value of the modified contact.
// Service running in background which always run and check to know that content has been changed
public class ContactChange extends Service {
ContactObserver observer;
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
observer = new ContactObserver(new Handler(),getApplicationContext());
// TODO Auto-generated method stub
getContentResolver().registerContentObserver(ContactsContract.Contacts.CONTENT_URI, false, observer);
super.onCreate();
}
#Override
public void onDestroy() {
super.onDestroy();
getContentResolver().unregisterContentObserver(observer);
}
}
//Content observer where we get to know that changes has made to the contact phonebook
public class ContactObserver extends ContentObserver {
private Context mContext;
DataBaseCurdOperation dataBaseCurdOperation;
ApiInterface apiInterface;
MyPrefs myPrefs;
ArrayList<InviteList> inviteArrayList;
public ContactObserver(Handler handler, Context context) {
super(handler);
this.mContext = context;
dataBaseCurdOperation = new DataBaseCurdOperation(mContext);
myPrefs = new MyPrefs(mContext);
apiInterface = ServiceGenerator.createService(ApiInterface.class, Config.BASE_URL_1);
inviteArrayList = new ArrayList<InviteList>();
}
#Override
public void onChange(boolean selfChange) {
this.onChange(selfChange, null);
}
#Override
public void onChange(boolean selfChange, Uri uri) {
Logger.LogError("URI", uri.toString());
boolean hasContactPermission = (ContextCompat.checkSelfPermission(mContext,
android.Manifest.permission.READ_CONTACTS) == PackageManager.PERMISSION_GRANTED);
if (hasContactPermission) {
SavingContactsActivity savingContactsActivity = new SavingContactsActivity(mContext);
savingContactsActivity.execute();
new InviteApiCall().execute();
}
}
Taking this approach and it is giving the contact whether it is added or updated not got the solution for deleted but surely will post the answer of deleted soon....
And I worked on the database after that
public class ContactSyncObserver extends ContentObserver {
Context mContext;
DataBaseCurdOperation dataBaseCurdOperation;
MyPrefs myPrefs;
public ContactSyncObserver(Handler handler, Context mContext) {
super(handler);
this.mContext = mContext;
dataBaseCurdOperation = new DataBaseCurdOperation(mContext);
myPrefs = new MyPrefs(mContext);
}
#Override
public boolean deliverSelfNotifications() {
return true;
}
#Override
public void onChange(boolean selfChange, Uri uri) {
super.onChange(selfChange, uri);
boolean hasContactPermission = (ContextCompat.checkSelfPermission(mContext,
Manifest.permission.READ_CONTACTS) == PackageManager.PERMISSION_GRANTED);
if (hasContactPermission) {
try {
Cursor cursor = mContext.getContentResolver().query(ContactsContract.Contacts.CONTENT_URI, null, null, null, ContactsContract.Contacts.CONTACT_LAST_UPDATED_TIMESTAMP + " Desc");
if (cursor.moveToNext()) {
String id = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts._ID));
Logger.LogError("contactId", myPrefs.getContactId());
String name = cursor.getString(
cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
String rawContactId = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.NAME_RAW_CONTACT_ID));
String phoneNumber = null;
String hasPhoneNumber = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER));
if (Integer.parseInt(hasPhoneNumber) > 0) {
Cursor phones = mContext.getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = " + id, null, null);
while (phones.moveToNext()) {
phoneNumber = phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
Log.e("Number", phoneNumber);
}
phones.close();
}
if (phoneNumber != null) {
phoneNumber = phoneNumber.replaceAll(" ", "");
}
if (dataBaseCurdOperation.checkIsContactIdExist(id)) {
if (!myPrefs.getContactId().equals(id)) {
dataBaseCurdOperation.updateNewNumber(id, phoneNumber, name, "updated");
UtilHandler.TriggerRefresh();
} else {
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
myPrefs.setContactId("0");
}
}, 3000);
}
} else {
dataBaseCurdOperation.insertServerContact(id, name, phoneNumber, "inserted", "newNumber", "newName");
UtilHandler.TriggerRefresh(); // triggering my sync adapter here...
}
myPrefs.setContactId(id);
}
} catch (Exception e) {
Logger.LogError("Contact Exception", "occured");
}
}
}
}

Can't Find nullpointer please assist

This is the class i gain a null pointer from it points to line 65.
public class searchlist extends ListActivity
{
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
new loadSomeStuff().execute();
}
public class loadSomeStuff extends AsyncTask<String, Integer, String[]>
{
ProgressDialog dialog;
protected void onPreExecute()
{
dialog = new ProgressDialog(searchlist.this);
dialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
dialog.setMax(100);
dialog.show();
}
#Override
protected String[] doInBackground(String... arg0) {
// TODO Auto-generated method stub
for(int i =0; i<20; i++)
{
publishProgress(5);
try
{
Thread.sleep(80);
} catch(InterruptedException e)
{
e.printStackTrace();
}
}
dialog.dismiss();
int loops = search_page.returnlooped();
int[] teacup = search_page.returnNumArray();
sqlStuff searching = new sqlStuff(searchlist.this);
String[] IDSysNames = searching.getIDSysName();
searching.close();
String[] resultList = new String[loops];
for(int i=0; i < loops; i++ )
{
if(IDSysNames[teacup[i]] != null)
{
resultList[i].equals(IDSysNames[teacup[i]]); //Line 65
}
}
setListAdapter(new ArrayAdapter<String>(searchlist.this, android.R.layout.simple_list_item_1, resultList));
return null;
}
protected void onProgressUpdate(Integer...progress)
{
dialog.incrementProgressBy(progress[0]);
}
}
This is the getIDSysname class used by the class above.
public String[] getIDSysName()
{
String[] result = new String[0];
try
{
String[] columns = new String[] {KEY_SYSNAME};
Cursor c = ChemPal.query(DATABASE_TABLE, columns, null, null, null, null, null);
Log.d("SqlDStuff", "Cursor count: "+c.getCount());
int iSysName = c.getColumnIndex(KEY_SYSNAME);
int i = 0;
for (c.moveToFirst(); !c.isAfterLast(); c.moveToNext()){
i++;
}
result = new String[i];
i = 0;
for (c.moveToFirst(); !c.isAfterLast(); c.moveToNext()){
result[i] = c.getString(iSysName);
i++;
}
}
catch(Exception e)
{
}
return result;
}
If anything else is needed please ask in the comments because this is frustrating me at the moment. Thank you
You've allocated an array of strings:
String[] resultList = new String[loops];
for (int i=0; i < loops; i++ ) {
if (IDSysNames[teacup[i]] != null) {
resultList[i].equals(IDSysNames[teacup[i]]); //Line 65
There aren't any strings in it upon which to call equals.
dialog.dismiss();
you can not call dismiss on doInBackground(). Every method pertinent to the UI Thread has to be called on the UI Thread.
try with:
runOnUiThread(new Runnable() {
public void run() {
dialog.dismiss();
}
});
setListAdapter(new ArrayAdapter(searchlist.this, android.R.layout.simple_list_item_1, resultList));
I had to move this method to the onCreate(); and i had to retrun the resultList value via a method called onPostExecute.
Turns out the log cat was making up the null pointer don't know why . Thanks guys but i got it now.

SimpleCursorAdapter ListView created by messagehandler

I've read through all posts I can find about simplecursoradapter and listview but I still can't seem to find the answer to my problem.
I have an Activity which contains a number of radio buttons, a button and a listview. The Activity first makes an http request to a web server to retrieve some data. The data from the server is written to the sqlite db on the device. Once data has been written to the db, the Activity regains control and creates a Cursor from the db, a SimpleCursorAdapter and sets the adapter as the listview adapter. All data is written ok to the db, I have looped through the elements in the cursor and it contains all expected elements, still no elements is displayed in my listview.
Activity.java:
public class MyActivity extends Activity {
private RadioButton rb1, rb2;
private Button addBut;
private ListView lv;
private LinearLayout statusLayout;
private ScrollView scroll;
private String username;
private DBHelper db;
private Cursor cursor;
private static final String userfk = "1";
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.mylayout);
rb1 = (RadioButton)findViewById(R.id.rb1);
rb1.setChecked(true);
rb2 = (RadioButton)findViewById(R.id.rb2);
addBut = (Button)findViewById(R.id.addButton);
statusLayout = (LinearLayout)findViewById(R.id.statusLayout);
scroll = (ScrollView)findViewById(R.id.configscroll);
lv = (ListView)findViewById(R.id.profilesll);
//get data from server, made in asynchtask
getData();
}
MessageHandler called from AsynchTask code:
private class MyHandler extends Handler {
public MyHandler() {
}
public void handleMessage(Message msg) {
final Bundle b = msg.getData();
if (b.getString("result").equalsIgnoreCase(MyResult.ERROR) || b.getString("result").equalsIgnoreCase(MyResult.FAIL)) {
//Handle error
} else {
handleList();
statusLayout.setVisibility(View.GONE);
scroll.setVisibility(View.VISIBLE);
}
}
}
private void handleList() {
if (db == null) {
db = new DBHelper(this);
}
if (cursor == null) {
try {
cursor = db.getListCursor(userfk);
} catch (Exception e) {
err = e.getMessage();
}
if (cursor == null) {
Toast.makeText(MyActivity.this, err != null ? err : getResources().getString(R.string.myerror), Toast.LENGTH_LONG).show();
} else {
try {
SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, android.R.layout.simple_list_item_1, cursor, new String[] {DBHelper.COLUMN_ID}, new int[] {android.R.id.text1});
lv.setAdapter(adapter);
} catch (RuntimeException e) {
Log.e("test", e.getMessage());
} catch (Exception e) {
Log.e("test", e.getMessage());
}
}
}
}
DBHelper class
public Cursor getListCursor(String userfk) throws Exception {
StringBuilder builder = new StringBuilder("select name as _id from mytable where userfk=?");
List<String> values = new ArrayList<String>();
values.add(userfk);
try {
return this.getReadableDatabase().rawQuery(builder.toString(), values.toArray(new String[values.size()]));
} catch (Exception e) {
Log.d("test", e.getMessage());
throw e;
}
}
I hope someone can give me a hint about what I'm doing wrong! Thanks for your help!

Update listview after asynctask completion

How do i update listivew when async task is done. Below is the sample code but the listview isn't updated.
class CallXML extends AsyncTask<Void, Void, Void> {
int gcid;
int scid;
public CallXML(int gid, int sid) {
// TODO Auto-generated constructor stub
gcid = gid;
scid = sid;
}
protected void onPreExecute() {
}
protected Void doInBackground(Void... arg0) {
// here goes the xml parsing....
}
return null;
}
protected void onPostExecute(String result) {
Log.e("TAG", "In postExecute");
Cursor cur3 = database2.query("Quote", qfield, null, null, null, null, null);
cur3.moveToFirst();
do {
quotesarray.add(cur3.getString(2));
} while (cur3.moveToNext());
if(cur3 != null){
cur3.close();
}
QList.post(new Runnable() {
public void run() {
mAdapter = new CustomAdapter();
mAdapter.notifyDataSetChanged();
QList.setAdapter(mAdapter);
}
});
if (helper2 != null) {
helper2.close();
}
if (database2 != null) {
database2.close();
}
}
}
EDIT:
Acutally onPostExecute is not executed why..This is the way I call asynctask new CallXML(gcid, scid).execute();
Also, onPostExecute is on the main thread so should not be doing database queries there. Instead, get data in doInBackground and return the final collection from there.
onPostExecute can be used for UI updates and updating your adapter with result collection.
Edit: posting a runnable
QList.post(new Runnable() {
public void run() {
//mAdapter.notifyDataSetChanged();
QList.setAdapter(mAdapter);
}
});
is not required since you are in the main loop.
You are not providing string items to the adapter in your code. And you don't need to call notifyDataSetChanged when you are setting adapter to a list, because when you set an adapter, it automatically loads the data into list. Perhaps you me try doing it in this way:
protected void onPostExecute(String result) {
Log.e("TAG", "In postExecute");
Cursor cur3 = database2.query("Quote", qfield, null, null, null, null, null);
cur3.moveToFirst();
mAdapter = new CustomAdapter();
do {
mAdapter.add(cur3.getString(2));
} while (cur3.moveToNext());
if(cur3 != null){
cur3.close();
}
QList.post(new Runnable() {
public void run() {
//mAdapter.notifyDataSetChanged();
QList.setAdapter(mAdapter);
}
});
if (helper2 != null) {
helper2.close();
}
if (database2 != null) {
database2.close();
}
}
Did u got any error? if so please post it. If not Check the size of data you got from database and if you want to refresh listview just call listview.invalidateViews() it will refresh the list view and set the new data in the listview.

Categories

Resources