I have a static class which extends android.app.Application (HireApplication) which is doing a lot of my background work. I create AsyncTasks here, I store the largest data objects that my application uses. I'm writing this code in the Application class so that I can reuse it between separate activities for Phones and Tablets.
This feels like the right way to layout my app, but now I have a problem. An AsyncTask has finished and needs to run notifyDataSetChanged on an ArrayAdapter within a Fragment (ListFragment).
Here is my solution:
ListFragment:
public void onCreate (Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
myListAdapter = new MyListAdapter(getActivity(), HireApplication.myList);
HireApplication.myListAdapter = myListAdapter; // Tell the application where the ListView is so that it can notifyDataSetChanged
}
HireApplication:
public static ArrayAdapter<BikeStation> stationListAdapter = null;
private static void asyncTaskCompleteCallback() {
{...}
myListAdapter.notifyDataSetChanged();
}
Now, this works... but it doesn't feel right. I am giving the Application a reference back to a UI element which sounds like it's a bit tightly coupled, but I don't know a better way to do this.
Is there a better way of my Application notifying my ArrayAdapter or Fragment that it should take some action to update the UI with fresh data?
Cheers.
The whole thing looks wrong to me... if you are using fragments and adapters, you should be using LoadManager instead of AsyncTasks. Also, putting everything on your Application looks like a poor solution to the problem you want to solve; it will lead to posible memory leaks and does not feel right.
Related
While I was coding, I wanted to use findViewById method to find a view that cant access in the current view but can be accessed via the MainActivity. So two options came to my mind. One is creating a static method from that object in the MainActivity class and access the static object. The second method is to create a static object form MainActivity class itself(this) and access the findViewById method by calling the static object. Please answer the method I should use.
And apart from that, it got me thinking that whether an Android developer should come across this type of scenario or whether I have done some improper coding to access findViewById method in MainActivity while I was in a different view.
You can take a look at the code in the below repo.
https://github.com/chrish2015/ExpenseTrackerLatest
Thanks
If you are inside a class that is neither a Context nor an Activity and you need to use a method which exists inside the activity or context, then simply pass the activity as a parameter to that class and take an instance to that activity inside your class.
public class MyAdapter extends ArrayAdapter { // this is not activity
private Activity mActivity; // activity is a member of this class.
public MyAdapter(Activity activity, List<String> data) {
mActivity = activity;
}
public View getView(...) {
// if you need to use findViewById:
View view = mActivity.findViewById(R.id.some_id);
}
}
Don't use any of your two methods.
I might be misunderstanding your first sentence, but just to be sure, are you asking for a way to access a View that exists in the MainActivity, while you're inside of a Fragment?
If that's what you're asking, then yes, as an Android Developer, there will definitely be moments where we come across this scenario. However, the solution is definitely NOT by making your Views or Context static.
This is one of the easiest ways to cause bugs to appear throughout your app, with a very high chance to cause memory leaks too. Here's an Article from Google talking about memory leaks related to keeping a reference to a Context: https://android-developers.googleblog.com/2009/01/avoiding-memory-leaks.html
Rather than your two options, there are better solutions that developers typically use.
First of all, keep in mind that you should NOT be directly accessing any Views from outside of your current layout... meaning, that if you're in a second Activity, you don't directly access Views from the first Activity, or if you're in a Fragment, you don't directly access Views that belong to it's FragmentActivity.
Instead, you let the Activity or Fragment handle it's own Views.
So for example, if you're in another Activity and you want to update some data in the previous Activity, you can take advantage of an Activity's startActivityForResult() and onActivityResult() to obtain the data necessary to update the Activity immediately upon returning to the app.
For Fragments, there's actually a tutorial from the Android Documentation that describes a very good way to communicate between other Fragments: https://developer.android.com/training/basics/fragments/communicating
This method is to use interfaces as a callbacks, so another Fragment or the Activity will be able to receive data and update it's Views within it's own layout.
So for your case, if you're using Fragments and an Activity, you can easily have your fragments and activities communicate to each other in a safer and more reliable way.
Also, make sure you read up more on static and it's effects on your code, especially the side effects on Android components. Do not carelessly use static without considering some of the effects it might cause, because that would cause an endless amount of trouble to your code.
I am a newbie to android. My question is not about how to do something, but more on the idea I have in mind is optimized or not.
I am creating a Chat App. The biggest issue I was facing was storing Non persistent data, coz whenever the activity closed, all data was lost. The biggest problem was when user moved from Chat Screen (Chat Activity) to Peoples List (Peoples Activity) all data was lost again, and if user reinitited chat, he couldnt see the history.
As a workaround, I am creating a few data classes, and a service. The service stores data in the classes, whenever it receives an update from activity or the server. After that on each new activity I will just pass around this object from one activity to another and service.
I would like some recommendations in this, Is this a good way to go around? Thanks for your precious time.
If I've understood properly, you need a way to store data of variables or the content of one data structure or whatever and don't lose this data when your app change across severals activities, right? You need save state across several Activities.
First solution: in Java, one solution for this problem could be to use "static" variables. You can do it but using Android, we can use a more elegant solution.
Second and recommended solution: Associate the state with the Application Context (easy)
You should create your own subclass of android.app.Application. It will work like a singleton.
One subclass of Application inherit the properties of Application and you can access to this class wherever you want using the command "Context.getApplicationContext()". Normally you will use this class to have everthing that need a global access. Example:
class YourName_App extends Application {
private ArrayList<String> chatConversation;
public String getChatConversation(){
return this.chatConversation;
}
public void setChatConversation(ArrayList<String> chat){
this.chatConversation = chat;
}
}
And now your Chat Activity:
class Chat extends Activity {
ArrayList<String> conversation;
#Override
public void onCreate(Bundle b)
{
...
YourName_App appState = ((YourName_App) getApplicationContext());
conversation = appState.getChatConversation();
...
}
}
It is done! This is the best way to do it.
Sorry for my poor english.
I have a very simple Activity:
public class A extends ListActivity implements ListAdapter
{
#Override public void onCreate(Bundle b)
{
super.onCreate(b);
setListAdapter(this); //no problems without this line
}
// etc... (empty implementation ListAdapter interface functions)
}
When I start this Activity from other activity:
startActivity(new Intent(this, A.class));
and bush "back" button (to destroy this activity), the heap grows up about 13..15 kbytes and doesn't reduce back even after GC works out.
When I start and finish this activity again, the head grows up more and more.
To monitor the heap size I use DDMS in Eclipse.
What am I doing wrong?
I would really urge you not to implement ListAdapter in the same class as your Activity. Its not a good programming practice and all the Android tutorials create separate classes as adapters. They certainly do not merge the adapter and activity into one class. For example consider the GridView tutorial as an example of my point.
The problem lies where you say setListAdapter(this) in my opinion. "this" refers to the ListActivity class A, which is not an adapter by any means. for the correct use of setListAdapter you should pass either an ArrayAdapter or create your own Adapter class (which implements ListAdapter, and extend BaseAdapter) and instantiate it.
I think this may solve your problem, as your setting the adapter of the view to the activity itself, which seems recursive or a kind of "infinite loop" in some nature.
Do you cache views inside getView() method of ListAdapter implementation? If the answer is yes then caching may be a reason of memory leaks. For example leaks can happen because of using static members or View.setTag(int, Object) for storing views.
Anyway I recommend you to install MAT Plugin, start and finish this activity for 5-10 times and analyze heap. After that you'll be able to see leaked objects and root of leaked object hierarchies.
I am working on an Application that require some interaction between two activities, and I am not sure of what is the best way to achieve it:
One of the Activities is a "Logbook" (Just a ListView that displays a bunch of events).
The other Activity allows the user to create the events, that will be sent (and displayed in the Logbook).
How do I notify my Logbook Activity when a new Event is ready to be added?
Also, where should I add the event to the database? From the Logbook Activity, when I add it to the ListView, or from the NewEvents Activity, as soon as it's ready?
Thanks!
Ok, I found how to do it, using a BroadcastReceiver:
In my Logbook activity, I just set up a new custom receiver onCreate():
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_logbook);
registerReceiver(new EventReceiver(this), new IntentFilter("SEND_NEW_EVENT"));
Now, I can make the calls in my newEventActivity:
public void sendToLogbook(int eventId){
Intent i = new Intent("SEND_NEW_EVENT");
i.putExtra("newEvent", this.newEvents[eventId]);
sendBroadcast(i);
}
Of course, I had to create my CustomReceiver Class, and override the onReceive() method to do what I want:
public class EventReceiver extends BroadcastReceiver {
private ActivityLogbook activity;
public EventReceiver(ActivityLogbook activity) {
this.activity = activity;
}
public void onReceive(Context context, Intent i) {
this.activity.addToReport((Event)i.getParcelableExtra("newEvent"));
}
}
It works great so far, but if you do have comments/concerns about this, please tell me!
Thank you!
If I recall cporrectly the Notepad project which is included in the android sdk and is also part of the tutorials online is a good examaple which should satisfy your needs.
To borrow from MV-* (Model-View-something or other) patterns, separate your idea of the Model (in this case, your Event objects) and what is displaying them (the View, or in your case an Activity) and it'll become more clear.
If you have your events somewhere global where all activities can interact with them, then you can work with the model and display the model from wherever and however you choose.
One simple suggestion is have a class (EventController or something like that) that allows you to interact with the Events collection, and make it available through a derived Application class. I can explain further if that doesn't make sense. I have a pattern I use in my Android apps whereby all Activity classes have access to a custom global Application instance, so my model is a model and can be accessed by whatever Activities I want to have access.
This is merely one approach, and as always, there are many that may suit your needs.
One possibility would be:
The ListActivity gets all the data each time it is resumed and updates the ListView accordingly
The NewEventActivity does all the job of storing the Event and simply finishes
You can improve it a bit more:
The ListActivity gets all the data when it starts
The ListActivity starts the NewEventActivity expecting a OK/CANCELLED result
The NewEventActivity does all the job of storing the Event and returns a result saying OK or CANCELLED
Depending on the result it gets from the NewEventActivity, ListActivity reloads its data or not
The problem I am facing is stated below in code. I am trying to call a 'method' from another class, which is going good until it reaches a activity (like getListView() or getAssets())
Calling class:
public class Main extends Activity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Utils ut = new Utils();
ut.initiateMainMenu();
}
}
Called class (method: initiateMainMenu):
public class Utils extends ListActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initiateMainMenu();
}
public void initiateMainMenu() {
listView = getListView();
assetManager = getAssets();
etc...
}
}
In the example above a nullpointer occurs when the first class (Main) is started with an intent.
The nullpointer is given on the following lines depending on which line comes first:
listView = getListView();
assetManager = getAssets();
The same nullpointer does not occur when class Utils is directly intended.
I hope the above description is suffient for solving my problem.
Kind regards,
Conrad
If you are holding a list view in your main activity, instead of doing this, which seems really weird to me, add the list view to R.layout.main and extend your class from ListActivity. You can get rid of Utils, and have all the listview related code in Main.
Or maybe some more information about what you pretend to implement might help...
Ger
Well the solution is simple, Your context for Utils class is never initialized, i.e. Utils class's onCreate method is never called or is out of focus or due to some other reason your ListView is never initialized.
You could do following :
Inverse calls and hold handle for list, may be using static keyword.
Or may be try changing code to getApplicationContext.getListView() / Utils.this.getListView of your initiateMainMenu();
I dont know to what extend this would work, but the basic cause behind this issue is uninitialized listView resulting in NULL.
The difficulty I was facing was not entirely described because my Java knowledge was not sufficient for identifying it as a problem.
What I was doing was using three Activities that inherit from each other. Namely Activity, MenuActivity (my own extended one) and ListActivity. The quick and dirty solution I am now using is a duplicate class. One class holds MenuActivity extending Activity and the other holds MenuActivity extending ListActivity.