marco marco - 2 months ago 102
Android Question

New to Android App / Java development, working through some abnormalities

As the title says I am just getting started writing an Android smartphone application and it is the first time I have written in Java as well. I do have some experience with C/C++/Swift/iOS app development.

I have been watching tutorials and I have managed to get some basic things working with buttons but there are a few abnormalities I would like to change. For starters, it seems to only allow me to declare button variables and utilise them within the scope of the

onCreate()
method of my
main activity
in my code shown below.

public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

final boolean[] connect_btn_pressed = {false};

final ImageButton btn_up = (ImageButton) findViewById(R.id.btn_up);
final ImageButton btn_connect = (ImageButton) findViewById(R.id.btn_connect);
final TextView ble_status = (TextView) findViewById(R.id.bt_message);

btn_up.setVisibility(View.INVISIBLE);

btn_connect.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if(connect_btn_pressed[0] == false){
ble_status.setText("Connecting...");
btn_connect.setImageResource(R.drawable.btn_x1_bt_on);
btn_up.setVisibility(View.VISIBLE);
connect_btn_pressed[0] = true;
}
else {
ble_status.setText("Cancelled");
btn_connect.setImageResource(R.drawable.btn_x1_bt_off);
btn_up.setVisibility(View.INVISIBLE);
connect_btn_pressed[0] = false;
}
}
});
}


If I try to move everything outside the
onCreate()
method, I cannot use the
btn_up.setVisibility(View.INVISIBLE)
call as it has some issue with the
View.INVISIBLE
argument.

The keyword
final
was placed for me, and I am not sure why that was necessary.

Lastly, my
boolean
variable was also turned into an
array
with a single element as soon as I tried to refer to it within the
onClick()
method. I will just let that slide if it is truly necessary but it still bugs me that I cannot just use it a simple boolean element.

So how can I move these lines of code outside the scope of
onCreate()
? I will want to refer to these buttons in the
onPause()
method but they won't be accessible in this current state.

Why do my variables need to be declared
final
? And do I really need to declare my
boolean
flag as an
array
?

Edit:

Now I have my code set up like this:

public class MainActivity extends AppCompatActivity {

boolean connect_btn_pressed = false;

ImageButton btn_up = (ImageButton) findViewById(R.id.btn_up);
ImageButton btn_down = (ImageButton) findViewById(R.id.btn_down);
ImageButton btn_right = (ImageButton) findViewById(R.id.btn_right);
ImageButton btn_left = (ImageButton) findViewById(R.id.btn_left);
ImageButton btn_connect = (ImageButton) findViewById(R.id.btn_connect);
TextView ble_status = (TextView) findViewById(R.id.bt_message);

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

btn_up.setVisibility(View.INVISIBLE);
btn_down.setVisibility(View.INVISIBLE);
btn_right.setVisibility(View.INVISIBLE);
btn_left.setVisibility(View.INVISIBLE);

btn_connect.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(!connect_btn_pressed){
ble_status.setText(R.string.bt_statusmessage_connecting);
btn_connect.setImageResource(R.drawable.btn_x1_bt_on);
btn_up.setVisibility(View.VISIBLE);
btn_down.setVisibility(View.VISIBLE);
btn_left.setVisibility(View.VISIBLE);
btn_right.setVisibility(View.VISIBLE);
connect_btn_pressed = true;
}
else {
ble_status.setText(R.string.bt_statusmessage_cancelled);
btn_connect.setImageResource(R.drawable.btn_x1_bt_off);
btn_up.setVisibility(View.INVISIBLE);
btn_down.setVisibility(View.INVISIBLE);
btn_left.setVisibility(View.INVISIBLE);
btn_right.setVisibility(View.INVISIBLE);
connect_btn_pressed = false;
}
}
});

}




/*btn_left.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
return false;
}
});*/

/* Called when the user clicks the Send button */
public void sendMessage(View view) {
//
}

}


It builds and runs but now as soon as the activity is started my app crashes. This is my stack trace:

09/21 14:00:23: Launching app
Cold swapped changes.
$ adb shell am start -n "com.rcbot/com.rcbot.Splash" -a android.intent.action.MAIN -c android.intent.category.LAUNCHER
Connected to process 13828 on device samsung-sm_g930p-91daafa6
E/Zygote: v2
W/SELinux: Function: selinux_compare_spd_ram, index[1], priority [2], priority version is VE=SEPF_SECMOBILE_6.0.1_0012
E/Zygote: accessInfo : 0
W/SELinux: SELinux: seapp_context_lookup: seinfo=default, level=s0:c512,c768, pkgname=com.rcbot
I/art: Late-enabling -Xcheck:jni
I/libpersona: KNOX_SDCARD checking this for 10214
I/libpersona: KNOX_SDCARD not a persona
D/TimaKeyStoreProvider: TimaSignature is unavailable
D/ActivityThread: Added TimaKeyStore provider
I/InjectionManager: Inside getClassLibPath + mLibMap{0=, 1=}
I/InjectionManager: Inside getClassLibPath caller
W/ResourcesManager: getTopLevelResources: /data/app/com.rcbot-2/base.apk / 1.0 running in com.rcbot rsrc of package com.rcbot
D/ResourcesManager: For user 0 new overlays fetched Null
W/System: ClassLoader referenced unknown path: /data/app/com.rcbot-2/lib/arm64
I/InstantRun: Instant Run Runtime started. Android package is com.rcbot, real application class is null.
W/System: ClassLoader referenced unknown path: /data/app/com.rcbot-2/lib/arm64
D/InjectionManager: InjectionManager
D/InjectionManager: fillFeatureStoreMap com.rcbot
I/InjectionManager: Constructor com.rcbot, Feature store :{}
I/InjectionManager: featureStore :{}
W/ResourcesManager: getTopLevelResources: /data/data/com.rcbot/files/instant-run/right/resources.ap_ / 1.0 running in com.rcbot rsrc of package com.rcbot
D/ResourcesManager: For user 0 new overlays fetched Null
D/RelationGraph: garbageCollect()
D/ContextRelationManager: ContextRelationManager() : FEATURE_ENABLED=true
W/ResourcesManager: getTopLevelResources: /data/app/com.rcbot-2/base.apk / 1.0 running in com.rcbot rsrc of package com.rcbot
W/art: Before Android 4.1, method android.graphics.PorterDuffColorFilter android.support.graphics.drawable.VectorDrawableCompat.updateTintFilter(android.graphics.PorterDuffColorFilter, android.content.res.ColorStateList, android.graphics.PorterDuff$Mode) would have incorrectly overridden the package-private method in android.graphics.drawable.Drawable
D/Activity: performCreate Call Injection manager
I/InjectionManager: dispatchOnViewCreated > Target : com.rcbot.Splash isFragment :false
D/ViewRootImpl: #1 mView = com.android.internal.policy.PhoneWindow$DecorView{705cd69 I.E...... R.....ID 0,0-0,0}
D/OpenGLRenderer: Use EGL_SWAP_BEHAVIOR_PRESERVED: true
D/SecWifiDisplayUtil: Metadata value : SecSettings2
I/Adreno: QUALCOMM build : f3dae48, Ic65b418ec7
Build Date : 04/08/16
OpenGL ES Shader Compiler Version: XE031.06.00.05
Local Branch :
Remote Branch : refs/tags/AU_LINUX_ANDROID_LA.HB.1.1.1.C1.06.00.00.165.137
Remote Branch : NONE
Reconstruct Branch : NOTHING
D/libEGL: eglInitialize EGLDisplay = 0x7f64a3a188
I/OpenGLRenderer: Initialized EGL, version 1.4
I/InjectionManager: dispatchCreateOptionsMenu :com.rcbot.Splash
I/InjectionManager: dispatchPrepareOptionsMenu :com.rcbot.Splash
D/ViewRootImpl: MSG_RESIZED_REPORT: ci=Rect(0, 96 - 0, 0) vi=Rect(0, 96 - 0, 0) or=1
D/libGLESv1: DTS_GLAPI : DTS is not allowed for Package : com.rcbot
I/Timeline: Timeline: Activity_idle id: android.os.BinderProxy@da565f2 time:125966383
D/AndroidRuntime: Shutting down VM
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.rcbot, PID: 13828
java.lang.RuntimeException: Unable to instantiate activity ComponentInfo{com.rcbot/com.rcbot.MainActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'android.view.Window$Callback android.view.Window.getCallback()' on a null object reference
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3093)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3349)
at android.app.ActivityThread.access$1100(ActivityThread.java:221)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1794)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:158)
at android.app.ActivityThread.main(ActivityThread.java:7224)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'android.view.Window$Callback android.view.Window.getCallback()' on a null object reference
at android.support.v7.app.AppCompatDelegateImplBase.<init>(AppCompatDelegateImplBase.java:116)
at android.support.v7.app.AppCompatDelegateImplV9.<init>(AppCompatDelegateImplV9.java:147)
at android.support.v7.app.AppCompatDelegateImplV11.<init>(AppCompatDelegateImplV11.java:27)
at android.support.v7.app.AppCompatDelegateImplV14.<init>(AppCompatDelegateImplV14.java:50)
at android.support.v7.app.AppCompatDelegateImplV23.<init>(AppCompatDelegateImplV23.java:29)
at android.support.v7.app.AppCompatDelegate.create(AppCompatDelegate.java:199)
at android.support.v7.app.AppCompatDelegate.create(AppCompatDelegate.java:181)
at android.support.v7.app.AppCompatActivity.getDelegate(AppCompatActivity.java:521)
at android.support.v7.app.AppCompatActivity.findViewById(AppCompatActivity.java:190)
at com.rcbot.MainActivity.<init>(MainActivity.java:24)
at java.lang.Class.newInstance(Native Method)
at android.app.Instrumentation.newActivity(Instrumentation.java:1095)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3083)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3349) 
at android.app.ActivityThread.access$1100(ActivityThread.java:221) 
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1794) 
at android.os.Handler.dispatchMessage(Handler.java:102) 
at android.os.Looper.loop(Looper.java:158) 
at android.app.ActivityThread.main(ActivityThread.java:7224) 
at java.lang.reflect.Method.invoke(Native Method) 
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120) 


When I revert the changes the app runs just fine.

SOLVED:

The reason it was crashing was because I was attempting to set the declared variables with findViewById before it was ready. I fixed it by keeping the declarations above
onCreate()
and then moving the assignments to those variables inside it.

Answer

Do some changes like this

public class MainActivity extends AppCompatActivity {
boolean[] connect_btn_pressed ;
ImageButton btn_up,btn_connect ;
TextView ble_status;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        connect_btn_pressed = {false};

        btn_up = (ImageButton) findViewById(R.id.btn_up);
        btn_connect = (ImageButton) findViewById(R.id.btn_connect);
        ble_status = (TextView) findViewById(R.id.bt_message);

        btn_up.setVisibility(View.INVISIBLE);

        btn_connect.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                if(connect_btn_pressed[0] == false){
                    ble_status.setText("Connecting...");
                    btn_connect.setImageResource(R.drawable.btn_x1_bt_on);
                    btn_up.setVisibility(View.VISIBLE);
                    connect_btn_pressed[0] = true;
                }
                else {
                    ble_status.setText("Cancelled");
                    btn_connect.setImageResource(R.drawable.btn_x1_bt_off);
                    btn_up.setVisibility(View.INVISIBLE);
                    connect_btn_pressed[0] = false;
            }
        }
    });
}