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.
Related
I am fetching data from database. My views are updating only first time when I open the activity. Then when I again open the activity, my views are not updated.(Activity is starting again, hence onCreate() is called again & all settings are same). If I getText() after setting the text, I am getting proper values in log but nothing is displayed in view.
Here is my code snippet:
//My Call Back method
#Override
public void onRatingDataLoaded(ReviewJsonModel review) {
int ratingCount = 0, ownRating = 0;
String averageRating = "0";
if (review != null) {
ratingCount = review.review_count;
DecimalFormat format = new DecimalFormat("##.00");
averageRating = format.format(review.rating);
if (review.ownreviews != null) {
try {
ownRating = Integer.parseInt(review.ownreviews.rating);
} catch (NumberFormatException e) {
e.printStackTrace();
}
}
} else {
// do something
}
mTotalRatingCount.setText(String.format(getResources().getString(R.string.review_count), ratingCount));
mAverageRating.setText(averageRating);
// Log.v("LoggingReview", mTotalRatingCount.getText().toString().trim);
myRating.setRating(ownRating);
}
//Here I am setting listner as well as loading data.
public void loadReviewData(RatingDataLoadListener listener, int destinationId) {
if (mDataLoadListener == null)
mDataLoadListener = listener;
new getReviews().execute(destinationId);
}
Next is my asyntask
private class getReviews extends AsyncTask<Integer, Void, ReviewJsonModel> {
#Override
protected ReviewJsonModel doInBackground(Integer... integers) {
Cursor appCursor = mRatingApi.getDestinationReview(integers[0]);
ReviewJsonModel mReviewData = new ReviewJsonModel();
if (appCursor != null && appCursor.getCount() > 0) {
appCursor.moveToFirst();
while (!appCursor.isAfterLast()) {
mReviewData = getDocument(appCursor);
appCursor.moveToNext();
}
appCursor.close();
}
return mReviewData;
}
#Override
protected void onPostExecute(ReviewJsonModel result) {
super.onPostExecute(result);
if (mDataLoadListener != null)
mDataLoadListener.onRatingDataLoaded(result);
}
}
Can't find cause of problem. Any help is appreciated.
Looks like there is callback issue, can you please try below
public void loadReviewData(RatingDataLoadListener listener, int destinationId) {
mDataLoadListener = listener;
new getReviews().execute(destinationId);
}
I have a custom progress dialog that seems to work everywhere except here in my code:
My login activity (relevant snippets):
#Override
protected void onCreate(Bundle savedInstanceState) {
try {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
context = this;
pd = AUtils.getProgressDialog(context, false);
UserExistsAuthenticateAndRoute = getIntent().getBooleanExtra("UserExistsAuthenticateAndRoute", false);
RouteToActivity = getIntent().getStringExtra("RouteToActivity");
//make sure there is no token in APrefs in memory during login
APrefs pref = new APrefs();
if (pref != null) {
pref.putNMToken(null);
pref.putNMRefreshToken(null);
}
ClickableSpan span = new ClickableSpan() {
#Override
public void onClick(View widget) {
}
};
setActionBar();
initUi();
mToolbarTitle.setText("Log In");
} catch (Exception exc) {
exc.printStackTrace();
}
}
#Override
protected Void doInBackground(Void... voids) {
GDDataManager.get().login(GDUser, new DataCallBack() {
#Override
public void update(DataUpdate update) {
if (update.code == 0) {
final GDUser _gdUser = pref.getMember();
//call get status
if (_gdUser != null) {
Log.i(TAG, "getUserStatus()");
GDDataManager.get().getUserStatus(_gdUser, new DataCallBack() {
#Override
public void update(DataUpdate update) {
if (update.code == 0) {
setGdUserStatus((GDUserStatus) update.data);
loginController(getGdUserStatus(), _gdUser);
} else {
Log.e(TAG, "getUserStatus(), error response msg " + update.message);
if (update.message.contains("error")) {
App.toast(getString(R.string.general_server_error_message));
}
}
}
});
}
} else {
Log.e(TAG, "update message:" + update.message);
if (update.message.contains("error")) {
App.toast(getString(R.string.general_server_error_message));
} else if (update.message.contains("could not verify password")) {
App.toast(getString(R.string.could_not_verify_password));
} else if (update.message.contains("no user found")) {
App.toast(getString(R.string.no_user_found));
} else {
App.toast(update.message);
}
if (btnLogIn != null) {
//disable is valid in order to prevent double click
btnLogIn.setEnabled(false);
btnLogIn.setTextColor(ContextCompat.getColor(context, R.color.colorGrey));
}
edtEmail.setCompoundDrawablesWithIntrinsicBounds(null, null, ContextCompat.getDrawable(context, R.drawable.cross_icon), null);
edtEmail.setBackground(ContextCompat.getDrawable(context, R.drawable.textfield_red));
edtPassword.setBackground(ContextCompat.getDrawable(context, R.drawable.textfield_red));
}
}//end update getUserStatus
}
);
return null;
}
};
try {
tryLoginTask.execute();
} catch (Exception exc) {
Log.d(TAG, exc.getMessage());
exc.printStackTrace();
//cancel task on exception , DISMISS DIALOG to avoid locking screen
tryLoginTask.cancel(true);
}
}//end tryLogin()
The static code from utility class, were the dialog is returned (relevant snippet):
public static Dialog getProgressDialog(Context c, boolean isCancelable) {
Dialog pd = new Dialog(c,c.getApplicationInfo().theme);
pd.setCanceledOnTouchOutside(isCancelable);
pd.requestWindowFeature (Window.FEATURE_NO_TITLE);
pd.setContentView (R.layout.progress_dialog);
pd.getWindow().setBackgroundDrawable(new ColorDrawable(Color.argb(150,0,0,0)));
return pd;
}
Im not seeing any errors, exceptions, and the dialog is showiong in other places using the same approach. Sometimes I see it for fraction of a second however the task hasn't completed.
Any suggestions.
Thanks
AlertDialogs are foreground things. You should show your Dialogs in your UI thread. So if you want to show your Dialog in an AsyncTask you should approach with runOnUiThread:
runOnUiThread(new Runnable() {
#Override
public void run() {
// Show your dialog here
}
});
Documentations:
https://developer.android.com/reference/android/os/AsyncTask.html
https://developer.android.com/guide/components/processes-and-threads.html
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..
I am trying to use ProgressDialog. when i run my app the Progress Dialog box show and disappear after 1 second. I want to show it on completion of my process.. Here is my code:
public class MainActivity extends Activity {
android.view.View.OnClickListener mSearchListenerListener;
private ProgressDialog dialog;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new YourCustomAsyncTask().execute(new String[] {null, null});
}
private class YourCustomAsyncTask extends AsyncTask <String, Void, Void> {
protected void onPreExecute() {
dialog = new ProgressDialog(MainActivity.this);
dialog.setMessage("Loading....");
dialog.setIndeterminate(true);
dialog.setCancelable(true);
dialog.show(); //Maybe you should call it in ruinOnUIThread in doInBackGround as suggested from a previous answer
}
protected void doInBackground(String strings) {
try {
// search(strings[0], string[1]);
runOnUiThread(new Runnable() {
public void run() {
// updateMapWithResult(); //Or call it onPostExecute before progressDialog's dismiss. I believe this method updates the UI so it should run on UI thread
}
});
} catch(Exception e) {
}
}
#Override
protected void onPostExecute(Void params) {
dialog.dismiss();
//result
}
#Override
protected Void doInBackground(String... params) {
// TODO Auto-generated method stub
return null;
}
}
}
Updated Question:
#Override
public void onCreate(SQLiteDatabase db) {
mDatabase = db;
Log.i("PATH",""+mDatabase.getPath());
mDatabase.execSQL(FTS_TABLE_CREATE);
loadDictionary();
}
/**
* Starts a thread to load the database table with words
*/
private void loadDictionary() {
new Thread(new Runnable() {
public void run() {
try {
loadWords();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}).start();
}
private void loadWords() throws IOException {
Log.d(TAG, "Loading words...");
for(int i=0;i<=25;i++)
{ //***//
final Resources resources = mHelperContext.getResources();
InputStream inputStream = resources.openRawResource(raw_textFiles[i]);
//InputStream inputStream = resources.openRawResource(R.raw.definitions);
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
try {
StringBuilder sb = new StringBuilder();
while ((word = reader.readLine()) != null)
{
sb.append(word);
// Log.i("WORD in Parser", ""+word);
}
String contents = sb.toString();
StringTokenizer st = new StringTokenizer(contents, "||");
while (st.hasMoreElements()) {
String row = st.nextElement().toString();
String title = row.substring(0, row.indexOf("$$$"));
String desc = row.substring(row.indexOf("$$$") + 3);
// Log.i("Strings in Database",""+title+""+desc);
long id = addWord(title,desc);
if (id < 0) {
Log.e(TAG, "unable to add word: " + title);
}
}
} finally {
reader.close();
}
}
Log.d(TAG, "DONE loading words.");
}
I want to show ProgressDialogue box untill all words are not entered in the database. This code is in inner calss which extends SQLITEHELPER. so how to can i use ProgressDialogue in that inner class and run my addWords() method in background.
You cannot have this
runOnUiThread(new Runnable() {
public void run() {
// updateMapWithResult(); //Or call it onPostExecute before progressDialog's dismiss. I believe this method updates the UI so it should run on UI thread
}
});
in your doInBackground().
Progress dialog doesn't take priority when there is some other action being performed on the main UI thread. They are intended only when the actions are done in the background. runonUIthread inside doInBackground will not help you. And this is normal behavior for the progressdialog to be visible only for few seconds.
You have two doInBackground() methods inside your AsyncTask Class. Remove the runOnUiThread() from First doInBackground() and move it to second doInBackground() which has #Override annotation.
I don't know whether you wantedly written two doInBackground() methods or by mistake but it is not good to have such confusion between the Method. Your AsyncTask is not calling the first doInBackground() and it will call doInBackground() which has #Override annotation. So your ProgressDialog is dismissed in 1 second of time as it returns null immediately.
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