Android Wear append to textView crashes app - java

So i have a strange issue when trying to retrieve a list of sensors on my application.
Printing to the log works just fine.
When I try to append to a textView, it crashes.
Here is where I am doing the attempted appending:
protected void onCreate(Bundle b) {
super.onCreate(b);
setContentView(R.layout.activity_main);
sensorTextView = (TextView) findViewById(R.id.sensorList);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
initialiseAccelerometer();
sensorManager=(SensorManager) getSystemService(SENSOR_SERVICE);
List<Sensor> sensors = sensorManager.getSensorList(Sensor.TYPE_ALL);
for (Sensor sensor : sensors) {
Log.d("Sensors", "" + sensor.getName());
sensorTextView.append(sensor.getName());
}
sensorManager.registerListener(
this,
sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
SensorManager.SENSOR_DELAY_NORMAL);
mGestureDetector = new GestureDetectorCompat(this, new LongPressListener());
}
And subsequent error:
java.lang.RuntimeException: Unable to start activity
ComponentInfo{com.example.XXXXXX.XXXXXXXXXXX.MainActivity}:
java.lang.NullPointerException:
Attempt to invoke virtual method
'void android.widget.TextView.append(java.lang.CharSequence)' on a null object reference
And the XML file with correct id:
android:id="#+id/sensorList"
Can anyone point me in the right direction or advise me as to what I'm doing wrong?
activity_main.xml:
<android.support.wearable.view.WatchViewStub
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:id="#+id/watch_view_stub"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:rectLayout="#layout/rect_activity_main"
app:roundLayout="#layout/round_activity_main"
tools:context=".MainActivity"
tools:deviceIds="wear"></android.support.wearable.view.WatchViewStub>
Thanks,
Emmett

This section of the documentation notes some quirks of WatchViewStub. In particular, note the following:
The layouts that you specify for square or round screens are not inflated until WatchViewStub detects the shape of the screen, so your app cannot access their views immediately. To access these views, set a listener in your activity to be notified when the shape-specific layout has been inflated
You are probably trying to set the TextView reference too early, which is why it's null at the point you attempt to append text. If you instead use an OnLayoutInflatedListener as in the sample code below (also from the documentation) to wait until the appropriate round/square layout is inflated, you should find that the reference is initialized properly for both screen types:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_wear);
WatchViewStub stub = (WatchViewStub) findViewById(R.id.watch_view_stub);
stub.setOnLayoutInflatedListener(new WatchViewStub.OnLayoutInflatedListener() {
#Override public void onLayoutInflated(WatchViewStub stub) {
// Now you can access your views
TextView tv = (TextView) stub.findViewById(R.id.text);
...
}
});
}
[Note that a colleague of mine has indicated that there is currently a bug that requires you to define the square layout xml attribute and the round layout xml attribute in a specific order for this to work - I don't remember offhand which needs to be first, just a heads-up if you run into problems].

Related

Android 11: Tried to access UI constants from a non-visual Context

I was running project OnmiNotes on Github when I ran, and looking at Logcat, the result was an error: "Tried to access UI constants from a non-visual Context", I found out that this is a new error on android 11, and there are quite a few suggestions to correct this error on gg, I look at them, those cases are not suitable for my case. And the person who wrote this app wrote on android 8, so they probably didn't know this error. Below are the code lines I find relevant.
There is an error in Logcat:
Tried to access UI constants from a non-visual
Context:it.feio.android.omninotes.OmniNotes#e9ea0eUI constants, such as
display metrics or window metrics, must be accessed from Activity or
other visual Context. Use an Activity or a Context created with
Context#createWindowContext(int, Bundle), which are adjusted to the
configuration and visual bounds of an area on screen
and:
Tried to access visual service WindowManager from a non-visual Context:it.feio.android.omninotes.OmniNotes#e9ea0e Visual services, such as WindowManager, WallpaperService or LayoutInflater should be accessed from Activity or other visual Context. Use an Activity or a Context created with Context#createWindowContext(int, Bundle), which are adjusted to the configuration and visual bounds of an area on screen.
And there are two command lines I see mentioned in logcat error
1.In BaseActivity:
#Override
protected void onCreate(Bundle savedInstanceState) {
// Forces menu overflow icon
try {
ViewConfiguration config = ViewConfiguration.get(this.getApplicationContext()); //ERROR IN LOGCAT IN THIS LINE
#SuppressLint("SoonBlockedPrivateApi") Field menuKeyField = ViewConfiguration.class.getDeclaredField("sHasPermanentMenuKey");
if (menuKeyField != null) {
menuKeyField.setAccessible(true);
menuKeyField.setBoolean(config, false);
}
} catch (Exception e) {
LogDelegate.w("Just a little issue in physical menu button management", e);
}
super.onCreate(savedInstanceState);
}
MainActivity
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);//ERROR IN LOGCAT IN THIS LINE
setTheme(R.style.OmniNotesTheme_ApiSpec);
binding = ActivityMainBinding.inflate(getLayoutInflater());
View view = binding.getRoot();
setContentView(view);
EventBus.getDefault().register(this);
Prefs.getPreferences().registerOnSharedPreferenceChangeListener(this);
initUI();
if (IntroActivity.mustRun()) {
startActivity(new Intent(getApplicationContext(), IntroActivity.class));
}
}
Does anyone know how to deal with it? Any help will be appreciated.
Replace this.getApplicationContext() and getApplicationContext() with this. this appears to be an Activity in both places.

Android: ImageButton causes crash upon assigning it a listener

So, basically, I have an ImageButton called boutonPortail, and another called logo. Initializing boutonPortail works fine, but when I assign it its listener with boutonPortail.setOnClickListener(boutonPortailListener); the app crashes, and I don't know why at all. It's not a problem with the listener since when I assign it to logo it works just fine. I doubt it is a problem with the XML since I copy/pasted the code of logo.
My app prompts for a password, and if the password is correct it switches to another view with the logo and the boutonPortail. Note that the password prompt view also has the logo.
Is the problem that boutonPortail is not on the main view? I tried assigning the listener after switching views, but it still crashes.
EDIT: After putting the button in the main view, the problem is definitely that the button is not in the main view, when I put it in the main view it works fine. Why does it crashes though?
Also, for some reason I can't manage to change the image of the button with boutonPortail.setImageResource(R.drawable.boutonfermer);. (this doesn't happen when it is in the main view)
onCreate method:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
logo = (ImageButton)findViewById(R.id.logo);
boutonPortail = (ImageButton)findViewById(R.id.boutonPortail);
codeEntered = (EditText)findViewById(R.id.codeEntered);
codeSurNotice = (TextView)findViewById(R.id.codeSurNotice);
//attribute all listeners
logo.setOnClickListener(boutonPortailListener);
codeEntered.addTextChangedListener(textWatcher);
codeEntered.setOnKeyListener(codeEnteredListener);
Method to change view:
void codeCorrect() {
setContentView(R.layout.activity_readytopress);
boutonPortail.setOnClickListener(boutonPortailListener); //this line crashes the app, even if put in the onCreate
}
Listener:
private OnClickListener boutonPortailListener = new OnClickListener() {
#Override
public void onClick(View v) {
boutonState++;
if(boutonState>=4)
boutonState=0;
boutonPortail.setImageResource(R.drawable.boutonfermer);
}
};
XML:
<ImageButton
android:id="#+id/boutonPortail"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="40dip"
android:src="#drawable/boutonouvrir"
android:background="#00000000"
style="#00000000"
android:layout_gravity="center"
/>
Here's my full code if you want to test it (note that you'll have to call the codeCorrect() method manually since you don't have access to the bluetooth device I use):
MainActivity.java http://pastebin.com/ZXDahPZ6
activity_main.xml http://pastebin.com/f14cVBKj
activity_readytopress.xml http://pastebin.com/0iZm91eq
boutonouvrir.png http://puu.sh/mLGeU.png
ouvertureencours.png http://puu.sh/mLGfI.png
boutonfermer.png http://puu.sh/mLGe5.png
fermetureencours.png http://puu.sh/mLGgW.png
Thanks :)
You do not have a button with the id boutonPortail in activity_main.xml
It is crashing with a Null Pointer Exception.
You cannot add a listener to a null object.
Here is your relevant code:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// On récupère toutes les vues dont on a besoin
logo = (ImageButton)findViewById(R.id.logo);
boutonPortail = (ImageButton)findViewById(R.id.boutonPortail);
So you call setContentView(R.layout.activity_main) and then you call findViewById(R.id.boutonPortail)
The findContentView() will return null, because acitivty_main.xml does not have a view ID of that value. So now boutonPortail is null.
Then you call boutonPortail.setOnClickListener(boutonPortailListener) which will crash with a Null Pointer Exception because boutonPortail is null

when am I safe to query a View's dimensions?

I'm trying to grab the dimensions of a view in my activity. The view is a simple custom view which extends an ImageView:
<com.example.dragdropshapes.CustomStrechView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#drawable/border"
android:src="#drawable/missingpuz"
android:clickable="true"
android:onClick="pickShapes"
/>
I need to know what the specific "fill_parent" ends up being. I attempted to get this information during the onCreate method of the Activity using the layout containing my custom views:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_puzzle_picker);
// Show the Up button in the action bar.
setupActionBar();
int a = findViewById(R.id.pickshapes).getMeasuredHeight();
int b = findViewById(R.id.pickshapes).getHeight();
In this case, both a and b return a value of 0. Later, the custom view will be used as a button (it has an onClick handler) so I thought to try again to get the size in the handler:
public void pickShapes(View view){
Intent intent = new Intent(this, ShapesActivity.class);
int a = findViewById(R.id.pickshapes).getMeasuredHeight();
int b = findViewById(R.id.pickshapes).getHeight();
startActivity(intent);
}
Here a and b both give valid dimensions... I don't want to wait for a "onClick" event however, I want to get the dimensions as soon as possible. I've tried Overriding both onStart() and onResume() to check the dimensions as well, but in both cases I still get 0.
So my question is, where in the Android Activity start up flow, is the first place I can get the actual size of a View? I want to be able to get the height/width as soon as I can, and I want to do it before the user has a chance to interact with the environment.
There's a fairly useful thing in Android called the ViewTreeObserver. I've done precisely what you need to do many times this way. As you've discovered, you need to wait until at least the measure cycle completes. Try something like the following:
...
setContextView(R.layout.activity_puzzle_picker);
final View view = findViewById(R.id.pickshapes);
view.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
int height = view.getMeasuredHeight();
if(height > 0) {
// do whatever you want with the measured height.
setMyViewHeight(height);
// ... and ALWAYS remove the listener when you're done.
view.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
}
});
...
(Note that you haven't set the id of your view in your XML... I'm using R.id.pickshapes because that's what you chose.)

Run a method after View is created - Android

I've currently got an activity that creates a view. this view uses other classes (such as one to create a random sequence of integers). I need to run a method (which will display the sequence using bitmaps) once the view is created. So once the user clicks "Start Game" this sequence will be displayed.
I've tried calling the method after setting the content view inside the onCreate method by the sequence is not generated (all 0's) correctly. I've tries this also with onStart and onFinishInflate inside the myView class.
Is there a way i can run this method after everything is inflated and initialized? So after the user clicks "Start Game" and the view is changed, the method needs to run.
Thanks for looking.
Edit: A failed attempt.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.gameView = new GameView(getApplicationContext(), getCellSource(getApplicationContext()));
setContentView(this.gameView);
// this.gameView.displaySequence(this.gameView.gameEngine.getGenSequence()); Need this to run once view is displayed.
}
Try using ViewTreeObserver as follow:
final View yourView = View.inflate(....);
ViewTreeObserver observer = yourView .getViewTreeObserver();
observer.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
yourView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
// Do what you need with yourView here...
}
});
Notice that the function removeGlobalOnLayoutListener(this) is different in some sdk versions.

Tabs using Fragments on Android, but inside another Layout

I'm creating android app that has table layout for the main activity, and that part works perfectly... Now, the idea was to add another part of an app below the existing components, but now I have to put a tabbed layout there. Well, that part also works perfectly when I try to run just that. But what do I have to do to mix those two in such a way that these two show up one below another on the very same screen.
My main code is:
package my.android;
import android.os.Bundle;
public class MyActivity extends FragmentActivity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
}
I have different layout files for all the tabs and I have my TabsActivity class I have created following the tutorial here:
http://thepseudocoder.wordpress.com/2011/10/04/android-tabs-the-fragment-way/
So how do I add some TabsActivity ta object to the MyActivity? And it is important to be below the content of this. Thaks in advance...
Ideally this would be done using nested Fragments, but Android doesn't support that yet. That leaves the deprecated ActivityGroup class. You'll need a top level activity that extends ActivityGroup and launches the two activities.
Here is how you launch the activities and get their views:
final Window w = getLocalActivityManager().startActivity(myTag, myIntent);
final View wd = w != null ? w.getDecorView() : null;
if ( null != wd ) {
wd.setVisibility(View.VISIBLE);
wd.setFocusableInTouchMode(true);
}
// TODO: Attach wd to a ViewGroup.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Edit: Below is a more complete solution.
This is the layout for the top level activity:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/root_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
>
</LinearLayout>
Here is the top level class:
public class EmbeddedActivityParent extends ActivityGroup {
private LinearLayout mRootLayout;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mRootLayout = (LinearLayout) findViewById(R.id.root_layout);
// Add embedded status activity.
embedActivity("StatusColumn", new Intent(this, StatusActivity.class));
// Add embedded work activity.
embedActivity("WorkArea", new Intent(this, MainActivity.class));
}
private void embedActivity(String myTag, Intent launchIntent) {
final Window w = getLocalActivityManager().startActivity(myTag, launchIntent);
final View wd = w != null ? w.getDecorView() : null;
if ( null != wd ) {
wd.setVisibility(View.VISIBLE);
wd.setFocusableInTouchMode(true);
mRootLayout.addView(wd);
}
}
}
You can add as many embedded activities as you want. You can even nest embedded activities, but be aware that performance could become a factor. We use this to support a dynamic status column.
Personally, I think there is still a use for the ActivityGroup and hope that Gooogle changes their mind about deprecating it.

Categories