getApplicationContext() with AppWidgetProvider - java

I'm trying to connect my Widget to the app's database, but I don't understand a thing.
Why this works:
import android.app.Activity;
public class Widgets1 extends Activity{
mMioDbHelper = new SqlHelper(getApplicationContext());
and this not?
import android.appwidget.AppWidgetProvider;
public class Widgets1 extends AppWidgetProvider{
mMioDbHelper = new SqlHelper(getApplicationContext());
How can I connect the widget to the database? I mean how can I do a query from a widget class?
Thanks.

AppWidgetProvider extends BroadcastReceiver, which does not, in turn, inherit from Context. getApplicationContext() is a method on Context. As you determined, the reason why you are passed a Context into onReceive() of a BroadcastReceiver (and onUpdate() and other callbacks on AppWidgetProvider) is so you can do things that need a Context.
All that being said, the code you have here has issues:
Do not use methods inherited from Context from an initializer, as you have with your Activity snippet. There is no guarantee that such methods are ready for use at that point in time. Delay using Context methods until the initial entry point of the component, such as onCreate() of an Activity.
Never do database I/O on the main application thread, as it will freeze your application's UI if one of your activities happens to be in the foreground at the time. All callbacks to your AppWidgetProvider, like onUpdate(), are called on the main application thread. Please use an IntentService or something else that can safely run a background thread. Note that the IntentService is perfectly capable of updating the app widget UI via AppWidgetManager. onUpdate() is a trigger for you to do certain work, but that work can -- and often times should -- be done elsewhere.
Be very careful in creating all sorts of SQLiteOpenHelper instances, and I am assuming that SqlHelper is a subclass of SQLiteOpenHelper. Please have exactly one instance of your SQLiteOpenHelper for your entire application, so that you can take advantage of the thread safety built into SQLiteOpenHelper. That usually winds up being a singleton SQLiteOpenHelper. Having multiple instances is likely to get you in thread-related trouble.

Related

Custom Application class: Constructor vs. onCreate()

One of my Android apps uses a custom Application class to perform some global initialization. This done in the onCreate() method:
public class MyApplication extends Application {
#Override
public void onCreate() {
super.onCreate();
someCustomInit();
}
}
This works fine, but now I have discovers a crash log in the Developer Console which indicated that MyApplication.onCreate() did not run / has not completed at the time the crash happened: The code crashed because some initialization that is performed MyApplication.onCreate() was not complete.
How is this possible? I assumed that MyApplication.onCreate() would run before all other code? Isn't that correct?
Is it save to move someCustomInit(); to the constructor of MyApplication instead? No other code should run before the application object has been created, correct?
Or are there any side effects from using the constructor instead of onCreate()?
I assumed that MyApplication.onCreate() would run before all other code? Isn't that correct?
ContentProvider instances are created before onCreate() is called on the Application. In theory, your stack trace should show you what code of yours is being invoked prior to your initialization.
Is it save to move someCustomInit(); to the constructor of MyApplication instead?
That would depend on what is happening in someCustomInit(). Your Application is not initialized yet.
Another possibility is to override attachBaseContext(), such as how ACRA is hooked in. There, you are passed a Context object that you can use, if your initialization requires a Context.
The Application class is a singleton for your app process, but its onCreate() is not the first possible code to execute. Class field initializers, the constructor as well as any static code blocks (often used for loading native libs) will execute first. The static code blocks, in particular, will run when the class is loaded by the runtime.
Normally, this is not a problem and your safest route is to put your specific code in the onCreate() method.
How is this possible?
It is possible since Application class onCreate is called for every process of your app.
For example Service can be started in separate process so your Application can be started twice. I have met this behaviour when used Yandex.Appmetrica library. It is not bad actually, because crashes in library will not affect other parts of application.
Or are there any side effects from using the constructor instead of
onCreate()?
From the documentation:
The Application class, or your subclass of the Application class, is
instantiated before any other class when the process for your
application/package is created.
So constructor will be called twice. Any difference?
You should move your code that supposed to run only once to somewhere else, outside Application class. Probably in some Singleton which will be called from Launcher Activity or smth. Actually if you see sources of Application class you will see that comment:
There is normally no need to subclass Application. In most situations,
static singletons can provide the same functionality in a more modular
way.

How to access an object instantiated in one activity and running in its own thread, from another activity?

I have a problem getting access to an object that controls audio output and that was created in another activity. Here's the case:
I have a class that implements Runnable so that I can run it in its own thread:
public class PulseGenerator implements Runnable {...}
In my main activity I instantiate this class, pass the instance to a Thread object and start the thread:
noise = new PulseGenerator();
noiseThread = new Thread(noise);
noiseThread.start();
I have a few controls in my main activity screen to control internals of 'noise': switch audio on and off, select a waveform, change pulse width and the like. This all works just fine.
Now I want to move a few of these existing and working controls to another screen that I've called 'Settings'. (In order to make room for other additional controls on the main activity screen.) I followed the typical Android approach by creating a new activity for the new Settings screen:
public class Settings extends Activity implements OnItemSelectedListener, View.OnClickListener { ... }
This all sounds simple enough. The problem I have now is that I don't know how to get access to the 'noise' object from the new Settings screen/activity/class. When I run the app on the emulator and press a button to switch to the Settings activity, the app crashes ("Unfortunately, xxxxx has stopped.") and in Android Studio's 'Run' view, I get:
E/AndroidRuntime: FATAL EXCEPTION: main java.lang.NullPointerException
with a reference to the line number in Settings where I try to access the 'noise' object for the first time. Which makes perfect sense to me, because I have declared, but not initialized the 'noise' object. Because I don't know how, which is the core of this question.
Putting the question more generally, how do I access an object instantiated in one activity and running in its own thread, from another activity?
I am a beginning java and Android programmer and this is my first post, please don't be too brief when answering. Actually I hope it's a 'stupid' beginner's question about multi-activity app programming with an easy answer, so I can move on with my project. I appreciate any help.
PS:
- Standard methods for passing objects between activities don't apply because an object running in its own thread is not serializable. (If I understood correctly.)
- I know of workarounds that use multiple screens per activity (one of them using setVisibility(View.GONE)) and that I could probably get to work. But these solutions lack generality and that's why I don't want to use them.
There are some possibilities:
A simple solution would be stopping the thread when an Activity is about to finish and restart it in the next Activity. Of course, it depends on what the thread does and whether it is possible at all.
Wrap the noise thread in a singleton, so you can access the thread from any Activity.
Create a Service and manage the noise thread in there. Maybe you can also reimplement the thread functionality as a Service. From https://developer.android.com/guide/components/services.html:
A Service is an application component that can perform long-running operations in the background, and it does not provide a user interface.
A long-running Service lifecycle is not bound to the lifecycle of an Activity, so even if an Activity finishes, your thread would keep running and would be accessible via the Service that controls it. Mind two things: although a Service doesn't provide UI, it runs on the main UI thread, and a Service might be finished by the operating system, but it can be restarted right after.

TimerTask Application Design issue

I am working on java TimerTask Scheduler Application. I have main class as Service which is running as Scheduler.
I have TaskSchedule() extends TimerTask class which is used for fixed time execution as:
timer.scheduleAtFixedRate(new TaskSchedule(), ...)
Inside constructor for TaskSchedule I have a dataHelper class which interacts with database for fetching and updating values from database.
In the TaskSchedule class I am overriding run method of TimerTask.
And inside the run method I am calling database helper call with parameters as:
#Override
public void run(){
dataHelper.fetchDataFromDB( ? )
}
Here the question I have placed, where I am stuck in design. I want to keep this parameter to database dynamic.
One Solution I though of is:
Passing database parameter throughout from service to TaskScheduler to dataHelper. But I am looking for better solution on the same at design level.
You can use a shared variable, which you can set outside and also take is before "fetchDataFromDB". You have to care of synchronization. Use a mutex to secure the shared memory.
A another solution is, that you can use somethink like a listener and every time you want to fetch from the db the listener will now it and get the data from you.

What context instance to pass to non-activity constructors from an Activity?

Several classes in Android API require a Context parameter in their constructor, for example ArrayAdapter, SQLiteOpenHelper or Intent. When creating such an object from inside an Activity, what context instance is more appropriate to pass to them: this (the activity instance itself) or the object returned by the activity's getApplicationContext() method and why?
Up to now, I have used both and didn't see any difference in the resulting functionality. Is there any rule of thumb?
From the docs of getApplicationContext() method:
Return the context of the single, global Application object of the
current process. This generally should only be used if you need a
Context whose lifecycle is separate from the current context, that is
tied to the lifetime of the process rather than the current component.
Consider for example how this interacts with {# #registerReceiver(BroadcastReceiver, IntentFilter)}:
If used from an Activity context, the receiver is being registered
within that activity. This means that you are expected to unregister
before the activity is done being destroyed; in fact if you do not do
so, the framework will clean up your leaked registration as it removes
the activity and log an error. Thus, if you use the Activity context
to register a receiver that is static (global to the process, not
associated with an Activity instance) then that registration will be
removed on you at whatever point the activity you used is destroyed.
If used from the Context returned here, the receiver is being
registered with the global state associated with your application.
Thus it will never be unregistered for you. This is necessary if the
receiver is associated with static data, not a particular component.
However using the ApplicationContext elsewhere can easily lead to
serious leaks if you forget to unregister, unbind, etc.

Long-lasting reference to an Activity - Lifecycle

Say that I have a singleton class (Downloader) responsible for downloading and persisting files. When a client requests a download, he must also provide a callback. My question regards the storage of those callback objects.
If I have an Activity that implements the callback interface and then requests multiple large downloads, the Downloader class will hold a reference to the Activity indefinitely. What if before the downloads are finished the Activity that requested them goes through its life-cycle and is destroyed.
In this case the Downloader will prevent the recycler from garbage collecting the Activity. I don't mind that the requested downloads continue. What I would like to do however, is somehow detect that the callback provided should be collected and I am effectively leaking it.
Is there a design pattern for something like this? I was thinking that one of the Reference subclasses would be useful.
Thanks.
Do it the other way around and you can keep them disconnected and avoid the highly unrecommended practice of keeping activity references around.
I created a very simple ServiceLocator class that keeps static references to all of my singletons and resolves them by type, but you can do this even simpler. You just need a class that holds a static reference to your Downloader and exposes that reference to your activities. If you need to call back into any of your activities, use the publish/subscribe model that the Android framework does (i.e. setOnClickListener(OnClickListener listener)).
Downloader can have an inner interface called DownloadUpdateListener, a single instance of this interface, and a register and unregister method for setting this and removing the reference from your activities. The Activity will create an instance of it DownloadUpdateListener locally so it has access to all of the Activity's fields and views. In Downloader, check that your listener isn't null before calling its methods. Register your listener in onResume and don't forget to unregister it in onPause

Categories