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
Related
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.
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
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!
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);
I am using services and broadcast receiver, to launch a listview (I am using only two activity classes first as first class starts it starts service with it..in the services hitting a webservice and parsing data, n passing data into the broadcast receiver,
now the data I am getting in onreceive, and storing that data into another data...now I want this data to access in my activity class which I wl use for listView...please tell how can I do it..without making that var. static.
I also tried this thing within another way please if it is possible in that way too.
There the first screen is getting launch there I kept one button as I click on the button service will start n will do the whole job as I wrote above.....but here as I click the button another activity is being launched which is that listview but that isn't extending listActivity that is extending activity.
so I want to update that list view dynamically how can I do this?
please, any Help is Appreciable.
my code is here where I am getting stuck
public class MessageList extends Activity {
public static final String TAG = MessageList.class.getSimpleName();
Context mContext;
public static ArrayList<String> mData;
public ListView mListView;
private List<Message> messages;
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.maina);
System.out.println("check bro"+mData);
System.out.println("In OnCreate of Messagelist class");
System.out.println("1st");
System.out.println("3rd");
mListView = (ListView) findViewById(R.id.mylist);
PlaceAdapter adapter = new PlaceAdapter(this, mData);
mListView.setAdapter(adapter);
}
private OnItemClickListener mItemClickListener = new OnItemClickListener() {
#Override
public void onItemClick(android.widget.AdapterView<?> arg0, View arg1, int arg2, long arg3) {
Intent viewMessage = new Intent(Intent.ACTION_VIEW,Uri.parse(messages.get(arg2).getLink().toExternalForm()));
startActivity(viewMessage);
}
};
/* #Override
protected void onListItemClick(ListView l, View v, int position, long id)
{
super.onListItemClick(l, v, position, id);
Intent viewMessage = new Intent(Intent.ACTION_VIEW, Uri.parse(messages
.get(position).getLink().toExternalForm()));
this.startActivity(viewMessage);
}*/
class MessageListBroadCast extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
System.out.println("hello");
System.out.println("final Done");
Bundle bundle = intent.getExtras();
mData = bundle.getStringArrayList("keya");
Log.d(TAG, "" + mData);
intent.putExtra("name", mData);
}
};
}
that message list is the class which is a list view
Thanks
Rather than working like this, I would use a class derived from CursorAdapter as Adapter and let your service store its results in a ContentProvider and notify changes on your ContentResolver on the same Uri you are using in the CursorAdapter. That way it will refresh automatically and your data is not lost should anything happen with your app (crash, memory,...). But I reckon this might be a bit of overhead, it all depends on what your webservice exactly does etc.