Android View rendering errors on screen reorientation? - android

I'm getting this weird behaviour on a very basic app, where the views render wrongly after a screen reorientation.
The code in the app works as expected when the screen reorients (with activity destruction/creation, since it's not intercepting those events) except for the view display.
When the screen reorients, the view works normally, only with an overlayed ghost image of whatever it looked like when the screen reoriented. It looks like a "burned in" CRT ghost image.
Launching the app in any orientation works normally, the issue only occurs when the screen is reoriented while it is running.
The views are used in a Fragment, which is the only one in its Activity. It happens the same for ListView, DatePicker, and TextView.
The issue occurs in multiple devices:
- nexus 4 running 4.4.3 stock android
- samsung galaxy s running cyanogenmod 10.2.1 (android 4.3.1)
- "galaxy nexus" AVD with API level 18 (android 4.3)
Any idea what is going on here? What more information would be useful for troubleshooting this?
Screenshots below:
layout file for the ListView example below:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/list_expenses"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<!-- Row for Buttons -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="3dp" >
<Button
android:id="#+id/list_expenses_button_add"
android:layout_width="0dip"
android:layout_height="40dp"
android:layout_weight="1"
android:text="#string/label_button_listexpenses_add" />
</LinearLayout>
<ListView
android:id="#android:id/list"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:id="#android:id/empty"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="#string/label_listexpenses_noexpenses"
android:gravity="center" />
</LinearLayout>

The issue was that, due to the following code in the Activity classes, the fragment was being repeatedly added to the layout, which resulted in overlapping views (not rendering errors, after all):
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_list_expenses);
if (getSupportFragmentManager().findFragmentById(R.id.list_expenses) == null) {
fragment = ListExpensesFragment.newInstance();
getSupportFragmentManager().beginTransaction().add(R.id.container, fragment).commit();
} else {
fragment = getSupportFragmentManager().findFragmentById(R.id.list_expenses);
}
}
Solution: replaced the call to getSupportFragmentManager().beginTransaction().add() by getSupportFragmentManager().beginTransaction().replace().

Related

Why recycle view inside horizontal scroll view not working?

I have created calendar by using recycle view. It worked perfectly in emulator but in real device only few elements gets loaded.
I used horizontal scrollview so all elements load at once and I'm adding padding at both sides for animations.
Code Snippet:
<HorizontalScrollView
android:id="#+id/dateHSV"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:overScrollMode="never"
android:scrollbars="none">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/dateRV"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:listitem="#layout/rv_item_calender" />
</HorizontalScrollView>
In Mobile
In Emulator (android 6)
As You can see in mobile only 3 dates gets loaded while in emulator (android 6) all dates gets loaded.

FragmentTabHost randomly goes blank after configuration change (rotation)

I came across a frustrating glitch in my app.
I have a FragmentTabHost in my Activity.
This tab host is hosting 5 fragments, each of these getting rendered correctly.
Now, the trick is that when I rotate the screen, sometimes the fragment is not being rendered.
The tab widget is still being rendered and is clickable, but the view corresponding to that fragment is not displayed.
Here is an example below.
Note that I put a red background on my realtabcontent FrameLayout:
Everything is working fine
Rotating the screen: randomly the screen becomes partially empty
Switching to other tabs executes the OnCreate/OnCreateView of the relevant fragment, but nothing is displayed
Switching back to the first screen does not even show the button of the Fragment anymore
Note that:
- the first time I rotate, there is still a button showing up (it belongs to the fragment that should be rendered).
- once the bug is triggered, I can switch to other tabs. The other tabs are loaded correctly (notice the action bar changing), but nothing is rendered in the FrameLayout
- If I go back to the first tab, the button that was still being displayed is not even rendered anymore
Notice also a detail: the reddot of the tab disappears, even though the code that set the reddot is correctly executed. It's as if the tab host is not responding to the drawing requests.
Here is the code in charge of displaying the reddot:
public void showReddotForTab(int tabIndx, Boolean showFlag){
try {
if (tabIndx < mTabHost.getTabWidget().getTabCount()) {
RelativeLayout tabRootView = (RelativeLayout) mTabHost.getTabWidget().getChildTabViewAt(tabIndx);
WhovaNotificationBadge notifBadge = tabRootView.findViewById(R.id.notif_badge);
if (showFlag) {
notifBadge.setVisibility(View.VISIBLE);
notifBadge.setLabel(null);
}
else {
notifBadge.setVisibility(View.GONE);
}
}
}
catch(Exception e){
e.printStackTrace();
}
}
Here is the layout of the activity containing the FragmentTabHost
<?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">
<androidx.fragment.app.FragmentTabHost
android:id="#android:id/tabhost"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<FrameLayout
android:id="#android:id/tabcontent"
android:layout_width="0dp"
android:layout_height="0dp" />
<FrameLayout
android:id="#+id/realtabcontent"
android:background="#color/red"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="2px"
android:background="#color/separate_gray"/>
<TabWidget
android:id="#android:id/tabs"
android:orientation="horizontal"
android:background="#color/new_whova_tab_bg"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:paddingTop="6dp"
android:layout_weight="0"/>
</LinearLayout>
</androidx.fragment.app.FragmentTabHost>
<TextView
android:id="#+id/text_network"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="40dp"
android:layout_alignParentTop="true"
android:background="#color/orange"
android:text="#string/network_off_indicator_msg"
android:visibility="gone"
android:textColor="#color/white"
android:gravity="center"/>
</RelativeLayout>
Here is the code setting up the tabhost
mTabHost = findViewById(android.R.id.tabhost);
mTabHost.setOnTabChangedListener(tabId -> {
...
})
mTabHost.setup(this, getSupportFragmentManager(), R.id.realtabcontent);
mTabHost.getTabWidget().setDividerDrawable(null);
//! simplified below, but the code is simlar to it
//! spec is basically TabHost.TabSpec spec = mTabHost.newTabSpec("someID").setImageResource(...).setIndicator(...).setContent(tag -> findViewById(R.id.realtabcontent));
mTabHost.addTab(spec, FragmentXXXX.class, fragmentBundleXXXX);
mTabHost.addTab(spec, FragmentXXXX.class, fragmentBundleXXXX);
mTabHost.addTab(spec, FragmentXXXX.class, fragmentBundleXXXX);
mTabHost.addTab(spec, FragmentXXXX.class, fragmentBundleXXXX);
mTabHost.addTab(spec, FragmentXXXX.class, fragmentBundleXXXX);
Found how to solve it, but I have no idea what is the reason.
My actionbar is a toolbar containing an AppCompatSpinner.
The spinner is only used for the tab showed in the pictures and has setOnItemSelectedListener set.
When rotating the screen, the listener is called (not sure why, because the initial selection is done before setting the listener and not selection occurred afterwhile.
Either way, sometimes when this listener is called, the data loaded from DB is still processing in the background. The weird thing being that once it is done, we refresh the UI but it stays blank and the other tabs are affected.
I suspect that there is something wrong in the way the listener is called and it blocks the processing of other UI events, but not sure.
When I set the listener within a post, the problem disappear
spinner.post(() -> {
spinner.setOnItemSelectedListener(...)
})

View is shown instantly even though I use handler.postDelayed

I have a two RelativeLayout where I have set their visibility to gone using,
android:visibility="gone"
And then on the root element of the activity which is also a RelativeLayout, I have added this attribute
android:animateLayoutChanges="true"
Here's my activity java code
RelativeLayout rellay1, rellay2;
Handler handler = new Handler();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
rellay1 = findViewById(R.id.rellay1);
rellay2 = findViewById(R.id.rellay2);
handler.postDelayed(new Runnable() {
#Override
public void run() {
rellay1.setVisibility(View.VISIBLE);
rellay2.setVisibility(View.VISIBLE);
}
}, 2000);
}
When I run the app, the views get displayed immediately without any wait. If I increase the time to 5s, still same results.
I've looked at the logs when starting the activity and nothing suspicious.
NOTE
When answering questions on SO, I sometimes find it hard to understand the users problem when it's cluttered with XML, so I tried hard to keep my question clean. But that might not be enough to diagnose what's wrong with my code so I'm adding a minimal version of the xml for the parent and two child RelativeLayouts without their contents, just the attributes. If more detail is needed I'd be happy to provide.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:animateLayoutChanges="true"
android:background="#drawable/grad_bg"
tools:context=".LoginActivity">
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_marginRight="40dp"
android:layout_marginLeft="40dp">
<ImageView
android:id="#+id/img_view_logo"
android:layout_width="80dp"
android:layout_height="80dp"
android:src="#drawable/ic_android_black_24dp"
android:adjustViewBounds="true"
android:scaleType="fitCenter"/>
<RelativeLayout
android:id="#+id/rellay1"
android:layout_below="#+id/img_view_logo"
android:layout_width="wrap_content"
android:visibility="gone"
android:layout_height="wrap_content">
</RelativeLayout>
</RelativeLayout>
<RelativeLayout
android:id="#+id/rellay2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:visibility="gone"
android:layout_alignParentBottom="true">
</RelativeLayout>
</RelativeLayout>
From the XML above, you'll see that my intention is to have only the ImageView visible initially and the rest should become visible after 2s.
I have looked similar questions about Handler#postDelayed but the problems are not exactly like mine so the solutions where not applicable.
UPDATE
The only problem here seems to be my lack of proper understanding of the android lifecycle(I'm a beginner here). I carried out an experiment by killing all running apps and tried launching my app again and I saw the animation.
So I guess what was happening here was that, the view had already been created and since my activity was still alive even though I had exited the app, subsequent launches of the App loaded a previously saved instance of the activity and that is why it seemed as if the animation wasn't working.

How to resize View with pull the edge gesture?

I am looking for solution as on images bellow:
I need to have two resizable views in one layout.
User just needs to move separation line to the top (ScrolView B becames higher) or to the bottom (ScrolView A becames higher).
What is the best solution, which gives this behavior? I know that I can extends from ScrollView and override public boolean onTouchEvent(MotionEvent ev) and protected void onDraw(Canvas canvas), but may be there is more simple solution. I want to avoid calculation the math of moving. Thank you for any information.
If you want to solve this problem quickly, I suggest you use Split Pane Layout.
Usage :
<com.mobidevelop.spl.widget.SplitPaneLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:spl="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:id="#+id/splitPaneLayout"
android:layout_height="match_parent"
spl:splitterSize="12dp"
spl:orientation="vertical"
spl:splitterPosition="50%"
spl:splitterBackground="#781b23">
<ScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5dp"
android:text="" />
</ScrollView>
<ScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5dp"
android:text=""/>
</ScrollView>
</com.mobidevelop.spl.widget.SplitPaneLayout>
I solved your problem by creating two xmls for portrait and landscape mode. For portrait mode, i set the panel's orientation as vertical by adding spl:orientation="vertical" and for lanscape mode, i set the panel's orientation as horizontal by adding spl:orientation="horizontal".
After doing all this, I got the look like below.
Made this into an answer.
You basically want the split screen view from Android N. You could base your code off the open source implementation in SystemUI:
http://androidxref.com/7.1.1_r6/xref/frameworks/base/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
Along with this for the handle:
http://androidxref.com/7.1.1_r6/xref/frameworks/base/packages/SystemUI/src/com/android/systemui/stackdivider/DividerHandleView.java
You can throw away all code that has to do with stacks (which is the row of screenshots off different activities in your history), buss events and anything that has to do with running another activity, such as the code for Vsyncing between apps (mSurfaceFlingerOffsetMs).
It should leave you with quite small and easy to use classes.

Black box in screen after pressing Android menu button

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?

Categories

Resources