Good day,
I'm working on an application that will serve as a monitor of some sort for drivers. My client would like the application to work regardless of the orientation of the device.
I implemented the solution provided in the following article , and after fiddling a bit with the debugger, I can see that the Asynctask is still working. However, the TextViews and ImageViews it is supposed to work on are not working anymore.
Here is the code of my TaskFragment.
To clarify : The AsyncTask still receive and handle the elements correctly, but the elements of the layout are not updated anymore. I would like to know how I can keep them working.
I would suggest using an AsyncTaskLoader as those can re-attach to whatever lifecycle element you created it in relatively easily. See here: https://developer.android.com/reference/android/content/AsyncTaskLoader.html
It might seem pretty involved to implement at first, however if you read https://developer.android.com/guide/components/loaders.html, most of the weirdness should be cleared up.
TLDR: Using AsyncTaskLoader allows an easy way for your AsyncTask to be reattached to your fragment after it is destroyed and recreated. You just need to call getLoaderManager().initLoader(...) in the onCreate of your fragment.
Ok, so I found a (probably not very efficient) workaround, but a workaround nonetheless.
The problem was that, after an orientation change, since the Activity is destroyed and recreated, the variables batterymonitor, valuemonitor, etc, would not point towards the new objects created because of the layout/activity change.
As a solution, I am now using a findViewById each time I need to do an operation on the layout. This way, the id is permanently refreshed to keep up with the activity changes on a rotation of the device.
The ugly line I use to do so is :
batteryMonitor = (ImageView)getActivity().findViewById(R.id.batteryMonitor);
batteryMonitor.setImageResource(R.drawable.no_battery);
Related
From Activity lifecycle we know, that in onResume the UI is visible. But if I set a breakpoint on onResume, I still don't see it, only after that. I heard there's some method which can check it, but I can't remind how it calls. We used it to make better animation. So how can I be fully sured that UI is ready?
Add global layout listener on view you want to check. Also please make sure that you remove listener once your work is done else it will keep getting called multiple times.
#onik shared a good link that should solve your problem
This ensures lay-outing. Drawing happens continuously and frame are refreshed according to sys clock.
I recommend watching: https://www.youtube.com/watch?v=Q8m9sHdyXnE
This will give you good idea on android drawing and layouting
New to Android. Trying to understand the technical downside of a design.
I have an ItemSelectorView which has both an availableItems collection as well as a selectedItem property. The latter is displayed at runtime along with a chevron letting the user know they can change it.
Functionality-wise, it's similar to a spinner except rather than showing a pop-up with the choices, it launches a second activity called ItemSelectorActivity which shows all of the available items from the ItemSelectorView which launched it, as well as helpful information about what each option means as well as the ability to search and filter.
When a user selects one, their choice is then returned back to the originating ItemSelectorView via a trip through MainActivity's onActivityResult override. The override then figures out which ItemSelectorView it's responding to and forwards it along.
However, I really didn't like the way MainActivity had to insert itself into the process just to get the result from ItemSelectorActivity. Plus, if ItemSelectorView was used in a fragment, things become more complex trying to forward the information to the correct view.
Because of this, I instead changed ItemSelectorView to ItemSelectorFragment which can override its own onActivityResult making it, not its owning activity, responsible for updating itself with the selected result. This means it's essentially completely self-contained now.
While this seems to work wonderfully--with this change a user only needs to place the ItemSelectorFragment somewhere in their layout and set the available and selected items--a veteran Android developer here said using a fragment like that was wrong and I should have stayed with a view because of the overhead of fragments.
But going back to a view means I'm back to having to get MainActivity involved again, making this much more complex to actually use.
So what is the technical down-side for using fragments like this? I thought that was the entire point of why they exist. And if I am supposed to use a view, is there an easier way to get a result from ItemSelectorActivity?
If I understand you correctly, your view is starting an activity (ItemSelectorView starts ItemSelectorActivity). But views should be dump in Android. They should display, nothing more.
So a view should never start an activity. A view can contain a list of items maybe, but these items should be views and nothing else. Usually we use an Adapter for that: a middle man between the items to be displayed and the views that are created to represent them on the screen.
You could look into MVP to do this in a proper way. Or maybe MVVM and android architecture, if you like that better.
To answer your question, using a fragment for your use case is a better approach then a view and there is not that much overhead at all.
I am using setContentView(R.layout.main) to switch the views in the same activity. I am calling some asynchronous task and populating the data on the main layout file after that I am changing the view by calling setContentView(R.layout.main) method.
I came to know that we should not use setContentView method multiple times for same activity. Though it is working fine for me.
Can anyone explain why we should not use setContentView method multiple times for the same activity to change the views?
Will it create any memory related exceptions? Could someone please clarify?
I think switching Views is not a good idea, because android platform already have strong framework to handle the transition in between the views and maintaining the state of each view associated with the Activity its always better to stick with the existing framework instead of thinking of some complex implementation that you have to go through to do all these things. If you do not need any of these things to taken care in your application and if only if you have only two or three screen in your entire application you can try switching the views. That even based on how your views are structured if you have complex logic and lot of data needed to create these views this wont be a good way of doing it.One more thing if you are adding more views say functionality to your application the load that need to be handled by the Activity will go high. In this case you will be declaring and initializing all views inside that particular Activity so maintaining all these views instances is heavy. If you want to know more about the Activty and Task kindly refer this link
Well every time you call setContentView() you'll have to find all the layouts again besides that I think you "can" do it. But as discussed here this is ill adviced as it clearly goes against the android guidelines. Also Commonsware have some very important points here one of the most important being that you will be prone to leak memory as you forget to clean up stuff from your views etc. which Android normally would handle for you.
In short you should follow Android guidelines and use Fragments or start a new Activity.
According to the developer docs setContentView(int layoutResID) is used to
Set the activity content from a layout resource. The resource will be inflated, adding all top-level views to the activity.
In best practice this method is used to Inflate your Activity layout on start up. This does not mean that it will cause issues in the future if you keep using this method. To quote a answer in this question
The setContentView on your Activity actually calls the setContentView on the Window used by the activity, which itself does a lot more than just inflating the layout.
I suggest that you find a alternative way to switch layouts like using a ViewPager with Fragments or some other Tabbing approach but in the end it all comes down to what you want to do.
This question might also give you what you're looking for.
I'm referring to Why use Fragment#setRetainInstance(boolean)?
The reason I ask so is for Activity to handle rotation, Official Activity Documentation encourages us to let Activity shut-down and restart during rotation.
android:configChanges Lists configuration changes that the activity
will handle itself. When a configuration change occurs at runtime, the
activity is shut down and restarted by default, but declaring a
configuration with this attribute will prevent the activity from being
restarted. Instead, the activity remains running and its
onConfigurationChanged() method is called. Note: Using this attribute
should be avoided and used only as a last-resort. Please read Handling
Runtime Changes for more information about how to properly handle a
restart due to a configuration change.
Any attempt to change this Activity default behavior seems to be bad practice. To avoid Activity from reloading time consuming data structure during restarting, we make make use of onRetainNonConfigurationInstance and getLastNonConfigurationInstance. - Official Handling Runtime Changes
However, when comes to handling rotation in Fragment, does Google give us different recommendation? They do not want us to shut down and restart Fragment?
public Object onRetainNonConfigurationInstance ()
This method was deprecated in API level 13. Use the new Fragment API
setRetainInstance(boolean) instead; this is also available on older
platforms through the Android compatibility package.
Why does Google encourage us to shut down and restart Activity during rotation, but encourage us to retain Fragment during rotation?
If setRetainInstance(true) is good in handling rotation, why don't Google make it as Fragment's default behavior?
Configuration changes: when suddenly screen becomes much wider and much less in height (typical landscape), it is apt for a visual component to update its display and more intelligently use the screen available. Another examples of config change are user sliding the hardware keyboard, device language changing, and so on. why re-start :
Android components favor declarative layout, you load a bunch of XML layouts, and work from there. Finding every View and re-arranging/updating it in real time will be a mess, not to mention the re-wiring of all the event handlers and other custom View code. Its way easier to reload another bunch of layout files.
Also, In Android, Activities kind of live at the mercy of system, so naturally, Activity life cycle is so designed (and recommended) that it is capable of re-creating itself on demand , any time, just as it was before it was destroyed. This pattern accommodates all re-starts, those due to configuration changes as well. If you make your Activities and Fragments capable of maintaining an eternal state, configuration changes won't be that much of a problem.
Retain state data (Models), not the stuff displaying it (UI and Views).
setRetainInstance(true): It is recommended only to be used with fragments that do not hold any reference to anything, that will be recreated on rotation. This means you should not use it on any Fragment that holds Context, Views, etc. A typical Visual fragment does. But it is very useful with Fragments that hold objects like running Threads, AsyncTasks, Data Collections, loaded assets, fetched results etc. This method helps in using a non visual Fragment, as a detachable holder, for non Context-dependent objects of an Activity.
Because you are misunderstanding its use. setRetainInstance(true) should only be used in fragments that are like solo elements/modules. Fragment that handle sockets etc. an don't have a GUI really benefit from being retained. Fragments with a GUI should probably not use setRetainInstance(true). Also any fragments that goes to the backstack shouldn't use setRetainIstance(true).
You could generalize it to any fragment which handles only data/connection etc. should use setRetainInstance(true). But there is a multitude of different ways to use Fragments, which wouldn't benefit of setRetainInstance(true).
I have a single activity with multiple views that represent different steps in a wizard. I have gotten code working that will save and restore the wizard to the correct screen, but after a save/restore cycle I cannot seem to get setContentView to work. The code executes without throwing any exceptions but the view isn't actually updated. Why would this be happening?
edit:
SOLVED I was using a handler to change screens, but on restore I wasn't using the newly constructed one, so messages were being sent to a handler that didn't have control of the screen.
You might be filling the contentview with data in onCreate rather than onResume. onCreate is not called again if you are doing a save/restore cycle. It might be worth checking which lifecycle method is called. It would also be helpful to know how you save/restore.