I want to know how a View is created in Android. On a View object creation which functions are called?Initially constructors will be called.Next what? And so on.
If anybody know the sequence of functions called after object creation,Please reply me.
Thanks
This might help you better I guess.
1) Constructor : to initialize variables
2) onMeansure : to prepare canvas , set Width and height
3)OnDraw() : to draw actual view .
now onDraw() will continuously be called after a particular interval which depends upon display/processor and UI eventsenter code here or on calling invalidate()
Related
Exo player has a widget that handles the progress called
DefaultTimeBar
<com.google.android.exoplayer2.ui.DefaultTimeBar
android:id="#+id/exo_progress"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
Using this how-to programmatically seek to a particular position like 50% in android
Through inspecting the source code, it seems like DefaultTimeBarcalls update() constantly to retrieve bufferedPositionand position and draw the view accordingly. But it also has a couple of functions that call update() themselves and redraw everything. It is first initialized under the hood with a context and a few other parameters like AttributeSet.
From here, it really depends on what you're willing to do with it. If you want to just seek the position in ExoPlayer (which I assume you already know), you can just call this
val desiredPosition = simpleExoPlayer.duration / 2.toLong() // 50%
simpleExoPlayer.seekTo(desiredPosition)
However, if you're miscellaneously using the view as a Custom View and wanna update your DefaultTimeBar on your own. You need to understand how to instantiate it. Our DefaultTimeBar will receive position and bufferedPosition value updates constantly from the class that instantiated it to begin with; PlayerControlView.
Let's break it down quickly, how a DefaultTimeBar is instantiated and updated:
1- Instantiation:
val timeBar: DefaultTimeBar = DefaultTimeBar(context, null, 0, playbackAttrs)
As you can see, it takes a context, a #Nullable AttributeSet, a defStyleAttr and a #Nullable timeBar AttributeSet. Of course this can be a little bit confusing at first, but for starters, try going with the sample line of code above to instantiate it. The playbackAttrs in the constructor are the same playbackAttrs passed from SimpleExoPlayer to PlayerControlView in order to instantiate it. If playbackAttrs are still a cause of confusion, please inspect the source code of SimpleExoPlayer.
2- Updating positions: After you have instantiated your DefaultTimeBar, you can constantly call these two functions on the instance you have
timeBar.setPosition(position)
timeBar.setBufferedPosition(bufferedPosition)
3- Modifying a DefaultTimeBar view that is inflated from the XML: I have no particular experience howsoever with manipulating the DefaultTimeBar, but I assume you can just pass the generated view as a DefaultTimeBar and store it in a variable, that is:
val timeBar: DefaultTimeBar = findViewById(R.id.defaulttimebar) as DefaultTimeBar
This MAY or MAY NOT work. DefaultTimeBar extends "View" so the casting may or may not work.
If you wanna seek to a particular position, always make sure you know the target position (For example, a result of a user-induced seeking), then call setPosition to update the DefaultTimeBar.
Hi I'm implementing click listeners in the following way but after some time the methods and variables inside the listener's closure get the wrong values or something. Let me explain the implementation of the listener a little better a for loop creates the listener for a set of image views then later in the program the for loop is called a second time and it resets the listener methods and variables to different values. Everything works great for about 30 minutes but then for some reason, the listener's methods and variables start having the wrong values. Has anybody ever heard of this behavior or can tell me where I've gone wrong with the code? Keep in mind that the listener I'm about to paste here is just a small piece of a 1014 line class. I'm hoping somebody can spot How I'm implementing the listener wrongly and can give me some advice on how to "reset" the listener so that it's variables and values stay over time. Hopefully you can read the code without putting it in an editor but feel free to copy it for readability's sake Here is the code for the image view listener with comments.
//image views are held in an array
//set an image view in its imageview container
imgArr0[slotId1].invalidate()
imgArr0[slotId1].setImageDrawable(null)
//drw is not defined in this example
imgArr0[slotId1].setImageDrawable(drw)
/*if video or image id is set to image then set a listener for the image
*/
/*slotId1 is not defined in this example but it is simply a counter to iterate over the ImageView array
*/
if (videoOrImageId0[slotId1] == "image") {
//null any listeners that might be attached to the image view
imgArr0[slotId1].setOnClickListener(null)
//set or reset the listener
imgArr0[slotId1].setOnClickListener() {
`enter code here`//if the current config is portrait then set a new image image
if (currentConfig0 == "portrait0") {
act0.lrgImage0.invalidate()
act0.lrgImage0.setImageDrawable(null)
/*drw is not defined in this example but works fine in the production script
*/
act0.lrgImage0.setImageDrawable(drw)
}
--calmchess
ccc tv application with problem.
(https://i.stack.imgur.com/PjdbN.jpg)![enter image description here](https://i.stack.imgur.com/FaMnc.
I was able to partially solve this question by destroying all the image views and their associated click listeners then rebuilding those... However I don't consider this issue completely solved so if anybody can provide a better solution I'd love to hear it because rebuilding the images every few minutes has to be using a lot of unnecessary hardware resources.
--calmchess
I am trying to do calculate view's x,y positions after completion of loading of activity. What I did is view.postDelayed(runnable, 2000) which is working fine. code reviewer is not happy with this and suggested to use OnGlobalLayoutListener to know about the completion of activity loading. Somehow I don't like OnGlobalLayoutListener because it is associated with entire view tree which is not required for my solution. I am trying to understand pros and cons of these approaches. Thanks!
If all you are trying to do is read the view's x and y coordinates, I recommend using view.post(Runnable) with no delay (unless there is a good reason to include a delay). This will add the Runnable to a message queue to in the UI thread. The Runnable will wait to execute until after your View is inflated and attached to the window. Since View position property values depend on the view's layout context, posting a Runnable will give you the timing that you are looking for.
As you mentioned in your question description, an OnGlobalLayoutListener will apply to the entire View's layout as the class name suggests. An OnGlobalLayoutListener should only be considered if you are concerned with the layout state or visibility of any or all views within the view tree. I.e. anything that causes the view tree to be re-laid out.
Code reviewer is not happy because you wait 2s and guess that the loading of the activity is finished by then. This may be the case with your emulator or device but on older and slower devices the activity may not have finished loading. To be 100% safe that the activity has finished loading you should use the listener to inform the 'listener' when loading is completed.
I think that the correct way of doing this is by adding an onPreDrawListener to the view. This is the listener that is called when the view is about to be drawn, and where you already have all the information about it's size (width and height) and position (X and Y).
Example:
final View v = new View(getContext());
v.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
#Override
public boolean onPreDraw() {
v.getViewTreeObserver().removeOnPreDrawListener(this);
float myX = v.getX();
float myY = v.getY();
return true;
}
});
Don't forget to make the method onPreDraw return true, I don't know why but Android Studio makes it return false when you create the listener.
Also don't forget to remove the listener from the view, otherwise it might be uselessly called again.
I have a fragment and I need to measure location/width/height of its views on screen and pass to some other class.
So what I have is a function which does it, something like this :
private void measureTest(){
v = ourView.findViewById(R.id.someTextField);
v.getLocationOnScreen(loc);
int w = v.getWidth();
...
SomeClass.passLocation(loc,w);
...
The problem is that the location/width/height of views is not ready within fragment lifecycle.
So if I run that function within these lifecycle methods :
onCreateView
onViewCreated
onStart
onResume
I either get wrong location and width/height measurments or 0 values.
The only solution I found is to add a GlobalLayoutListener like this to mainView
mainView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
public void onGlobalLayout() {
if(alreadyMeasured)
mainView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
else
measureTest();
}
});
this gets the job done.. but its just Yack! IMO.
Is there a better way of doing this? seems like such a basic thing to do
inside onActivityCreated of your fragment retrieve the currentView (with getView()) and post a runnable to its queue. Inside the runnable invoke measureTest()
There is no better way. That code isn't that bad! It's fired as soon as the view is layed out (my terminology might be a bit weird there) which happens right after measuring. That is how it is done in the BitmapFun sample (see ImageGridFragment, line 120) in Google's Android docs. There is a comment on that particular piece of code stating:
// This listener is used to get the final width of the GridView and then calculate the
// number of columns and the width of each column. The width of each column is variable
// as the GridView has stretchMode=columnWidth. The column width is used to set the height
// of each view so we get nice square thumbnails.
I have some methods in my View that modify some of the shapes that are drawn when called. In Java in order to make sure the component is updated I would call repaint(). Is there something that will make sure my view is updated correctly?
I had read somewhere that calling invalidate() in the onDraw() method would keep things up to date and therefore I wouldn't need to have something like repaint() in my methods that modify that shapes that are drawn.
Is this correct, or is there something else I have to do?
EDIT
To add in an example, a method I call in my view is:
public void setLineThickness(int thickness) {
aLineThickness = thickness;
if(aLineThicness > 1)
//repaint(); - Okay in Java but not in Android
}
Calling invalidate() will tell the view it needs to redraw itself (call onDraw) sometime in the future. So if you change something in your view, like the line thickness, call invalidate() after it. That way you know your view will eventually be updated.
All your drawing code should be implemented in onDraw() and your other methods should just change the state of your view, which will then be used to draw it, after you call invalidate().