0

I have a Runnable class that ends up changing the text and color of a textview depending on a certain value that it gets from the SharedPreferences.

I tried creating the class inside a class that is calling the runnable at first, that worked fine, Now I wanted to put this class inside it's own class file to keep it clean and to be able to access it easily from other classes.

However I get a nullpointer now and after commenting some code out it seems like the textview is causing the problem.

This is my class

public class SettingsRunnable extends Activity implements Runnable {
View mView;
SharedPreferences mSettings;
SharedPreferences.Editor mEditSettings;
TextView mText;
CardScrollView mCardScroller;

public SettingsRunnable(View view, TextView text, SharedPreferences settings, CardScrollView cardView)
{
    this.mView = view;
    this.mText = text;
    this.mSettings = settings;
    this.mCardScroller = cardView;
    mEditSettings = mSettings.edit();
}

@Override
public void run() {
    try {
        if(mView == null)
        {
            mView = mCardScroller.getSelectedView();
        }
        String status = "";
        if (mSettings.contains("headgesture")) {
            status = mSettings.getString("headgesture", "");
            mText.setText(status);
            switch (status) {
                case "on":
                    mText.setTextColor(getResources().getColor(R.color.status_on));
                    break;
                case "off":
                    mText.setTextColor(getRecources().getColor(R.color.status_off));
                    break;
            }
        }
        if (mSettings.contains("network")) {
            status = mSettings.getString("network", "");
            //mText.setText(status);
            switch (status) {
                case "always":
                    break;
                case "wifi":
                    break;
                case "never":
                    break;
            }
        }
        mView.setTag(mText);
    }
    catch(Exception e)
    {
        Log.wtf("ErrorRun", e.getMessage());
    }
}
}

Then I've the following in my onCreate() in the class that is trying to call it.

mCards = new ArrayList<>();
    //android.os.Debug.waitForDebugger();
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
getWindow().requestFeature(WindowUtils.FEATURE_VOICE_COMMANDS); 

CreateCards();//is being used to add cards to the mCards list, these cards will be inflated in the mainAdapter

mCardScroller = new CardScrollView(this);
mCardScroller.setAdapter(new mainAdapter(mCards, getLayoutInflater()));

mCardScroller.setOnItemClickListener(this);

mGestureDetector = createGestureDetector(this);
card = new CardPosition(mCardScroller);//is being used to get the current position of the cardscroller
setContentView(mCardScroller);
settings = getSharedPreferences(PREFERENCE, PRIVATE);
view = new View(this);
mText = (TextView) findViewById(R.id.headgesture_status);
setR = new SettingsRunnable(view, mText, settings, mCardScroller);
handler.postDelayed(setR, 1000);

Edit

6086-6086/com.example.sw_stage.glass E/AndroidRuntime﹕ FATAL EXCEPTION: main
Process: com.example.sw_stage.glass, PID: 6086
java.lang.NullPointerException
        at com.example.sw_stage.glass.Runnables.SettingsRunnable.run(SettingsRunnable.java:42)
        at android.os.Handler.handleCallback(Handler.java:733)
        at android.os.Handler.dispatchMessage(Handler.java:95)
        at android.os.Looper.loop(Looper.java:149)
        at android.app.ActivityThread.main(ActivityThread.java:5045)
        at java.lang.reflect.Method.invokeNative(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:515)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:602)
        at dalvik.system.NativeStart.main(Native Method)

Edit 2

It seems that when I try to get the textview in my onCreate it returns null. I'm not completely sure why this is. The view should already be inflated and set at the point that this is being called. Actually when I put in this code to test it quickly it works perfectly. However it's dirty ofcourse

settings = getSharedPreferences(PREFERENCE, PRIVATE);
    view = new View(this);
    mText = (TextView) findViewById(R.id.headgesture_status);
    //handler.postDelayed(setR, 1000);
    handler.postDelayed(new Runnable() {
        @Override
        public void run() {
            mText = (TextView) findViewById(R.id.headgesture_status);
            setR = new SettingsRunnable(view, mText, settings, mCardScroller, false);
            handler.postDelayed(setR,0);
        }
    },0);

XML file

<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:background="@color/main_background">

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/settings_headgesture"
    android:gravity="center"
    android:textSize="47pt"/>
<TextView
    android:layout_height="wrap_content"
    android:layout_width="wrap_content"
    android:textAllCaps="true"
    android:textStyle="bold|italic"
    android:gravity="center"
    android:textSize="47pt"
    android:id="@+id/headgesture_status"/>

</LinearLayout>
NoSixties
  • 2,443
  • 2
  • 28
  • 65

2 Answers2

2

It's not a good idea to instantiate activity because Android manages activity lifecycle. Moreover, I don't think your should extend Activity and implement Runnable.

I suggest you can create the runnable in a separate class and instantiate it in onCreate. Also, you might consider moving some related code from the constructor to onCreate.

Edit:

I've checked Android source code. From my understanding, your code should throw java.lang.InstantiationException because your Activity doesn't have no zero argument constructor. (Android uses reflection to instantiate activity and the zero argument constructor is required.)

I am not sure why you can get away with that on Glass. Anyway, as I mentioned, you should separate the runnable to another class and move the code from the constructor to onCreate.

Please see

Community
  • 1
  • 1
pt2121
  • 11,720
  • 8
  • 52
  • 69
  • I already tried it without extending Activity. doesn't change anything. i know it's still a bit dirty, that's because I just started writing it from what I had in my class to it's own class – NoSixties Mar 18 '15 at 14:57
  • Could you post the log? – pt2121 Mar 18 '15 at 15:06
  • the exception just gives me null back but I'll take the try catch out and post the error I get then – NoSixties Mar 18 '15 at 15:08
0

I think the issue is that you are making changes on a text view belonging to a layout that has not been inflated in your Runnable class. I have not yet tested the following code, but you may find it helpful:

LayoutInflater inflater = (LayoutInflater) context.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
View mView = inflater.inflate(R.layout.<your XML file>, null);
mText = (TextView) mView.findViewById(R.id.headgesture_status);

The code explicitly inflates the layout XML file so you can get the text view.

Answer is based on Cristian's answer here and here.

Community
  • 1
  • 1
Koh
  • 1,570
  • 1
  • 8
  • 6
  • In the end it was caused by my view for sure. I ended up fixing it by using `mView = mCardScroller.getRootView();` I'll test your code too just for good measures – NoSixties Mar 31 '15 at 06:18