setVisibility(View.GONE) causes a Crash - android

[Edit: I have just replaced adView.setVisibility(View.GONE) with adView.setVisibility(View.INVISIBLE) the WebView loads and nothing crashes, so it really looks like it is something to do with when I remove the AdView xml element, rather than just making it invisible. Making it invisible is not ideal, as you get a white empty bar at the bottom where the Ad should have been. So it really looks like it is something to do with reloading the Webview or messing with the UI. My html/javascript code is solid and can handle any dimension changes.]
I have a Webview above a banner for an advert (the "ca-app-pub-3940256099942544/6300978111" is the test ad id, so I am not given out any personal info)
<WebView
android:id="#+id/webView"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginBottom="5dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintBottom_toTopOf="#+id/adView" />
<!-- "BANNER" or "LARGE_BANNER" -->
<com.google.android.gms.ads.AdView
android:id="#+id/adView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:adSize="BANNER"
app:adUnitId="ca-app-pub-3940256099942544/6300978111"/>
Note: the app:layout_constrain... in the Webview. I think that might be part of the problem.
At start up, I am checking for purchases. If the user has made any purchases whatsoever, I turn off the ads with the code:
public void turnAdvertsOff() {
advertsOn = false;
AdView adView = (AdView) m_Context.findViewById(R.id.adView);
adView.destroy();
adView.setVisibility(View.GONE);
}
With the line adView.setVisibility(View.GONE); the program crashes with the unfounded allegation:
I/chromium: [INFO:CONSOLE(6381)] "Uncaught Error: Java exception was raised during method invocation", source: file:///android_asset/www/index.html?IsAndroidWebview=true (6381)
D/WebView: loadUrl=about:blank
D/WebView: destroy
However, I know there is nothing wrong in the Webview, as when I hash out the line //adView.setVisibility(View.GONE);, the WebView loads fine.
Does anyone know why?
Is it anything to do with the app:layout_constraint.., and if so how do I overcome it?

This is what is recommended to hide the adView:
adView.pause();
adView.setVisibility(View.GONE);

Try using a LinearLayout as below
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<WebView
android:id="#+id/webView"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginBottom="5dp"
android:layout_weight="1" />
<!-- "BANNER" or "LARGE_BANNER" -->
<com.google.android.gms.ads.AdView
android:id="#+id/adView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:adSize="BANNER"
android:layout_gravity="center"
app:adUnitId="ca-app-pub-3940256099942544/6300978111" />
</LinearLayout>
SMART_BANNER

OK, I have found the answer, and it is not obvious. It is a combination of #mTak 's answer and a critical bit of how Android apps work (which is something I did not realise since I come from an html/javascript world and multi-threading is something programmers have absolute control over in that environment).
The purchases checks were being made on another thread. So the attempt at doing adView.setVisibility(View.GONE) was causing grief to the program. It does not seem to like you messing with the UI except on the main UI thread.
So this is how I changed my code to make the Android protocols happy:
My Purchase check (in a separate thread, but in the MainActivity). Note, stringListARR is just an array of strings with the product codes that the user had purchased. So if there was at least one purchase, whatever it was, I had decided to turn off adverts:
// Any purchase means we have no adverts
myAdverts.advertsOn = stringListARR.size() > 0 ? false : true;
// This is the evil line of code that caused the problem - this was being called not on the UI thread
//if(!myAdverts.advertsOn) myAdverts.turnAdvertsOff();
// And this is how to do it properly forcing it to be run on the UI thread
// 'this' in the following is my MainActivity
if(!myAdverts.advertsOn){
this.runOnUiThread(new Runnable(){
#Override
public void run() {
myAdverts.turnAdvertsOff();
}
});
}
And #mTak was perfectly right how to do things properly. My turnAdvertsOff() looks like this:
public void turnAdvertsOff() {
advertsOn = false;
AdView adView = (AdView) m_Context.findViewById(R.id.adView);
adView.pause();
adView.setEnabled(false);
adView.setVisibility(View.GONE);
}
So thanks to #mTak and thanks to this almost unfindable thread on google which gave me the idea:
https://groups.google.com/forum/#!topic/google-admob-ads-sdk/d30EAC1zGFo
In fact, if any people here on Stackoverflow are answering questions about crashes when people are messing with the UI in Android, this runOnUiThread might be the first solution that springs to mind. It is not obvious and a pain to discover.

Related

Android TextView.setText() is not changing on recent Samsung phones with SurfaceView Overlay

In my app I have a TextView and an ImageView that I update based on sensor information. This works perfectly on emulators and most of the handsets I have tried it on, however on Samsung handsets from the S7 to the S9 for some reason neither of them changes when they should be updated.
They are part of a Fragment overlaying a SurfaceView with a camera preview in it, there is a second SurfaceView overlay above them:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="myApp.CameraViewFragment">
<FrameLayout
android:id="#+id/control"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentBottom="true"
android:layout_alignParentStart="true">
<myApp.CameraSurfaceView
android:id="#+id/camera_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true" />
<TextView
android:id="#+id/direction"
android:layout_width="80dp"
android:layout_height="wrap_content"
android:background="#color/black_overlay"
android:layout_gravity="center_horizontal"
android:gravity="center"
android:layout_centerInParent="true"
android:layout_centerHorizontal="true"
android:layout_marginTop="10dp"
android:textSize="30dp"
android:text="" />
<ImageButton
android:id="#+id/gpsNotification"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/gps_unfixed"
android:layout_gravity="right"
android:tint="#color/gps_unfixed"
android:background="#null" />
</FrameLayout>
<com.myapp.OverlaySurfaceView
android:id="#+id/overlay_view"
android:layout_width="200dp"
android:layout_height="200dp"
android:gravity="center"
android:layout_gravity="center_horizontal|center_vertical"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true" />
</FrameLayout>
As far as I know, this is the relevant part of the Fragment code:
public class CameraViewFragment extends Fragment
{
private TextView directionView;
private CameraSurfaceView cameraView;
private OverlaySurfaceView overlay;
#Override
public void onViewCreated(final View view, Bundle savedInstanceState) {
cameraView = (CameraSurfaceView) view.findViewById(R.id.camera);
directionView = (TextView) view.findViewById(R.id.direction);
overlay = (OverlaySurfaceview) view.findViewById(R.id.overlay_view);
}
private void setDirection(AccurateDirection direction) {
final String directionString = direction.getDirection();
overlay.update();
Activity activity = getActivity();
if ( activity != null ) {
activity.runOnUiThread(new Runnable() {
public void run() {
directionView.setText(directionString);
directionView.invalidate();
}
});
}
}
}
When I run this on a regular handset, the directionView text updates as new direction data arrives. On a Samsung S7 the value gets set once, maybe updated once right at the start and then it seems to stick and not change any more. If I pause in the debugger and call directionView.getText() from the immediate window, it gives me the result I am expecting, not what I see on the screen. If I call directionView.setText('ABC') in the immediate window, the value returned by directionView.getText() changes but again the value on the screen does not. The ImageView also seems to get stuck in its initial state regardless of changes that should adjust it.
Previous questions on this topic seem to involve updates not being triggered from the UI thread or failures to call invalidate on the view component, so I have fixed both of those already but the problem persists.
I have only seen this on recent Samsung handsets ( my old Samsung S4 appears to be fine ) which makes it hard to troubleshoot. Why are my view components not changing on the Samsung devices and what do I need to do to get them to update?
Edit: Apologies to anyone previously attempting to answer this as I had ommited the OverlaySurfaceView and I now realise that the other components update correctly if the OverlaySurfaceView is removed, so apparently having that second SurfaceView in the view hierarchy is interfering, but only on Samsung. Switching on and off hardware acceleration doesn't seem to make a difference, but there may be a specific place or way that I need to do it. On a working handset hardware acceleration is marked as disabled for the `OverlaySurfaceView.
I had the same issue with Samsung S7 device,
eventually I realized i was not handling the setZOrderOnTop correctly
check out this answer :
Button on top of SurfaceView with setZOrderOnTop set to true in Android

Setting textview visibility inside retrofit on failure callback

I am trying to set the visibility of a Textview depending on the response returned by Retrofit . onFailure, I am setting the visibility to visible tv_no_cat.setVisibility(View.VISIBLE); However, this does not work. I am doing the same with a ContentLoadingProgressBar and it's working appropriately. Here is my code
public void onFailure(Call<List<MoviesCategory>> call, Throwable t) {
tv_no_cat.setVisibility(View.VISIBLE); ////This does not work
Boolean x = tv_no_cat.getVisibility() == View.VISIBLE;
Toast.makeText(getContext(), "Network Error "+x, Toast.LENGTH_LONG).show(); //This shows true
tv_no_cat.setTextColor(Color.BLUE);
videoLoadingPb.setVisibility(View.GONE); //This works
}
My guess is that am trying to set the textview which is on UI thread from another thread. If so, why is it working for the ContentLoadingProgressBar?
Here is my xml for the 2 views
<android.support.v4.widget.ContentLoadingProgressBar
android:id="#+id/loading_categories"
style="?android:attr/progressBarStyleLarge"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:layout_gravity="center"
android:visibility="visible" />
<TextView
android:layout_below="#id/loading_categories"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="No Movie Category Found"
android:id="#+id/tv_no_cat"
android:textAlignment="center"
android:layout_gravity="bottom"
android:visibility="gone"
/>
Any help on how I can set the textview Visibility to VISIBLE is welcome.
From the docs:
On Android, callbacks will be executed on the main thread...
So this is not your issue, and I'm doubtful that it's related to Retrofit, especially when it works for another view. Please make sure that there are no problem in your xml design, and that there are no other methods that affect this view's visibility.
are registering Textview inside Oncreate or some where else ?
And this code you are using inside activity of fragment ?
Please check this ...
tv_no_cat=(TextView)findViewById(R.id.tv_no_cat);(Inside Activity)
tv_no_cat=(TextView)rootView.findViewById(R.id.tv_no_cat);(Inside Fragment )

In Android: How to Force refresh (update) of a TextView that is INSIDE a Dialog Window?

This is probably a basic procedure, and in fact I've been extensively searching for a suitable answer, but I haven't found anything usable or that actually works. Now, the case:
A Dialog window is placed inside a method:
public void method_with_Dialog_code() {
Dialog simpleDialog = new Dialog(this, R.style.FilterDialogTheme);
simpleDialog.setContentView(R.layout.dialog_xml_layout);
simpleDialog.setCancelable(true);
TextView insideTextView = (TextView) simpleDialog.findViewById( R.id.insidetextview );
insideTextView.setText("This text should change when the WiFi is offline");
simpleDialog.show();
}
The respective dialog_xml_layout.xml file is simply:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="#+id/insidetextview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center" />
</LinearLayout>
If the device is for example disconnected from the Internet, it generates a message that should be shown in the insideTextView. But notice that simpleDialog and insideTextView are inside the method, so they are local objects, so the first issue is how to execute:
insideTextView.setText("This device is now offline");
from another part of the code, that is, outside of the method?
If I decide to make simpleDialog and insideTextView as Global variables, I can with no problem, from another part of the program, set the line:
insideTextView.setText("This device is now offline");
But the instruction doesn't work. The TextView is never updated with the new message.
So, any ideas? Maybe with TextView.addTextChangedListener, so insideTextView could be updated when the TextView.setText is executed externally?
Gracias.
make insideTextView a member variable of the class and use it later.

Android studio throws "Too much output to process error" on debug

Android studio throws "Too much output to process error" on debug.
I just started working on android development and trying to debug using my nexus 5 as a connected device.
Being a novice, I thought it was a memory issue and even closed all the background applications. In my single activity I am just displaying a background image and a button.
Please have a look at the layout xml...
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/backgroundimage"
android:weightSum="5"
android:orientation="vertical">
<LinearLayout
android:layout_height="0dp"
android:layout_width="match_parent"
android:layout_weight="1"
android:background="#C9BDBD"
android:padding="5dp">
<Button
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textSize="20dp"
android:background="#6C7B8B"
android:textColor="#000000"
android:text="Become An Android Developer"
android:onClick="Congratulations!!! You are now initiated.."/>
</LinearLayout>
your Button's android:onClick should be a method in the Java code.
<Button
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textSize="20dp"
android:background="#6C7B8B"
android:textColor="#000000"
android:text="Become An Android Developer"
android:onClick="Congratulations!!! You are now initiated.."/>
something like
android:onClick="doSomthing"/>
and in the Java code:
public void doSomthing(View v){
...
...
...
}
As far as "too much output..." issue is concerned, you can mostly ignore it. Still it would make sense if you remove some of the really unnecessary Log lines from your code, especially from methods that are called repeatedly and frequently.
Another thing, i believe you want to show a text "Congratulations!!! You are now initiated.." when user clicks on button.
So change your xml's android:onClick to android:onClick= "myButtonClicked"
In the activity, implement this function
public void myButtonClicked(){
}
Finally, show the text "Congratulations!!! You are now initiated.." either via dialog (e.g. alertDialog) or in some textView
You may have selected "No Filters" in android monitor which causes "Too much output to process error", Change it to "Show only selected Application" then all other Log line are filtered and will not show in Logcat.

Check if ads:testdevice is working properly?

I put this in my LinearLayout
<com.google.ads.AdView
android:id="#+id/adView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
ads:adSize="BANNER"
ads:adUnitId="d7fd8f9ghf042k4"
ads:loadAdOnCreate="true"
ads:testDevices="34HF70000000G501" />
I'm still testing my application, but when I checked my AdMob account, I found out this:
I don't understand, what's happening? Am I getting revenue for clicking my own Ads?
If Yes, how could this happen when I have mentioned this line ads:testDevices="34HF70000000G501" in my XML layout?
The ID you put inside of ads:testDevices needs to be the hashed device ID which is output in LogCat when you load an ad request on the device. It does not work if you use your actual device id.

Categories

Resources