The work flow of my program is:
Launch app
Splash screen, check the server api, from the api get a list of file name
Download some of the file in file list , remove the downloaded file name from the list
App opened
when the download is finished , jump to main page that will start download another file in the list
The problem is , the list I was keep in the download manager , when I select don't leave activities in android setting , it will be killed. If I need a class that is some Data Class , that means I put a share data (A several hash map , array list) in it, and it keep updating (delete after async download finish) , and it never get killed. How can it be done? Thanks
The more general problem you are encountering is how to save state across several Activities and all parts of your application. A static variable (for instance, a singleton) is a common Java way of achieving this. I have found however, that a more elegant way in Android is to associate your state with the Application context. As you know, each Activity is also a Context, which is information about its execution environment in the broadest sense. Your application also has a context, and Android guarantees that it will exist as a single instance across your application. The way to do this is to create your own subclass of android.app.Application, and then specify that class in the application tag in your manifest. Now Android will automatically create an instance of that class and make it available for your entire application. You can access it from any context using the Context.getApplicationContext() method (Activity also provides a method getApplication() which has the exact same effect):
class MyApp extends Application {
private String myState;
public String getState() {
return myState;
}
public void setState(String s) {
myState = s;
}
}
class Blah extends Activity {
#Override public void onCreate(Bundle b) {
...
MyApp appState = ((MyApp) getApplicationContext());
String state = appState.getState();
...
}
}
This has essentially the same effect as using a static variable or singleton, but integrates quite well into the existing Android framework. Note that this will not work across processes (should your app be one of the rare ones that has multiple processes).
Related
I'm part of an Android project that uses a global class that contains public static variables, like the example below:
public class Globals {
public static MyObject variable = "this is a test";
}
In the middle of using the application, this global variable's value will be changed let's say:
#Override
public void onCreate(Bundle savedInstanceState) {
Globals.variable = new MyObject(somethingHere);
}
And I came across using Headless Retained Fragments from these blog posts:
http://www.androiddesignpatterns.com/2013/04/retaining-objects-across-config-changes.html
http://www.vogella.com/tutorials/AndroidFragments/article.html#headlessfragments
Problem:
I need to have a reference of an initialized object all over the application.
Question:
which is better to implement, a good practice, and practical? Or is there another way I could store a reference of an object all over the application?
The global class has been used over the project, and works fine, but are there any downsides of this implementation?
are there any downsides of this implementation?
Memory leaks, depending on what you are storing there. Leaks are why static data members are considered poor form in classic Java, even if we tend to use them more in Android app development.
Also, this data needs to be considered a cache, one that has to be able to be lazy-created on first access. Your process can be terminated at any point (wiping out the static data member) and the user can return to any activity in your app (courtesy of the recent-tasks list). If you want this data to survive process termination, the most likely solution will be to persist it in a file, database, or SharedPreferences.
All that being said, a retained fragment is a per-activity solution, not a per-application solution, and so it is not a valid alternative for your scenario AFAICT.
I am looking for how to share functions and data across multiple activities within a single application. I researched the daylights out of it and find some ideology war between overriding the extend for the application and doing a singleton, neither of which I can find examples sufficient to make me understand. Basically I want to share data and share functions. All activities need the same functions and data so this is not one activity sharing data with another activity. It is all activities needing to have access to the same functions and data.
What I want to know is what is the way to go and how do I do it. I need to see what I need to do in my 34 activities, what the class that is going to be common looks like, and what the Manifest entry needs to be. I also need to be sure the common data area will not be closed by the OS.
This is my first Android - Java program and now find my 15,000 line, 34 activity application needs some structure. I know, should have done things differently but the app works really well with two exceptions. One is that it is structurally a mess. Two is that the fact it is a mess is making it hard to fix one behavior I would like to fix.
This is a GPS based application for racing sailboats. It is timing critical and every activity basically runs a once a second loop inside the location manager onLocationChanged function. That part is fine and I do not want to put the GPS code in one place. The problem is that most activities need to filter the data so a lot of code is copied and pasted to the activities. The filter needs history so it needs to remember a state. There are other functions that are used by several activities so these have been copied as well. Think of a function that averages the last three GPS speed readings. It needs to save some history, do its thing, and give a result. All activities need to do the exact same thing. All this works but the problem is that the averaging starts over every time I switch activities because every activity has its own filter. That gives a glitch in the data that I need to get rid of. I need common place to save the data and hopefully a common place to run the filtering and other functions that are common. If every activity can call the filter function that is using common state data, there will be no glitch across activity changes.
I would appreciate some guidance.
Why you don't just make a Class with only static functions, passing needed Parameters? An example if you want to show an ErrorDialog
public class SharedHelper{
public static Dialog showErrorDialog(Context ctx, String message, String title, DialogInterface.OnClickListener okListener, DialogInterface.OnClickListener cancelListener){
AlertDialog.Builder builder = new AlertDialog.Builder(ctx);
builder.setMessage(message).setTitle(tilte);
if (okListener != null){
builder.setPositiveButton(R.string.button_positive, okListener);
}
if (cancelListener != null){
builder.setNegativeButton(R.string.button_negative, cancelListener);
}
return builder.show();
}
}
Singletons are (from my point of view) one of the uglyest design pattern and will bite you sooner or later. Putting anything in Application requires you to cast it everytime to the Special Application class you designed. A class with only statics however is very flexible in its usage and doesn't need an instance to work.
For the storage-issue:
lookup "SharedPreferences" & "SQLite" and decide afterwards which storage-type suits your needs more.
For the methods-issue:
This question is a bit more complex and there are different ways to do it. For example you could write a parent-class that implements all your globally needed questions and you let all your activity-classes inherit from it.
public class MyParentActivity extends Activity {
public void myMethod() {
}
}
and:
public class Activity1of34 extends MyParentActivity {
myMethod();
}
I think what this comes down to is not an Android problem but an Object-Oriented Programming problem. If I understand the situation correctly, I'm betting the best solution would be to take your shared filter and create a new Filter class that is instantiated within each Activity (this is likely more manageable than a singleton, but not having seen your use case, it's hard to say for sure). If you need to centrally track the averaging, you can simply create a static variable within the Filter class that maintains the same value during the life of the application. If you really want to maintain that average (even past the application's current lifecycle), you can persist it in a database or other local data options. However, I don't see any reason to put everything in a singleton just to maintain that average. Singletons (and all static data structures) can be potentially troublesome if used incorrectly.
I, for one, do not mind the singleton pattern. Of course as everything else it should not be abused.
This is the construction I use for my shared objects. My app is divided into modules this way but can just as well be used in your case.
public class SharedDataObject {
private Context context;
private static SharedDataObject instance;
public static SharedDataObject getInstance() {
if (instance == null) throw new RuntimeException("Reference to SharedDataObject was null");
return instance;
}
public static SharedDataObject createInstance(Context context) {
if (instance != null) {
return instance;
}
return instance = new SharedDataObject(context.getApplicationContext());
}
// notice the constructor is private
private SharedDataObject(Context context) {
this.context = context;
}
...
public void myMethod() {
// do stuff
}
}
Notice that it uses the application context, that means among other things, means that the context owned by SharedDataObject cannot be used for GUI operations. But, the context will live for the entire lifetime of the application, which is nice.
Furthermore I hate having to pass a context everytime I wish to call methods on my SharedDataObject, thus I have a splashscreen calling SharedDataObject.createInstance() on all my modules.
Once an instance is create, I can call:
SharedDataObject.getInstance().myMethod();
Anywhere in my code, regardless of a context being present or not (from the place calling this code that is).
I am from an Android background and am progressing into Windows Phone 8.
I have a Page that uses the camera to decode a QR code and this works fine. In Android I would start this Activity using the Intent StartActivityForResult, which would then give me the decoded value back to the original Activity.
I have searched but could not find an obvious equivalent in Windows Phone 8. My thought at the moment is to navigate to the calling page with a query string containing the decoded value and alter the back stack, but this seems a little messy.
The Question
Is there an equivalent to the process in android, and if so can someone outline the methodology so I may see it in action?
First, there's no such thing in WP8, so you'll need a workaround. Workarounds could be different, and the linked question (and answer) is one of the potential approaches. I personally do this a bit differently. I'll describe my current project's architecture here, though it may not be applicable to your situation, since my app is quite big and has a complex structure. But I'll try to explain how it could be applied to your situation.
Particularly, my current app consists of so called services (just my name, not a standard one). Those have different scope (some are used by 1 page, some are global for the app), different lifetime, and so on. Essentially, every service is a class implementing a well-defined interface, so that other services could use that.
Next, services could depend on each other. I'm using Ninject framework for dependency injection. Essentially, if service A depends on service B, it leads to a code like this:
public class B : IB
{
...
}
public class A
{
IB b;
public A(IB b)
{
this.b = b;
}
}
where IB is an interface, which service B implements.
Then I have view models (yes, I'm using MVVM and you probably should too, if you want to build a reasonably big WP8 app). View models are using services to perform app functions. Some of the services are used by several view models. For example, I have one service that fetches some data from the web, and keep it up to date with periodic polling. That web data is used in several pages of the application, so it should be shared between different view models. It is achieved by dependency injection again, so that all interested view models accept this service instance as a constructor parameter.
public class MainPageViewModel : INotifyPropertChanged
{
private string webData;
public MainPageViewModel(IWebDataService service)
{
webData = service.CurrentWebData;
service.WebDataChanged += (o, e) => webData = service.CurrentWebData;
}
...
}
public class DetailPageViewModel : INotifyPropertChanged
{
private string webData;
public DetailPageViewModel(IWebDataService service)
{
webData = service.CurrentWebData;
service.WebDataChanged += (o, e) => webData = service.CurrentWebData;
}
...
}
public class WebDataService : IWebDataService
{
public string CurrentWebData;
public event EventHandler WebDataUpdated;
...
}
Ninject allows me to have a single instance of IWebDataService instantiated, so that main and details page share the same instance of it. When the web data is updated, an event is fired, so that both view models can update their instances of web data, and push this new data to the views.
So here's how I do it. You could potentially reuse some part of this architecture, like having a singleton instance of some class accessible by different pages. One page puts some new data to that singleton instance, and, when data is updated (event fired or during construction, if garbage collector had enough time to kill existing page and/or view model instance), another page reads the updated data. That's how they share.
If you want me to go deeper into details on some topic, please feel free to ask in comments. Android developers are more than welcomed to the Windows Phone. :)
I've been stumped with this for a while now.
I'm working on an android app that stores a person's fish catches, favorite fishing locations, tackle box inventory and other data. All my classes are Serializable and can saved and loaded between activities which seems to work thus far. But I'm predicting as more and more data is stored, the app will start running slow.
What I'm basically asking is there any way to retain this data throughout the entire application, so I don't have to load it every time a new screen pops up. I've already found the following information to help but it needs to be a little more clear for me to understand:
Another forum said you could stuff it in the Application object:
[Application]
public class MyApp : Android.App.Application {
public MyApp(IntPtr handle)
: base (handle)
{
}
public FishingData Data {get; set;}
}
Then within your Activity:
((MyApp) this.ApplicationContext).Data = value;
So I've never really heard of doing this approach before and I'm not sure this will live through the entire application process (I feel like either way it's going to have to load the data via serialization. Here's what I want the app todo:
The first activity is the main menu and the following must be done when the screen loads:
If a settings file is found, use serialization to load a previous FishingData object (I know how to do this)
If not, then create a new clean FishingData object to save later (I know this as well)
So now that we have a FishingData object, how do I ensure that I don't have to repeat steps 1-2 in every activity. How can I somehow pass the FishingData object to the next activity and ensure that it lives globaly while the app is still living. I only want to load it once (via serializing) (<--Don't know how to do this) and save it only when a user adds data to this object (which I know how to do).
Any help will be appreciated. This is bugging me I cant seem to figure this out. This seems like it would be a common thing to do but I haven't had any luck finding any detailed information.
Here is how I would pass my data around the app via parcelable. Lets say you have a class named Fisherman (for a user basically)
public class Fisherman implements Parcelable {
private String name;
private Tacklebox box;
public int describeContents() {
return 0;
}
public void writeToParcel(Parcel out, int flags) {
out.writeString(name);
out.writeParcelable(box, 0);
}
public static final Parcelable.Creator<Fisherman> CREATOR
= new Parcelable.Creator<Fisherman>() {
public Fisherman createFromParcel(Parcel in) {
return new Fisherman(in);
}
public Fisherman[] newArray(int size) {
return new Fisherman[size];
}
};
private Fisherman(Parcel in) {
name = in.readString();
box = in.readParcelable(com.fisher.Tacklebox);
}
}
In this example, you define parcelable for each data model you have. So say you have a fisherman object, that contains another object called tacklebox. You will also define this for tacklebox, and so on if you continue to nest models. This way, all you need to do to pass data between activities is
Intent intent = new Intent(this, Activity.class);
intent.putParcelableExtra("com.fisher.Fisherman", fisherman);
and read
Bundle b = getIntent().getExtras();
Fisherman fisher = b.getParcelable("com.fisher.Fisherman");
This unfortunetly answers only step 3 of your problem, but I suggest breaking each one of your 3 steps into its own question because what your trying to do is slightly more lengthy than one question
You can use this approach, it will live as long as your Application object is alive (Which means it will live through your entire application and activities). You can read more about using global variables stored in the Application object here. I don't think mono would make a difference which will prevent you from using this approach.
Can anyone enlighten me about the safety of a class holding global values in Android?
Here's a short example of what I mean:
public class Globals {
public static int someVariable = 0;
public static User currentUser = null;
public static Handler onLogin = null;
}
Then somewhere in an Activity I do the following:
Globals.someVariable = 42;
Globals.currentUser = new User("John", "Doe");
I have to rely on Globals.currentUser at multiple places in my app as soon as the user is logged in, but I'm unsure if I should do it, and also if I could use a Handler like this.
I read everywhere that an Android app could be killed anytime, does this mean it is killed completely or maybe just a part of it, thus killing my Globals class only?
Or is there any other way to store globally available data in a safe way, without writing every member change to the database (in fact, my User class is a little more complex than in this example. ;-)
Thanks for your effort!
Edit: Ok, here's what I finally did:
public class MyApp extends Application {
private static MyApp _instance;
public MyApp() {
super();
_instance = this;
}
public static MyApp getContext() {
return _instance;
}
....
private User _user = null;
public User getUser() {
if (_user == null) _user = new User();
return _user;
}
}
Then modify the AndroidManifest.xml and add android:name=".MyApp" to your application node to tell the app to use your subclass.
So far everything works fine and I can easily access the current Context (f.ex. in SQLiteOpenHelper) by calling MyApp.getContext().
It would be better to use the Android Application class. It's meant to store global application state
http://developer.android.com/reference/android/app/Application.html
Just create a subclass and make sure to update your manifest file to use your version. Then you can store whatever you need to in it. Activities have a method getApplication() which you can cast to your class to access your implementation
The pattern is discouraged--you will run into problems when unit testing.
Can you explain how you unit-test a class that must supply different custom "Users" here? You are either forcing a mock/fake class into "User" which will probably have a cross-effect on other tests or you are putting an if(test) into your code which gets ugly quick.
Over time populating this class artificially for testing gets more complex and starts to have relationships and dependencies.
More simply it makes it difficult to unit test a class in isolation.
It's one of those patterns that a given programmer either doesn't see a problem with or never uses because he's been burnt--you'll see little middle ground.