Jay Castell Jay Castell - 1 month ago 11
Android Question

Android Studio - Using methods from outside classes with views

I'm having some difficulty with getting views in a method called from another class to function properly.

My app contains an experience bar present in the main activity (named Overlay) that tracks user progression using a progress bar. What I would like to do is have a separate method in another class that handles any code related to the experience bar.

I have already created an instance for the class and the method is called upon correctly, but certain android/view related pieces result in a crass. System.out.println will display text into the debugger, however the use of Toast and other views do not. Here are the two class files and the associated error.




public class OverlayActivity extends AppCompatActivity
implements NavigationView.OnNavigationItemSelectedListener {

NavigationView navigationView = null;
Toolbar toolbar = null;
int level = 0;
int addXP = 110;
ProgressBar experienceBar;
Button buttonXP;
TextView experienceLevel;
ExperienceManager exp;

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

//Set the Overlay Fragment

OverlayFragment fragment = new OverlayFragment();
android.support.v4.app.FragmentTransaction fragmentTransaction =
getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, fragment);
fragmentTransaction.commit();

toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);

FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Snackbar.make(view, "Hay! Don't touch me!", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
}
});

DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawer.setDrawerListener(toggle);
toggle.syncState();

navigationView = (NavigationView) findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(this);

experienceBar = (ProgressBar) findViewById(R.id.experienceBar);
experienceBar.setProgress(12);

experienceLevel = (TextView) findViewById(R.id.ds_appBar_level);

buttonXP = (Button) findViewById(R.id.buttonXP);
buttonXP.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View View) {
exp = new ExperienceManager();
exp.addExperience(level, addXP);
}
});
}





public class ExperienceManager extends AppCompatActivity {

ProgressBar experienceBar;

public int addExperience(int level, int addXP) {
experienceBar = (ProgressBar) findViewById(R.id.experienceBar);

int addLevel = 0;
while (addXP >= experienceBar.getMax()) {
addXP -= experienceBar.getMax();
addLevel += 1;
}
if (addXP >= experienceBar.getMax()-experienceBar.getProgress()) {

experienceBar.setProgress(experienceBar.getProgress() + addXP - experienceBar.getMax());
addLevel += 1;
} else {
experienceBar.setProgress(experienceBar.getProgress() + addXP);
}
if (addLevel >= 1) {
level += addLevel;
Toast toast = Toast.makeText(getBaseContext(), "Level up!", Toast.LENGTH_SHORT);
toast.show();
//experienceLevel.setText("Level " + level);
}
return level;
}





E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.teamcirelios.deepstone, PID: 4138
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.teamcirelios.deepstone.ExperienceManager.addExperience(ExperienceManager.java:15)
at com.teamcirelios.deepstone.OverlayActivity$2.onClick(OverlayActivity.java:77)
at android.view.View.performClick(View.java:5697)
at android.widget.TextView.performClick(TextView.java:10826)
at android.view.View$PerformClick.run(View.java:22526)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:158)
at android.app.ActivityThread.main(ActivityThread.java:7225)
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)





Likewise, a similar error results when trying to register a button click in a fragment. The experience bar itself displays with the Overlay acitvity, however for the app to work as intended it would need to receive an input to call that class from a button (or to be more accurate, a checkbox) inside a fragment.

The only solution that I could see working would be to take experienceBar.getMax() and similar and include them as parameters. However, I would need to return both the level and current xp, which to my knowledge isn't possible.

To basically sum everything up, I have three main questions.


  • What's the non-technical explanation for this error?

  • What is the best (and relatively simple) way to fix the code to achieve the desired function?

  • How can I register events inside a fragment?



Thank you!

Answer

First of all, your utility class, i.e. Experience manager should not extend AppCompatActivity... Your utility class is not an activity! PS you cannot findViewById your progressBar in the Experience Manager class since that ProgressBar isn't a part of your ExperienceManager Activity, It's a part of your OverlayActivity.

If you wish to create a static utility method for adding experience and managing it, You should write your code this way.

public class ExperienceManager{

public static int addExperience(ProgressBar experienceBar, int level, int addXP){

    int addLevel = 0;
    while (addXP >= experienceBar.getMax()) {
        addXP -= experienceBar.getMax();
        addLevel += 1;
    }
    if (addXP >= experienceBar.getMax()-experienceBar.getProgress()) {

        experienceBar.setProgress(experienceBar.getProgress() + addXP - experienceBar.getMax());
        addLevel += 1;
    } else {
        experienceBar.setProgress(experienceBar.getProgress() + addXP);
    }
    if (addLevel >= 1) {
        level += addLevel;
        Toast toast = Toast.makeText(getBaseContext(), "Level up!", Toast.LENGTH_SHORT);
        toast.show();
        //experienceLevel.setText("Level " + level);
    }
    return level;
}
}

And you can call this method this way :

buttonXP.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View View) {
            // Calling the static utility method over here...
            ExperienceManager.addExperience(experienceBar, level, addXP);

        }
});

That's all you need to do :)

I would recommend becoming familiar with Java design patterns and best programming practices before trying Android.

Comments