Hoping someone can assist with this what seems to me a peculiar problem.. My mind is pulsing a little here as it's blown my understanding of the Android Activity Lifecycle.. Let me try to make things clearer.
Problem: I'm receiving a 'StaleDataException' during the 'getView' method of a custom adapter (extending BaseAdapter) that I use on an activity to populate a GridView. Sounds straight forward so far.. When I first go into the activity, the adapter is working as expected and the grid is populated.
I have a button on the activity which fires off an Intent to allow the user to take a photo, and comes back via 'onActivityResult' saving the image to a database. This all worked also. In fact I wrote that portion first, then added the adapter & gridview afterwards.
Now the StaleDataException is occuring when I've gone to the camera to take a pic, and then click OK to return... I have lots of Log statements in most events on my activity, and very bizarrely the StaleDataException is occuring before ANY of these events are triggered... before OnActivityResult/OnResume etc.
SO I'm quite confused as to why the Adapter is being accessed before I've properly returned to my activity and before onActivityResult/OnResume have been called..
Debugging the steps that lead up to the exception, it all occurs on this line :
String contentType = dataCursor.getString(dataCursor.getColumnIndexOrThrow(DbStatics.ACCIDENTS_MEDIA_KEY_TYPE));
What's also baffling me is the dataCursor is actually Open and the first call (getColumnIndexOrThrow) is also returning a value.. so its the getString() which leads to the exception.
So I hope that's clear enough... and really really hope someone might be able to shed some light on what's going on..
Many Thanks,
I recently encountered exactly the same problem in almost exactly the same scenario.
(I'm using a Gallery rather than a GridView)
In my case, my code worked fine for months - until I recently updated my N1 to 2.3.
My solution (after much brain pulsing of my own) was to not call startManagingCursor on the cursor I pass in to my adapter.
Instead, I manage the cursor myself.
That seemed to clear the problem up for me....though I couldn't tell you why...maybe someone more experienced can shed some light.
Hope this helps you.
Related
I have a list of orders in one fragment. In a second fragment, I display the detail of the order, and I use a third fragment to display the buttons that change the status of the order.
In the list, each order is displayed with a background color that indicates its status, for example green for a completed delivery.
When in landscape mode, both the detail and list are shown. In portrait mode I use two separate activities.
This all works fine, up until I change the status of an order. I can't find a way to get the list to update.
As I understand it, what needs to happen is the adapter needs to have its notifyDateChanged() method called. I've tried calling it directly from the method that processes the button click, I've tried an asynctask, and I've tried a handler. My debug methods show that the call is happening, but the list doesn't get updated.
It's possible I'm doing something completely bone-headed, but I've double and triple checked things. I suspect there is some key element I don't understand. I hope someone else does and will tell me what I'm missing.
I had some code posted, but it was clearly wrong. Not sure what code to post, since I think this is more a conceptual than coding issue.
If you want to update a view, try to use :
Thread + Handler
AsyncTask
What I discovered, through the helpful comments of other posters, is that my problem wasn't that the adapter wasn't getting the notifyDataChanged() call on the correct thread. I put in debug code that proved that. The problem was that the background of the listview item was based on a change in the underlying data itself, so the real answer was to get the Adapter to refresh the Cursor. I made some changes. I modified the AsyncTask I was using to notify the adapter. Now the AsyncTask gets a new cursor and calls adapter.changeCursor(cursor) with the result. The AsyncTask is called from the MainActivity (which hosts both the list and detail fragments) when the status is changed. It's also called in the onResume() portion of the ListFragment code, so the list will be updated properly when coming back from the detail fragment. Works great.
A strange behavior I'm tearing my eyes on since early this afternoon, I'm givin up understanding but perhaps someone has an idea (yeah, I'm a beginner, some PROBABLY has an idea ^^).
Situation :
MainActivity.java (first one to be called, only one of interest here)
public ExpandableListView listClubs;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listClubs = (ExpandableListView) findViewById(R.id.expLstMainClubs);
AppGlobal.CreateDistricts() ;
ELVAdapterDistrictsClubs adapter = new ELVAdapterDistrictsClubs(this);
listClubs.setAdapter(adapter);
}
it's the only code in the class. Basically, I'm filling an ExpandableList with an adapter that relies on what's created in the CreateDistricts() method (creates business objects, Districts containing Clubs containing Members, Events, etc.).
Basically (again ^^), everything runs fine, on first start the ExpList works as expected, as well as the rest of the app. If I hit the back button from the MainActivity, however, and rerun the app, a "strange" (to me at least) behavior occurs :
The ExpList is loaded twice in a row - first one with the data, works fine, and just below a duplicate (with the same 2 Groups, i.e. here the only two Districts in my sample data), which doesn't work at all (if you try to expand it, it crashes the app).
Frankly, I'm lost - I've tried some things on the various on[Pause/Stop/Destroy/Start/Resume] etc. to no avail (therefore, there is yet nothing done on this side, no override, as it seems not to bring anything good).
As the onCreate will after the onDestroy load the bundle, it should load the ExpList as it were, and in this case there might be a conflict between the "old" groups/children and the actual ones (currently, data is simulated, but will afterward come from a remote data source), and I haven't decided yet what the best "save" behavior is, i.e. if I should find a way to obliterate the ExpList onDestroy in order to be sure it's 100% recreated anew (and how does one do that ?) and start from scratch, or if I could use the ExpList as is, while updating it's content, in order not to lose the previous selection. It may be irrelevant to complicate matters in order to do that, the first list being not so big and quite quickly used to reach the second activity...
Anyway, I suspect it comes from around that part, the bundle load after destroy and rerunning, does it reload the ExpList as is and then I add things instead of first deleting ? What I found confusing is that the next activity (reached simply by clicking one of the items of the ExpList) displays a similar ExpList (filled with Months and Events per Month for the selected Club), and doesn't present the same strange behavior after a destroy... and both have an almost identical ExpList declaration in their original xml layout so... well, perhaps tomorrow morning I'll see the light, but if anyone has an idea, feel free :D
The more I write, the more I think I should first clear the ExpList but... I don't see how exactly. I've tried
listClubs.removeViewsInLayout(0, listClubs.getCount()) ;
but it just doesn't seem to do anything.
Thanks in advance
Nothing related to Android behavior - I was recreating everytime the whole set of BO behind if the base ArrayList of Districts was not null... instead of simply getting out of the method, but it raises another question - how was the state of this ArrayList, which is declared in a subclass of Application serving as Application in my manifest ? I'll have to make some tests about that...
Im just coding the Android application which I thought of in order to learn the SDK a little more and ran into a problem when trying my program with the emulator. The application installs normally and then closes only to give me a logcat saying theres a NullPointerException in the main class. I cant manage to find it anywhere and research says that theres an object being used without it being initialized? I dont think this is possible as if it were the case, Eclipse would give me an error, but in this case it is a runtime exception. I do not have a lot of programming experience especially in Android and this bug is stopping me from seeing if the rest of my program works!
Heres the Source
and heres the Logcat
Thanks in advance for any help
The error occurs on line 80 in your onCreate method in IOweYou.java. You can see it on line 19 in the stacktrace you posted.
08-03 07:11:35.068: E/AndroidRuntime(681): at com.andrei.iou.IOweYou.onCreate(IOweYou.java:80)
Is localEL properly defined?
EDIT:
make your activity extend ExpandableListActivity instead of activity. Then remove setContentView. And change
localEl.setListAdapter(mAdapter);
to
this.setListAdapter(mAdapter);
and your list will show. However clicking on the item will still make it crash but its a start!
EDIT2:
here is an example I found.
http://smartandroidians.blogspot.com.es/2010/04/expandablelistactivity-in-android.html
I think the problem is that your ExpandableListActivity localEl has been created but not launched. When you call localEL.setListAdapter(mAdapter); it internally calls its setContentView, as is shown in the log. Probably getWindow() returns null because the activity has not yet been initalized.
Without knowing much of what you want to do, perhaps your activity should instead inherit from ExpandableListActivity?
So after a while of programming android apps(1 uploaded on market, have 3k+ active installs with a 4,7 rating), I started to wonder, how can I make my app even more awesome. I realized, that I couldnt really add any really new, and world changing features, so I started to inspect the performance, and how to optimize just about everything, how to find the best cpu/memory usage ratio, and so on.
Anyway, I found out that onCreate will run in the case of rotating the screen, which is quite logic, but there are some(big) calculations, that I surely dont need to redo after every rotate. One of this is iterating through a csv with 6500 rows, having 4 columns, 2 of it always contains some data, 2 of it not always. The 2 column with datas will be used for autocomplete adapter, the another 2 is optional for a feature, but it still need to be initialized. Currently, this is running in an asynctask, triggered at the end of the onCreate, and takes about 3 seconds on my HTC Desire S, which has a quite good CPU, so lower budget devices will have a longer initialize time after every rotate which is surely not I want... It wont crash the UI, but there won't be any autocomplete until thoose seconds are over.
SO: my question is, can I do this in some separate method, for example a constructor(like in standard java), or is it a bad practise, because the special lifecycle of activities? I mean, I instantiate my activity the way the "constructor" will run, and just after that, my onCreate will run. In case of rotating, my "constructor" won't run again, but the onCreate will. Stability will still be my nr1 goal. Or, is there any good way to do this? Something that is created for exactly like this, which im unaware of? I really want to improve a lot in this matter, and I would really appreciate some help in this, preferrably from ones with experience in this, but any help is welcome! :)
For example, if I want to make a new activity this way, I would do it something like this:
new MyActivity(some parameters);
so the constructor runs, which ends something like this:
startActivity(new Intent(context, MyActivity.class));
So this way, the constructor runs, my variables will be initalized(not connecting to any view etc), and after that, my activity can run its onCreate variable anytime it has to.
Pardon me if Im wrong the syntax, I just fasttyped it :)
You should decouple this logic from your activity. There are many ways to do this, but the end goal is to have your csv parsing done in a different class, and this class should expose information about whether or not the data has already been parsed. So, in onCreate, you call your class to get the data. If it already exists, you get your cached data immediately. If this is the first time the method is called or for some reason your cache has been cleaned up, you parse your csv file and do whatever calculations you need.
you could take a look at onRetainNonConfigurationInstance which can return an object which you can access after your activity has been recreated.. so you would simply return an object containing all your processed results of onCreate and the next time around you check if there is a getLastNonConfigurationInstance() - and don't recalculate everything
I don't think my future lies in Android development, as I am consistently failing at the simplest things...
I've got a button with the label "Game Slot 1". When the user clicks it, I succesfully take them through a couple of activities in which they create a new character. I save the game name in an SQLite database, and the next time I launch my app, I can quite happily dynamically change "Game Slot 1" to the name of that slot's game from the database. Perfect.
But how on earth do I get it to update the view in the same manner when I return to that activity via the back button, or having called finish() on all the subsequent activities?
I'm sure it's something to do with onResume(), and maybe invalidate(), but I just can't seem to find an example.
Is invalidate overkill just to refresh a few UI elements onResume()?
How the heck do you use it, anyway, even if it is?
Is there a better way?
Many thanks in advance for any help offered...just try not to laugh at how simple this probably is! :)
Cheers,
James
That sounds like something you could do in onResume, just query the database and call setText on the element of interest. You should not need to explicitly call invalidate.