How to show ProgressiDialog when using LoaderCallbacks - android

I have a class that loads the images on the device. This is an example of my activity:
public class MediaListActivity extends AppCompatActivity implements LoaderCallbacks<Cursor> {
private ProgressDialog progressDialog;
#Override
protected void onCreate(Bundle savedInstanceState) {
...
progressDialog.show();
getSupportLoaderManager().initLoader(1, null, this);
}
#Override
public android.support.v4.content.Loader<Cursor> onCreateLoader(int id, Bundle args) {
CursorLoader cursorLoader = new CursorLoader(this, MediaStore.Images.Media.EXTERNAL_CONTENT_URI, null, null, null, null);
return cursorLoader;
}
#Override
public void onLoadFinished(android.support.v4.content.Loader<Cursor> loader, Cursor cursor) {
progressDialog.dismiss();
}
}
Of course, I can't put progressDialog.show() inside the onCreate() method, since if the ContentObserver find a change in MediaStore.Images.Media.EXTERNAL_CONTENT_URI and the Cursor is reloaded the method progressDialog.show() will not be called.
How can I solve this problem?
Thank you in advance

Try showing the dialog in onLoaderReset() callback. It is called anytime a loader is restarted, despite the onCreateLoader() that may not be called every time because the loader might already be created.

Related

ProgressDialog with LoadManager

I checked questions asked in StackOverflow but couldnt make to solve my issue.
I am trying to get some data in ListView in asynchronous way (to not overload UI Thread) and while i get the data i want to show a ProgressDialog. I am getting the data using ContentProvider and it loads the data successfully in ListView, however the progressDialog is not spinning, but after the list is shown with data it starts spinning and never stops (Keeps spinning).
How can i make ProgressDialog spin and dismiss() after the ListView is Visible.
Here is the activity which implements LoaderCallbacks:
public class AttractionsActivity extends Activity implements LoaderManager.LoaderCallbacks<Cursor> {
DatabaseHelper dbHelper;
private SimpleCursorAdapter cursorAdapter;
private ListView attractionsListView;
private ProgressDialog progressDialog;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.custom_listview);
attractionsListView = (ListView)findViewById(R.id.lvCustom);
progressDialog = new ProgressDialog(this);
progressDialog.setMessage("Loading");
progressDialog.setCancelable(false);
progressDialog.setIndeterminate(true);
progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
dbHelper = new DatabaseHelper(this);
dbHelper.open();
populateAttractionsListView();
dbHelper.close();
}
private void populateAttractionsListView() {
//final ImageView image = (ImageView) findViewById(R.id.ivAttImage);
//Initialize Loader
getLoaderManager().initLoader(0, null, this);
String[] from = {PoisContract.COLUMN_POI_MAIN_PIC, PoisContract.COLUMN_POI_NAME};
int[] to = {R.id.ivAttImage, R.id.tvAttName};
//Initialize CursorAdapter
cursorAdapter = new SimpleCursorAdapter(this, R.layout.attractions_listview_row, null, from, to, 0);
ViewBinder viewBinder = new ViewBinder() {
#Override
public boolean setViewValue(View view, Cursor cursor, int columnIndex) {
boolean binded = false;
if(view != null){
String imgName = cursor.getString(columnIndex);
int imgResId = getResources().getIdentifier(imgName, "drawable", getPackageName());
((ImageView) view).setImageResource(imgResId);
binded = true;
}
return binded;
}
};
//Set Adapter but there is no cursor right now
attractionsListView.setAdapter(cursorAdapter);
//Set Binder to the adapter
cursorAdapter.setViewBinder(viewBinder);
//Hide ListView as there is no data returned
attractionsListView.setVisibility(View.GONE);
}
private Cursor getAllAttractions(){
ContentResolver resolver = getContentResolver();
return resolver.query(PoisContract.CONTENT_URI, PoisContract.PROJECTION, null, null, null);
}
#Override
public Loader<Cursor> onCreateLoader(int i, Bundle bundle) {
progressDialog.show(this, "Please wait...", "Loading List...");
CursorLoader cursorLoader = new CursorLoader(AttractionsActivity.this, PoisContract.CONTENT_URI, PoisContract.PROJECTION, null, null, null);
return cursorLoader;
}
#Override
public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor cursor) {
cursorAdapter.swapCursor(cursor);
progressDialog.dismiss();
attractionsListView.setVisibility(View.VISIBLE);
}
#Override
public void onLoaderReset(Loader<Cursor> cursorLoader) {
//Data is not available anymore, delete reference
cursorAdapter.swapCursor(null);
}
however the progressDialog is not spinning, but after the list is
shown with data it starts spinning
This is happening because, despite (correctly)using a Loader to load the data, you also manually query the provider on the main UI thread through the call to the getAllAttractions() method(in the onCreate() method) which will block the UI thread. In fact I don't know why you did that as the returned Cursor is not used at all. Remove the:
Cursor cursor = getAllAttractions();
line from your activity's onCreate() method to solve this issue.
...and never stops (Keeps spinning).
This is happening because you call dismiss on the wrong ProgressDialog reference so you don't cancel the currently showing ProgressDialog. In the onCreate() method of the Activity you create a ProgressDialog reference, however in the onCreateLoader() callback you use the show() method which creates a new instance of a ProgressDialog(the method is static) so when you try to dismiss it in onLoadFinished() you dismiss the previously created ProgressDialog(which isn't even showing). To solve it use:
progressDialog = ProgressDialog.show(this, "Please wait...", "Loading List...");
in the onCreateLoader() callback.
As a side note you should always call a static method of a class by using the class name and not some object reference of that class, this will make thing more clear for you and also anyone who would later read your code.
Ok #Luksprog thank you very much for helping. I found the issue. The problem was in the ContentProvier AUTHORITY declaration. I misspelled the AUTHORITY String in one place. It took a day to figure out that stupid mistake.
I really appreciate your help

Opening an activity with a webview (and url) restarts application

I am working on a small app that uses cursorloaders and loader callbacks. I am new to loader callbacks. The app displays a list of items and on item click a new activity is called that loads a url in a webview. I am not finishing the parent activity, but it so happens that when the webpage loads completely after some 1 or 2 minutes the previous activity restarts.
I did not know what to put in as the question since i am not sure if it the webpage that causes the restart of it the loader that causes the activity to restart. Though i have read the documentation and also:
this, but none of them talks about a restart.
I have also looked at this , but got no clue. Could this be a cause for the application restart ?
I am calling the following link in the webview activity:
url
I also looked at webview shows blank page, and from that i added the following code to mine (inside the webviewclient class)
public void onReceivedSslError (WebView view, SslErrorHandler handler, SslError error){
handler.proceed() ;
}
------ EDIT, my activity extends SherlockFragmentActivity and implements LoaderCallbacks and my code is as under for the first activity
private ListView mListView;
private Cursor mCursor;
private MyListAdapter mListAdapter;
private CursorLoader mCursorLoader;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mListView = (ListView)findViewById(android.R.id.list);
fillDataIntoCursor();
new GetDataAsyncTask(this, mLimit).execute();
mListView.setOnItemClickListener(this);
}
private void fillDataIntoCursor() {
getLoaderManager().initLoader(0, null, this);
mListAdapter = new MyListAdapter(this,mCursor,false);
mListView.setAdapter(mListAdapter);
}
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
mCursor = mListAdapter.getCursor();
mCursor.moveToPosition(position);
String link = mCursor.getString(mCursor.getColumnIndex(MyTable.COL_NAME_HERE));
Intent intent = new Intent(MainActivity.this, WebViewActivity.class);
intent.putExtra("link",link);
startActivity(intent);
}
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
if(mListAdapter!=null && cursor!=null)
mListAdapter.swapCursor(cursor);
}
#Override
public void onLoaderReset(Loader<Cursor> cursor) {
}
#Override
public Loader<Cursor> onCreateLoader(int arg0, Bundle bundle) {
String[] projection = { // columns here};
mCursorLoader = new CursorLoader(this,
MyContentProvider.CONTENT_URI, projection, null, null, null);
return mCursorLoader;
}
Any help will be appreciated.
Thanks
PS: When i replace the url with Google the mainactivity does not restart. Also there are no conifg changes that take place which might cause the restart
I also get this error 10-09 21:02:53.229: E/InputDispatcher(156): channel '40bed3f0 packagename_here/packagename_here.MainActivity (server)' ~ Consumer closed input channel or an error occurred. events=0x8

Android AsyncTask, Pass view from UI Activity

I have a web browser application.
A AutoCompleteTextView act as a Url textbox, and being fetch a list (Cursor Type) when application start.
Below code is work well, but i don't know it correct to use AsyncTask or not.
So, did the AutoCompleteTextView will freeze will application launch?
And i monitor the thread via Eclipse thread monitor, the AsyncTask#1 thread keep in wait status when done.So how can i close the thread???
Code:
public class BrowserActivity extends StandOutWindow {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Build the layout
LayoutInflater inflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
View v = inflater.inflate(R.layout.activity_browser, frame, true);
AutoCompleteTextView txtUrl = (AutoCompleteTextView) v.findViewById(R.id.txtUrl);
//Run the async task
BrowserDataTask bdTask = new BrowserDataTask();
bdTask.execute(txtUrl);
}
//A method belong to BrowserActivity class and reusable.
public Cursor getBrowserData() {
String[] projection = new String[] { "_id", Browser.BookmarkColumns.TITLE,
Browser.BookmarkColumns.URL };
Cursor mCur = getContentResolver().query(android.provider.Browser.BOOKMARKS_URI,
projection, null, null, null);
return mCur;
}
//Sub Class of BrowserActivity
private class BrowserDataTask extends AsyncTask<AutoCompleteTextView, Integer, Cursor>
{
private AutoCompleteTextView m_acText;
#Override
protected Cursor doInBackground(AutoCompleteTextView...params) {
m_acText = params[0];
return getBrowserData();
}
#Override
protected void onProgressUpdate(Integer... progress) {
super.onProgressUpdate(progress);
}
#Override
protected void onPostExecute(Cursor result) {
//UrlAdapter, custome Cursor Adapter from other class.
UrlAdapter adapter = new UrlAdapter(BrowserActivity.this, result);
m_acText.setAdapter(adapter);
}
}
}
Why is it waiting?
AyncTask uses ThreadPoolExecutor and hence you they might not get destroyed but rather kept, because destroying and reinitializing them would be a definite waste. In case you really want to close it, call cancel() on it, that might help.
Will it freeze the app?
No, it won't.
Also, you are never setting your progress!

Android - onLoadFinished not called

I am facing an issue with Loader.
I have an Activity, which displays list of records retrieved from local DB. When the activity starts, records are automatically loaded via LoaderManager.initLoader() method.
There is also possibility to manually refresh the list via refresh button in ActionBarSherlock. However, after finishing another activity which adds a record to DB, onLoadFinished is not called.
I am using SimpleCursorLoader and here is code snippet from the activity:
#Override
public void onStart() {
...
getSupportLoaderManager().initLoader(0, null, this);
}
#Override
public void onPause() {
...
getSupportLoaderManager().destroyLoader(0);
}
public void refreshRecords() {
getSupportLoaderManager().restartLoader(0, null, this);
}
#Override
public Loader<Cursor> onCreateLoader(int id, final Bundle args) {
Loader<Cursor> l = new SimpleCursorLoader(this) {
#Override
public Cursor loadInBackground() {
return recordDAO.getCursor();
}
};
l.forceLoad();
return l;
}
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor c) {
// updateUI
}
#Override
public void onLoaderReset(Loader<Cursor> loader) {
}
The issue is that after finishing the other activity, onLoaderCreate is called, but onLoaderFinished is not called.
after some debugging, I've found that SimpleCursorAdapter.deliverResults() is also called, bud ends up on .. if (isReset()) { ..
Am I missing something? How to force the reload of data?
Thank you in advance
I have finally found the solution to this problem thanks to the discussion on
https://groups.google.com/forum/#!topic/android-developers/DbKL6PVyhLI
public static <T> void initLoader(final int loaderId, final Bundle args, final LoaderCallbacks<T> callbacks,
final LoaderManager loaderManager) {
final Loader<T> loader = loaderManager.getLoader(loaderId);
if (loader != null && loader.isReset()) {
loaderManager.restartLoader(loaderId, args, callbacks);
} else {
loaderManager.initLoader(loaderId, args, callbacks);
}
}
In addition as of support library 28 make sure that you don't call initLoader from within Fragment.onCreate(). As the updated documentation states
You typically initialize a Loader within the activity's onCreate() method, or within the fragment's onActivityCreated() method.
see https://developer.android.com/guide/components/loaders
RaB solution dont work for me
My worked Solution, was always destroy Loader before restart
Loader<Cursor> loader = mLoaderManager.getLoader(mKeyLoader);
if (loader != null)
{
mLoaderManager.destroyLoader(mKeyLoader);
}
mLoaderManager.restartLoader(mKeyLoader, args, this);
In addition to RaB's answer, if you are using a custom Loader, make sure that if you call super if you overwrite deliverResult():
#Override
public void deliverResult(D data) {
super.deliverResult(data); // <--onLoadFinished() will not be called if you don't call this
...
}
fwiw, I had a similar problem from attempting to immediately restart the loader a second time, before the first onLoadFinished was called, resulting in neither being called.
this worked for me:
if( loader == null )
loader = loaderMngr.initLoader(
0, null, myLoaderCallbacks
);
else if( loader.isAbandoned() )
return;
else
loaderMngr.restartLoader(
0, null, myLoaderCallbacks
);
Check the support library.Use this import android.support.v4.app. Don't use android.app.loadermanager.
import android.support.v4.app.LoaderManager;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
Initialize part
LoaderManager mLoaderManager=getSupportLoaderManager();
LoaderManager.LoaderCallbacks<Cursor> mCursorLoaderCallbacks=new LoaderManager.LoaderCallbacks<Cursor>() {
#Override
public Loader<Cursor> onCreateLoader(int id, Bundle cursor) {
return new CursorLoader(getActivity(), MediaStore.Video.Media.EXTERNAL_CONTENT_URI, COLUMNS_OF_INTEREST, null, null,
MediaStore.Video.Media.DATE_ADDED + " DESC");
}
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
}
#Override
public void onLoaderReset(Loader<Cursor> loader) {
}
};
mLoaderManager.initLoader(URL_LOADER_EXTERNAL, null, mCursorLoaderCallbacks);

Calling UI thread method from AsyncTask

I have a problem with calling the setadapter() method from the inside of AsyncTaskActivity onPostExecute() method. I've read docs about AsyncTask: http://developer.android.com/reference/android/os/AsyncTask.html#onPostExecute(Result) but found no answer how to achieve that. Should I use an Intent to do so? I'm new to a Android development so please forgive me if it's a kind of stupid question.
MainActivity
public class MainActivity extends ListActivity {
private String[] columns = new String[] {"foreign_word", "native_word"};
private int[] target = new int[] { R.id.foreign_word, R.id.native_word };
private Cursor cur = null;
#Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
new AsyncTaskActivity(this).execute();
}
public void setadapter(Cursor cur) {
SimpleCursorAdapter aaa = new SimpleCursorAdapter(this.getApplicationContext(), R.layout.list_entry, cur, columns, target, 0);
this.setListAdapter(aaa);
}
}
AsyncTaskActivity
public class AsyncTaskActivity extends AsyncTask<Void, Void, Cursor> {
Activity activity = null;
private SQLiteDatabase db = null;
private String[] selection = {"_id", "native_word", "foreign_word"};
Cursor cur = null;
public AsyncTaskActivity(Activity activity) {
this.activity = activity;
}
#Override
protected Cursor doInBackground(Void... params) {
DbAdapter mSQLadapter = new DbAdapter(activity);
db = mSQLadapter.getWritableDatabase();
Cursor cur = db.query("words", selection, "foreign_word='car'", null, null, null, null);
return cur;
}
protected void onPostExecute(Cursor cur) {
// I'd like to call setadapter() ,passing it Cursor as a parameter
}
}
Assuming that your AsyncTask is always called by MainActivity, do this
protected void onPostExecute(Cursor cur) {
MainActivity mActivity = (MainActivity) activity;
mActivity.setadapter();
}
You can specify more parameters for your setAdapter method so you can pass off the Cursor, String Array, etc.
However an even better method if the AsyncTask is only called from MainActivity is to make this AsyncTask a private inner class inside MainActivity. This will allow it to access all the global variables and methods of MainActivity
Your approach is a little unusual, but to answer the question asked:
Change activity to a ListActivity:
ListActivity activity = null;
And use:
protected void onPostExecute(Cursor cur) {
activity.setListAdapter(new SimpleCursorAdapter(activity, R.layout.list_entry, cur, columns, target, 0));
}
You should look into using the LoaderManager class, it creates and handles background threads for you. You should also consider using a ContentProvider, it handles a lot of busy work for you as well.
Lastly AsyncTaskActivity is not an Activity, so this class name is a little confusing...

Categories

Resources