Loader doesn't start after calling initLoader()? - java

I have a fragment, and want to start a loader when a button is clicked:
public class MyFragment extends Fragment {
public void onActivityCreated() {
super.onActivityCreated();
Button btn = ...;
btn.setOnClickListener(new OnClickListener() {
public void onClick(View view) {
getLoaderManager().initLoader(500, null, mMyCallback);
}
});
}
private LoaderManager.LoaderCallbacks<String> mMyCallback = new LoaderManager.LoaderCallbacks<String>() {
#Override
public Loader<String> onCreateLoader(int arg0, Bundle arg1) {
Log.e(TAG, "LoaderCallback.onCreateLoader().");
return new MyLoader(getActivity());
}
}
}
public class MyLoader extends AsyncTaskLoader<String> {
public MyLoader(Context context) {
super(context);
}
#Override
public String loadInBackground() {
Log.e(TAG, "Hi, running.");
return "terrific.";
}
}
After clicking the button, I can see my callback's onCreateLoader method called, but the created loader never actually starts. Do we need to call forceLoad() on the loader itself to get it to actually start? None of the sample posts do this,
Thanks

You need to implement onStartLoading() and call forceLoad() somewhere in the method.
See this post for more information: Implementing Loaders (part 3)

In my experience it never worked unless I used forceLoad().
You may find the answer to this previous question helpful:
Loaders in Android Honeycomb

Three important points regarding Loaders are:
Always Use forceLoad() method while initialising Loaders. For Example:
getLoaderManager().initLoader(500, null, mMyCallback).forceLoad();
Always implement onStartLoading(). This function will automatically be called by LoaderManager when the associated fragment/activity is being started.
Make sure the ID of the loader is unique otherwise new Loader will not be called.
If there is still a problem you can check the state of loader by calling the isStarted() method.

You need to keep a reference to the instance of the loader you create in the method onCreateLoader. Then, to refresh it, call yourLoader.onContentChanged();

If you have more than 1 loader in the same activity, make sure their id differs. I lost few hours to figure it out :)

Related

Unable to find Context for getExternalFilesDir() function in Android Studio

So, I am trying to write text to a file in Android Studio. I have the following code:
public void sampleFunction() {
File file = new File(getExternalFilesDir(null), "sample-file.txt");
}
The issue is that the method getExternalFilesDir(null) cannot be resolved. After doing some research I have noted that I need to provide the Context class. Such as:
public void sampleFunction(Context c) {
File file = new File(c.getExternalFilesDir(null), "equation_history.xml");
}
And when I called sampleFunction, I would simply pass in the current Context:
sampleFunction(this);
This normally would work, however, I need to call this function inside a setOnClickListener function for a Button. For example:
Button b_go = findViewById(R.id.b_go);
b_go.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Functions.sampleFunction(this);
}
});
So the return value for this is android.view.View.OnClickListener rather than android.content.Context.
How might I get around this? Any advice would be greatly appreciated.
Instead of passing "this" as an argument try calling getApplicationContext() or if you are in fragment just call getActivity().
What is often done is that a Context myContext variable is declared in the class, then onCreate, you populate it with myContext = this; Then, in any listener or Async Task, you can use myContext.getExternalFilesDir(null)
File storageDir = getActivity().getExternalFilesDir(Environment.DIRECTORY_PICTURES);

possible alternative to static inner classes to prevent memory leaks in android/java?

lately i have been researching about memory leaks in java/android and pretty much everywhere it says that instead of anonymous classes i should use static inner classes with weak references.
so, in my android app i started doing that but very quickly got tired of it because it's a lot of boilerplate code... i think have an alternative solution which i would prefer to use, but i'm juts not sure that it is a valid alternative to static inner classes in terms of preventing memory leaks. as i said before, i haven't seen this solution suggested anywhere else (all say to use static inner classes) so thats why im not sure my alternative will work.
ill use a simple example from my app:
i have a class called WebClient which handles asynchronous web requests and it accepts an interface called iCallback which returns the response from the server to the caller, and in my activity once i get this callback i need to dismiss a dialog, and maybe perform some activity related things (like trigger onBackPressed() and setResult()).
so here is my static inner class i have created:
private static class CallBack implements WebClient.ICallback
{
private WeakReference<ProgressDialog> mProgDiag;
private WeakReference<BaseActivity> mActivity;
public CallBack(BaseActivity activity, ProgressDialog progDiag)
{
this.mProgDiag = new WeakReference<>(progDiag);
this.mActivity = new WeakReference<>(activity);
}
#Override
public void onCallback(String data)
{
String responseAsString = Utils.extractStringFromResponse(...);
final BaseActivity parentActivity = mActivity.get();
ProgressDialog dialog = mProgDiag.get();
if(dialog != null)
{
dialog.dismiss();
}
if (responseAsString == null)
{
if(parentActivity != null)
{
Utils.makeServerErrorDialog(parentActivity,
new iDialogButtonClickedListener()
{
#Override
public void onDialogButtonClicked()
{
parentActivity.onBackPressed();
}
});
}
return;
}
//everything is ok
if (responseAsString.equals("1"))
{
if(parentActivity != null)
{
Intent result = new Intent();
result.putExtra(...);
parentActivity.setResult(Activity.RESULT_OK, result);
}
}
else
{
Utils.reportErrorToServer(...);
if(parentActivity != null)
{
parentActivity.setResult(Activity.RESULT_CANCELED);
}
}
if(parentActivity != null)
{
parentActivity.onBackPressed();
}
}
}
so for every variable i need in this static inner class i have to create a new weak reference, then retrieve the object itself, and then every time i want to access it i need to check whether it's null... that seems like a lot of code to me.
and here is my suggested alternative:
public abstract class BaseActivity extends AppCompatActivity
implements WebClient.ICallback
{
private static final String TAG = "BaseActivity";
WebClient.ICallback mCallBack;
ProgressDialog mProgDiag;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(...);
mCallBack = this;
//some code to invoke a server request on button click
//and passing mCallBack to the request
}
#Override
public void onCallback(String data)
{
String responseAsString = Utils.extractStringFromResponse(...);
mProgDiag.dismiss();
if (responseAsString == null)
{
Utils.makeServerErrorDialog(this,
new iDialogButtonClickedListener()
{
#Override
public void onDialogButtonClicked()
{
onBackPressed();
}
});
return;
}
//everything is ok
if (responseAsString.equals("1"))
{
Intent result = new Intent();
result.putExtra(...);
setResult(Activity.RESULT_OK, result);
}
else
{
Utils.reportErrorToServer(...);
setResult(Activity.RESULT_CANCELED);
}
onBackPressed();
}
#Override
protected void onPause()
{
mCallBack = null;
super.onPause();
}
#Override
protected void onResume()
{
super.onResume();
mCallBack = this;
}
}
to me this seems much cleaner: no creating and retrieving instances of weak references for every variable i need access to, i can directly invoke activity methods (e.g. onBackPressed()), and no checking for null everywhere.
the only place i would now have to check for null is inside WebClient class before invoking the callBack method.
so my question is, does this approach achieve the same result in terms of preventing memory leaks? is it a "worthy" alternative to static inner classes?
Unfortunately, your approach does not work. By implementing the WebClient.ICallback in your activity, rather than an inner class, you don't get rid of the leak. The leak happens not because the references to activity and dialog are implicit in an anonymous class, or in lambda, or in a non-static inner class instance; the happens when the WebClient keeps this reference while the activity is gone (it is not destroyed, because there is a strong reference to it).
The special mCallBack that you set to null when the activity is paused, gains nothing. Just as well, you can simply pass your activity instance to the WebClient. Now there is a strong reference to your activity, which is managed by someone (async handlers of the WebClient), who is not under your control. If you are unlucky, the async handler will get stuck somewhere and will never release this reference.
Please read this detailed explanation.
Note that WebView itself can cause a memory leak, if special measures are not undertaken!

In Android, how do you call a parent function with View references in it?

Here is the parent class:
public class void ParentClass () extends Activity {
private ListView _listView;
#Override
protected onCreate (Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_parent);
_listView = (ListView) getViewById(R.id.list_view);
ChildClass cc = new ChildClass();
}
protected void SetScroll() {
try {
_listView.setFastScrollEnabled(false);
} catch (Exception e) {
e.printStackTrace();
}
}
Here is the child class:
private void ChildClass extends ParentClass () {
public ChildClass() {
SetScroll();
}
}
Forgive me with regards to the syntax as I'm typing this from memory. The problem with these classes is that the SetScroll function called from the CallParent function does not work because it is unable to find the right _listView reference (it becomes null). What should I do to make it work correctly? Bear in mind that this is just an example.
But the view is getting null is because you are extending an activity class and before using its view you need to call the onCreate and set the view (if child activity needs new one). But for that you will have to follow the complete flow of the lifecycle. This will help you in extending an activity class. android how to create my own Activity and extend it?
Call parent class activity like this (Just for info). With your code it wont work. You need to correct your code first. See the link I have posted.
super.SetScroll();

Android: Fragments, SQLite and Loaders

So I've come to a point where I need to implement an SQLite database for my app.
Following "The Busy Coder's guide to Android Development" I have created a DatabaseHelper class that extends SQLiteOpenHelper.
One of my use cases is to run a query against the database and display the results on a ListView within a Fragment (I use fragments from the support library).
From what I understand, using managedQuery() is not really appropriate and even if it were it isn't recommended due to the fact that some of the logic encapsulated inside this method is actually executed on the main thread, specifically reQuery() which to my understanding is performed when the Activity is restarted.
So I've been trying to get acquainted with the Loader class for the first time, only to see this:
"The only supplied concrete implementation of a Loader is CursorLoader, and that is only for use with a ContentProvider"
My initial thought was to implement my own content provider and perhaps prevent other apps from getting access to it, then I read the following in the ContentProvider documentation via developer.android.com:
"You don't need a provider to use an SQLite database if the use is entirely within your own application."
I've also been playing with this:
https://github.com/commonsguy/cwac-loaderex
Yet I am not familiar with this project, and not sure if it can be used on a production environment.
So, right now all I can think of is creating a bunch of AsyncTask instances within my Fragment and manage their lifecycle appropriately, make sure they're cancelled whenever needed and whatnot.
Are there any other options?
I think implementing content provider is a good idea, no matter that data will not be accessible outside of the application. It provides very modern interface and from my experience makes your application error prone to database locking issues and other db-specific problems.
I've implemented it in my latest project and I was very happy to use it.
You can extend Loader class in order to perform other Async work such as loading directly from your DB.
Here is an example of that
Edit: added A better example of Loader usage.
Finally managed to find the tutorial that really helped me understand how things work.
By extending the loader class you can avoid messing with content observers and its quite easy to implement (at last)
the modifications that need to be taken in your code are
Add implementation of LoaderManager.LoaderCallbacks<D>, where D is your data list (snippet 1)
Create your loader class, copy snippet 2, and add the loading of your data from the DB
Finally call the loaders 1 call for init and then for refreshing the restart call. (snippet 2 & 3)
Snippet 1: How to "link" the loader with your fragment:
public static class AppListFragment extends ListFragment implements
LoaderManager.LoaderCallbacks<List<SampleItem>> {
public Loader<List<SampleItem>> onCreateLoader(int id, Bundle args) {
//...
return new SampleLoader (getActivity());
}
public void onLoadFinished(Loader<List<SampleItem>> loader, List<SampleItem> data) {
// ...
mAdapter.setData(data);
if (isResumed()) {
setListShown(true);
} else {
setListShownNoAnimation(true);
}
// ...
}
public void onLoaderReset(Loader<List<SampleItem>> loader) {
// ...
mAdapter.setData(null);
// ...
}
/* ... */
}
Snippet 2: Schema of your custom loader: (I have double commented the observer things as I believe that it is quite difficult to implement it from the beginning and you can simple recall the loader without messing with that automated refreshing)
public class SampleLoader extends AsyncTaskLoader<List<SampleItem>> {
// We hold a reference to the Loader’s data here.
private List<SampleItem> mData;
public SampleLoader(Context ctx) {
// Loaders may be used across multiple Activitys (assuming they aren't
// bound to the LoaderManager), so NEVER hold a reference to the context
// directly. Doing so will cause you to leak an entire Activity's context.
// The superclass constructor will store a reference to the Application
// Context instead, and can be retrieved with a call to getContext().
super(ctx);
}
/****************************************************/
/** (1) A task that performs the asynchronous load **/
/****************************************************/
#Override
public List<SampleItem> loadInBackground() {
// This method is called on a background thread and should generate a
// new set of data to be delivered back to the client.
List<SampleItem> data = new ArrayList<SampleItem>();
// TODO: Perform the query here and add the results to 'data'.
return data;
}
/********************************************************/
/** (2) Deliver the results to the registered listener **/
/********************************************************/
#Override
public void deliverResult(List<SampleItem> data) {
if (isReset()) {
// The Loader has been reset; ignore the result and invalidate the data.
releaseResources(data);
return;
}
// Hold a reference to the old data so it doesn't get garbage collected.
// We must protect it until the new data has been delivered.
List<SampleItem> oldData = mData;
mData = data;
if (isStarted()) {
// If the Loader is in a started state, deliver the results to the
// client. The superclass method does this for us.
super.deliverResult(data);
}
// Invalidate the old data as we don't need it any more.
if (oldData != null && oldData != data) {
releaseResources(oldData);
}
}
/*********************************************************/
/** (3) Implement the Loader’s state-dependent behavior **/
/*********************************************************/
#Override
protected void onStartLoading() {
if (mData != null) {
// Deliver any previously loaded data immediately.
deliverResult(mData);
}
// Begin monitoring the underlying data source.
////if (mObserver == null) {
////mObserver = new SampleObserver();
// TODO: register the observer
////}
//// takeContentChanged() can still be implemented if you want
//// to mix your refreshing in that mechanism
if (takeContentChanged() || mData == null) {
// When the observer detects a change, it should call onContentChanged()
// on the Loader, which will cause the next call to takeContentChanged()
// to return true. If this is ever the case (or if the current data is
// null), we force a new load.
forceLoad();
}
}
#Override
protected void onStopLoading() {
// The Loader is in a stopped state, so we should attempt to cancel the
// current load (if there is one).
cancelLoad();
// Note that we leave the observer as is. Loaders in a stopped state
// should still monitor the data source for changes so that the Loader
// will know to force a new load if it is ever started again.
}
#Override
protected void onReset() {
// Ensure the loader has been stopped.
onStopLoading();
// At this point we can release the resources associated with 'mData'.
if (mData != null) {
releaseResources(mData);
mData = null;
}
// The Loader is being reset, so we should stop monitoring for changes.
////if (mObserver != null) {
// TODO: unregister the observer
//// mObserver = null;
////}
}
#Override
public void onCanceled(List<SampleItem> data) {
// Attempt to cancel the current asynchronous load.
super.onCanceled(data);
// The load has been canceled, so we should release the resources
// associated with 'data'.
releaseResources(data);
}
private void releaseResources(List<SampleItem> data) {
// For a simple List, there is nothing to do. For something like a Cursor, we
// would close it in this method. All resources associated with the Loader
// should be released here.
}
/*********************************************************************/
/** (4) Observer which receives notifications when the data changes **/
/*********************************************************************/
// NOTE: Implementing an observer is outside the scope of this post (this example
// uses a made-up "SampleObserver" to illustrate when/where the observer should
// be initialized).
// The observer could be anything so long as it is able to detect content changes
// and report them to the loader with a call to onContentChanged(). For example,
// if you were writing a Loader which loads a list of all installed applications
// on the device, the observer could be a BroadcastReceiver that listens for the
// ACTION_PACKAGE_ADDED intent, and calls onContentChanged() on the particular
// Loader whenever the receiver detects that a new application has been installed.
// Please don’t hesitate to leave a comment if you still find this confusing! :)
////private SampleObserver mObserver;
}
Snippet 3: How to call the loader for the first time (ONLY)
// Initialize a Loader with an id. If the Loader with this id is not
// initialized before
getLoaderManager().initLoader(LOADER_ID, null, this);
Snippet 4: For refreshing data (recalling the query)
// Check if the loader exists and then restart it.
if (getLoaderManager().getLoader(LOADER_ID) != null)
getLoaderManager().restartLoader(LOADER_ID, null, this);
Reference:
Snippet 1 : usage of loader extracted from here
Snippet 2 : here for more info and logic read throughout the hole article
Snippet 3 & 4: are just loader usage.
Full code of these is also uploaded by the creator on github
I recommend OrmLite library, a lightweight Object Relational Mapping that can work for Android. This library will make your life easier . You don't need to create or update database by hand, you don't need to focus on managing database connection, all queries select, insert, update will be easier with a DAO approach (usually you don't need to write your own sql query) and a lot of features. They have some examples that you can start with.
And if you want to use the Loader, there is a ORMLite Extras , additional functionality for ORMLite available on github (You can use the support package which is compatible with support android library). Here is an example usage on my previous project:
public class EventsFragment extends Fragment implements LoaderCallbacks<Cursor>{
private static final int LOADER_ID = EventsFragment.class.getName().hashCode();
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getLoaderManager().initLoader(LOADER_ID, null, this);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View layoutRoot = inflater.inflate(
R.layout.fragment_events, null);
lvEvents = (ListView) layoutRoot.findViewById(R.id.lvEvents);
adapter = new EventAdapter(getActivity(), null, null);
lvEvents.setAdapter(adapter);
return layoutRoot;
}
#Override
public Loader<Cursor> onCreateLoader(int arg0, Bundle arg1) {
try {
PreparedQuery<Event> query = getDatabaseHelper().getEventDao().getQuery();
return getDatabaseHelper().getEventDao().getSQLCursorLoader(query );
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
#Override
public void onLoadFinished(Loader<Cursor> arg0, Cursor cursor) {
adapter.swapCursor(cursor);
try {
adapter.setQuery(getDatabaseHelper().getEventDao().getQuery());
} catch (SQLException e) {
e.printStackTrace();
}
}
#Override
public void onLoaderReset(Loader<Cursor> arg0) {
adapter.swapCursor(null);
}
private OrmliteDatabaseHelper getDatabaseHelper(){
return ((MainActivity)getActivity()).getDatabaseHelper();
}
}
The adapter
public class EventAdapter extends OrmliteCursorAdapter<Event>{
public EventAdapter(Context context, Cursor c, PreparedQuery<Event> query) {
super(context, c, query);
}
#Override
public void bindView(View itemView, Context context, Event item) {
TextView tvEventTitle = (TextView) itemView.findViewById(R.id.tvEventTitle);
TextView tvEventStartDate = (TextView) itemView.findViewById(R.id.tvEventStartDate);
tvEventTitle.setText(item.getTitle());
tvEventStartDate.setText(item.getFormatStartDate());
}
#Override
public View newView(Context context, Cursor arg1, ViewGroup arg2) {
LayoutInflater inflater = LayoutInflater.from(context);
View retView = inflater.inflate(R.layout.event_item_row, arg2, false);
return retView;
}
}
And a custom Dao which provides PreparedQuery for cursor adapter above:
public interface IEventDao extends Dao<Event, Integer>{
PreparedQuery<Event> getQuery() throws SQLException;
OrmliteCursorLoader<Event> getSQLCursorLoader(Context context, PreparedQuery<Event> query) throws SQLException;
}
public class EventDao extends AndroidBaseDaoImpl<Event, Integer> implements IEventDao{
public EventDao(ConnectionSource connectionSource) throws SQLException {
super(connectionSource, Event.class);
}
public EventDao(ConnectionSource connectionSource,
DatabaseTableConfig<Event> tableConfig) throws SQLException {
super(connectionSource, tableConfig);
}
#Override
public PreparedQuery<Event> getQuery() throws SQLException{
return queryBuilder().prepare();
}
}
Hope this can help!
If your database contains thousands of records consider madlymad's answer
If not keep it stupid and simple, use SQLiteOpenHelper and create a method that returns you your data as array of strings or define your one objects.
Also use custom/regular CursorAdapter or ArrayAdapter.
I use the SQLiteOpenHelper to create my database. I have made Java classes for all the tables and when I get the data from my database I put it in an ArrayList. The ArrayList I then load into the adapter of the Listview.

Separate a java listener to its own function?

Can I break the set-listener line into smaller pieces?
Here is the code I have:
protected void onCreate(Bundle savedInstanceState) {
Preference button = (Preference)getPreferenceManager().findPreference("exitlink");
button.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
#Override
public boolean onPreferenceClick(Preference arg0) {
finish();
return true;
}
});
I would like this to look something like:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Preference button = (Preference)getPreferenceManager().findPreference("exitlink");
if(button != null) {
button.setOnPreferenceClickListener(onPreferenceClick);
}
}
public boolean onPreferenceClick(Preference arg0) {
finish();
return true;
}
You can also create a variable outside of your method:
private Preference.OnPreferenceClickListener listener = new Preference.OnPreferenceClickListener() {
#Override
public boolean onPreferenceClick(Preference arg0) {
finish();
return true;
}
};
Then you use it as a variable: setListener(listener). This would allow you to have multiple instances of the same listener class in your Activity.
Your code above nearly works already. Use your above code with this tiny change:
button.setOnPreferenceClickListener(this);
Then you just let your class implement the specific interface needed, in this case Preference.OnPreferenceClickListener.
In addition to dmon's suggestion below about using variables for this, it is also possible to write a function that returns a listener, which is very useable when you want to have similar listeners but with slight changes, like in the example below.
private Preference.OnPreferenceClickListener getListener(int listenerId) {
return new Preference.OnPreferenceClickListener() {
#Override
public boolean onPreferenceClick(Preference arg0) {
Log.i("MyTag", "Listener " + listenerId + " invoked!");
finish();
return true;
}
};
}
As others have mentioned, even though you cannot pass a method name to setOnPreferenceClickListener you can create a variable of a type that extends Preference.OnPreferenceClickListener. In your original code, that is actually exactly what you are doing: you are creating an object of an anonymous inner class.
The advantage of this approach, say over Simon André Forsberg's answer above is of scope: it keeps the listener functionality in that small block, instead of potentially all over the class.
Creating a separate variable outside the method as in dmon's answer loses one big benefit of the anonymous inner class, that they can access the variables in the containing scope: in your original code, the listener can access the variables button and savedInstanceState. This is not possible with a separate variable defined outside the function.
None of this means that you must use anonymous inner class. Oracle has an excellent tutorial titled General Information about Writing Event Listeners that you will greatly benefit from.
Not exactly. The set-listener requires an instance of listener, so you always need to create one. And I don't think it's a good manner for activity implementing listener interfaces.
The workaround is that you can use annotations with reflection, such as http://code.google.com/p/roboguice/. This may make the code cleaner, but also introduces dependencies.

Categories