I have a PlayerView that takes up the top half of the Fragment in portrait orientation with the bottom half showing some text. The fragment is a part of a ViewPager and a user can switch screens with different videos.
Problem: While navigating between screens (swiping right/left) the PlayerView sometimes shows a preview image from the previous screen. It is shown just for a fraction of a second and then it shows the correct preview picture, but it is noticeable.
Question: How do I make the PlayerView show only the correct preview picture? It shouldn't blink with the previous picture. May be I'm misusing something (wrong instantiation of the Player or the View...)? May be some workaround if it is a known issue(blurring the video while swiping, etc)? Any suggestion/idea is appreciated.
Here is how my layout looks like:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.exoplayer2.ui.PlayerView
android:id="#+id/video_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<TextView
android:id="#+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_below="#id/video_view"
android:scrollbars="vertical" />
</RelativeLayout>
In Fragment code I have:
#Override
public void onStart() {
...
SimpleExoPlayer player = ExoPlayerFactory.newSimpleInstance(
getActivity(), new DefaultTrackSelector()
);
player.prepare(mediaSource);
playerView.setPlayer(player);
...
}
EDIT 1.
As requested in the comments section my PageAdapter is pretty standard (just like the one Android Studio generates while creating a Tabbed Activity) with the only extension - I save current fragment in it just like it is suggested here.
Related
I am creating a library class in Android Studio for my internship. I have created a custom RelativeLayout that inflates the layout shown below.
I can't find this issue anywhere, so I hope someone is able to help me out.
I have a layout file that looks like this:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="#+id/videoFrame"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_centerInParent="true"
android:background="#color/wallet_holo_blue_light">
<VideoView
android:id="#+id/videoBackground"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="center"
android:background="#null"/>
</FrameLayout>
</RelativeLayout>
I do need the FrameLayout, to be able to scale the VideoView where the VideoView's width is bigger then the parent this Layout is inflated into. I resize this VideoView dynamically on runtime-level, but that all works fine.
When I start the activity with this VideoView, everything is fine.
Whenever I hit the Android "Windows"-button and return to the Activity, a black box appears.
Screenshots
It also happens in Portrait mode. Then the black box is even bigger than half the screen.
After changing screenOrientation, so rotating my tablet, for example, the black box is gone again.
I really have no clue, does anyone know what the problem might be?
I'am stuck!
I am developing my first Android App, so I am considered as a beginner. I have some programming background, so I managed to solve the first problems myself. But now I am at a point where I don't know how to solve several problems. So please share your eternal wisdom with me.
I am developing a game. I want the menu to be in a virtual phone. The picture below describes best what I want to achieve. Don't be confused by the words, I am from Germany.
Einstellungen = preferences ...
http://www.directupload.net/file/d/3565/2xwgz3al_png.htm
When I am pressing the menu-button a fragment gets called. At the moment the layout of the fragment contains relative layout with android : background set to that entire image. What I want to achieve is that the phoneframe stays all the time, only the view (RED) will change. With up and down buttons I want to be able to move the chooser (BLUE) to the different menuitems. If I press OK (YELLOW) the selected item is called an e new view slides from the right side in the RED area. Hope that's clear.
So my questions are:
How do I get the RED area to that phoneframe? Maybe a LinearLayout with fixed Width and Height? But i cant image that as a good solution.
How do I animate the chooser (Blue) to the different menupoints by clicking up and down?
How would you perform the switch between the views inside of the phone Frame.
I want to perform all of that in that only fragment. Or is there a better solution?
I do not need the code for that all, only a push, a start or ideas so I can start googleing in the right directions.
Big Text an many questions, I hope you can take a little time for me, THANKS for answers.
Greetings from Germany (sorry if my English is not perfect)!
Well you are asking a lot of question at once so it's difficult for me to give a clear answer. I am just going to explain to you how I would build a screen like that:
1) The Layout:
You Layout can simply be built with a RelativeLayout:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="#+id/flFragmentContainer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentTop="true"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_marginTop="64dp"
android:layout_marginLeft="64dp"
android:layout_marginRight="64dp"
android:layout_marginBottom="128dp"
android:background="#ff0000"/>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true">
<Button
android:id="#+id/btnDown"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_alignParentBottom="true"
android:layout_marginBottom="15dp"
android:text="#string/fragment_main_button_down_text"/>
<Button
android:id="#+id/btnUp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="#id/btnDown"
android:layout_centerHorizontal="true"
android:text="#string/fragment_main_button_up_text"/>
<Button
android:id="#+id/btnClose"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toLeftOf="#id/btnDown"
android:layout_alignParentBottom="true"
android:text="#string/fragment_main_button_close_text"/>
<Button
android:id="#+id/btnOk"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="#id/btnDown"
android:layout_alignParentBottom="true"
android:text="#string/fragment_main_button_ok_text"/>
</RelativeLayout>
</RelativeLayout>
So the layout is not that complicated, I set the background color of the FrameLayout to white so you can see were the fragment will be placed. Here is the Result:
This layout contains the buttons ok, close, up and down and of course a FrameLayout where our fragment is going to go. The layout in this example is by far not optimal, the problem is the positioning of the FrameLayout. It is as big as the screen with a fixed margin on all sides, so on different phones with different aspect ratios the FrameLayout is also going to have a different aspect ratio.
2) The FragmentTransaction
Now comes the interesting part, we are going to put our fragment into the FrameLayout container. But first, since we want the fragment to slide in from the right we have to write an ObjectAnimator like this:
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="#android:anim/linear_interpolator"
android:propertyName="xFraction"
android:valueType="floatType"
android:valueFrom="1.0"
android:valueTo="0.0"
android:duration="750" />
This describes a translation animation from right to left, if you want more information on that feel free to ask.
Now with that animation we have everything we need, now whenever you want to change the Fragment inside the phone you just have to perform a FragmentTransaction like this:
// We get our FragmentManager and begin our transaction
FragmentManager manager = getFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
// Here we set our animations, to make the effect nicer I added a fade out animation for the old fragment
// The fade out animation is already built into Android
transaction.setCustomAnimations(R.animator.slide_in_right, android.R.animator.fade_out);
// We specify were we want the Fragment to go and pass along our new fragment instance.
// Calls to replace(), add(), remove()... always have to take place AFTER setCustomAnimations()
// Otherwise the animations are not applied to the fragments
transaction.replace(R.id.flFragmentContainer, fragment);
// With commit() the transaction is actually executed. You can replace multiple fragments in a single transaction
transaction.commit();
And here is the result, in my example app the FragmentTransaction is executed every time I press OK:
I'm facing weird issue of flickering using VideoView. When activity starts, it causes minor flicker of fraction for a second. Then, video starts. It shows 2 black lines on the top and the bottom of the video. See the snap-shot below.
I have tested my application on 2 devices
1) Samsung n-8000(Tablet)
2) Lenovo a-800
video.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#ffffff"
android:gravity="center">
<VideoView
android:id="#+id/vvSplash"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:background="#00ffffff">
</VideoView>
</LinearLayout>
Activity code:
private VideoView vd;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().requestFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.video);
vd = (VideoView) findViewById(R.id.vvSplash);
playVideo();
}
private void playVideo() {
Uri uri = Uri.parse("android.resource://" + getPackageName() +"/"+ R.raw.intro);
vd.setVideoURI(uri);
vd.setMediaController(null);
vd.start();
}
Any help would be appreciated. Thank you.
As ridiculous as it sounds, but the answer is here:
VideoView inside fragment causes black screen flicking
SurfaceView flashes black on load
I repeat the solution, kudos to those who found out:
<SurfaceView
android:layout_width="0px"
android:layout_height="0px"
android:visibility="gone" />
It is VERY IMPORTANT that you add the surface view to the root view in your activity, not the immediate parent. Otherwise it won't work.
i also faced same problem but solved it by changing layout parameter of videoview from wrap content to match parent . Also you need to remove the background property of video view from XML. I hope it will work for you
For people in the future: This ugly bug seems to have been resolved in Marshmallow. At my work, we are developing with Xamarin (so, basically, all views are added in programmatically). We have a bunch of test devices, and I was mainly working with a Marshmallow device, so I never noticed this black flicker when building the page I was working on. After finally testing with a Lollipop device, I noticed this flicker.
Unfortunately I do not have a solution. We need our application to be as cross-platform as possible, so using a layout xml is discouraged /sadface.
If your issue is VideoView flickering when the back button is pressed, just set your VideoView visibility to INVISIBLE or GONE in the onBackPressed() method of your Activity before calling the super implementation.
If the user can also leave through the "up" button, intercept android.R.home option item to hide the VideoView.
Here's an example in Kotlin:
override fun onOptionsItemSelected(item: MenuItem) = when (item.itemId) {
android.R.id.home -> super.onOptionsItemSelected(item).also {
video_view.visibility = GONE // Hide videoView before leaving to avoid flickering
}
R.id.action_share -> consume { shareVideo() } // Your regular menu options
else -> super.onOptionsItemSelected(item)
}
override fun onBackPressed() {
video_view.visibility = GONE // Hide videoView before leaving to avoid flickering
super.onBackPressed()
}
Just remove the following line from your xml.
android:background="#00ffffff"
It will help you :)
For anyone who's still facing the problem and don't get how to use the above answer.
It simply just copies this code and paste it in the main activity layout that you're using the videoview in under the main (first) layout.
<SurfaceView
android:layout_width="0px"
android:layout_height="0px"
android:visibility="gone" />
in my case
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/Mainframlayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/facebookbgcolor" >
<SurfaceView
android:layout_width="0px"
android:layout_height="0px"
android:visibility="gone" />
.....rest of the layout
Adapted the xml-based solution from https://stackoverflow.com/a/27307286/38557 to use Java code instead. Put this in the Fragment's onCreateView(), before inflating the layout:
// Add a SurfaceView to prevent flickering when the video is loaded later.
SurfaceView surfaceView = new SurfaceView(getActivity());
surfaceView.setVisibility(View.GONE);
container.addView(surfaceView, new ViewGroup.LayoutParams(0, 0));
It does the same thing, and can be used when you can't or don't want to change the XMLs.
Update:
I ended up separating out the video player into a separate activity and layout. I then started this activity using the code below.
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
startActivityForResult(new Intent(MainActivity.this, VideoActivity.class), VIDEO_PID); //load video
//etc.
}
When the app is loaded, I call this function to kill the Video Activity and bring the main activity to the front:
public void doneLoading() {
finishActivity(VIDEO_PID);
}
I don't know if this is the best way, but it worked.
=======================
What's the easiest way of showing a centered VideoView and then switching to a WebView after the application is fully loaded? I verified that both these views work when included individually in the app. I just want to only show the VideoView when loading, then hide it until the application is closed.
I was looking into ViewPager and ViewFlipper, but I haven't gotten anything working yet. I was going to avoid including them in separate activities. PageViewer seemed to manage the views (meaning allow them to run and init themselves), but not actually display them (all I saw was a black screen). I'm probably missing something.
Would it be easier to start the loading video then start off another activity that initializes the webview, which requests focus and sends a message for the loading video activity to quit after initialization is finished?
My layout is below to give an idea of what I'm using.
Thanks.
P.S. I'm avoiding the use of Fragments for Gingerbread support.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<android.support.v4.view.ViewPager android:id="#+id/view_pager"
android:layout_width="wrap_content"
android:layout_height="0dip"
android:layout_weight="1" >
<VideoView
android:id="#+id/videoview_component"
android:layout_width="fill_parent"
android:layout_height="0dip"
android:layout_gravity="center"
/>
<WebView
android:id="#+id/webview_component"
android:layout_width="fill_parent"
android:layout_height="0dip"
/>
</android.support.v4.view.ViewPager>
</LinearLayout>
In Android 2.3 application I used to support two cameras: one built-in and onу externally MJPG-streamed using Wi-Fi. The built-in camera must be recording video all the time and a user must have the ability to switch view between those. So, each camera had a dedicated SurfaceView to draw on. As the last child added to a FrameLayout has a higher Z-order, I programatically add the required camera view to a FrameLayout last to make it visible. I can't skip adding built-in camera since it can't record video without the preview display.
This scheme no longer works with Android 4: the built-in camera preview is always shown in spite of being added first or last. I played with 'setVisibility' methods on views and noticed that if one of views is set to be invisible (or gone) then none of them is showed at all. ViewGroup's 'bringChildToFront' method had no effect as well.
So, is there some workaround to make this work on Android 4? And I know that having multiple SurfaceViews is considered bad. Some code follows.
FrameLayout:
<FrameLayout android:id="#id/data"
android:layout_width="fill_parent" android:layout_height="fill_parent"/>
Code that populates the layout (no longer works on Android 4):
private void setCorrectView() {
data.removeAllViews();
List<Recorder> others = recorders.getOthers();
for (Recorder other : others) {
addToTheView(other);
}
addToTheView(recorders.getCurrent());
}
private void addToTheView(Recorder recorder) {
View view = recorder.getView(this); // get recorder's surface view
data.addView(view);
}
The same effect if I use FrameLayouts from XML:
<FrameLayout android:layout_width="fill_parent" android:layout_height="fill_parent"
xmlns:android="http://schemas.android.com/apk/res/android">
<FrameLayout
android:id="#id/data"
android:layout_width="fill_parent" android:layout_height="fill_parent"/>
<FrameLayout
android:id="#+id/data_invisible"
android:layout_width="fill_parent" android:layout_height="fill_parent"/>
</FrameLayout>
Wherever I put built-in camera's surface view - it's always shown. Looks like internal camera's preview is now always on top in Android 4.
Answering to myself. To make this work I set the views' visibility to View.VISIBLE before starting the camera and set it to View.INVISIBLE after. This link may be helpful.