Classes & Activities in Android - android

Another Java/Android newbie...
My Activity contains a delcaration for a variable of a class that I've defined...
public Teams theTeams = null;
Within the onCreate method of this Activity, I create an object of that class...
Teams theTeams = new Teams();
I've been able to make some changes to this object...
theTeams.setName("A", "Jets");
... which assigns "Jets" to a string in the class.
However, from within a private method of the Activity, attempts to refer to "theTeams" give me a null pointer error. I guess there's something about object visibility that I'm not understanding. Can someone clarify?

You declared first public Teams theTeams = null;
Then in the onCreate method, you have this
Teams theTeams = new Teams();
So you are initializing a new theTeams object of type Team inside the onCreate, which you can see only in the scope of onCreate.
So when you call a method on theTeams in your private method, the method is called in the object you have declared first outside the onCreate (which is still null)
So inside, your onCreate, you have to use:
theTeams = new Teams();
Something like the following should work (untested):
private Teams theTeams = null;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
theTeams = new Teams();
}
private void myMethod() {
theTeams.getName();
}

Related

Wait for event when fragments fully initialized in FragmentPagerAdapter to setup them with data

I have an activity with collapsing AppBarLayout. In onCreate() method I am sending request to server to get some data. And depending what data I get - I need to dynamically in runtime choose what view to show to the user: 1. MyFragment1; or 2. TabLayout/ViewPager with FragmentPagerAdapter, which has two fragments in it. And I need to set some data to that fragments. But the issue is in next: I already have data and set it to fragments in my adapter, but fragment method onCreate is not yet called, and my layout is not initialized. That's how I get crash on populating data into layout view. So, how can I make somehow - fragment created and initialized it's fields first and only then setup it with data? Thanks.
private MenuFragment1 menu1Fragment1;
private MenuFragment3 menu1Fragment3;
private TabMenuAdapter adapter;
private void setupViewPager(ViewPager viewPager) {
menu1Fragment1 = new MenuFragment1();
menu1Fragment3 = new MenuFragment3();
adapter = new TabMenuAdapter(getSupportFragmentManager());
adapter.addFragment(menu1Fragment1, "Menu 1");
adapter.addFragment(menu1Fragment3, "Menu 2");
viewPager.setAdapter(adapter);
}
public onDataLoaded(String data)
{
//at this point, fragment is created, but it's View fields are NULL!!
menu1Fragment1.data = data;
}
#Layout(id = R.layout.content_shop_final)
public class ShopFinalTermsFragment extends BaseFragment {
private static final String SANS_SERIF_FAMILY_NAME = "sans-serif";
private static final String SANS_SERIF_MEDIUM_FAMILY_NAME = "sans-serif-medium";
private InfoModel InfoModel;
private RateModel RateModel;
#BindView(R.id.shop_final_nested_scroll_view)
NestedScrollView nestedScrollView;
#BindView(R.id.shop_final_pending_txt)
TextView pendingDurationTxt;
#BindView(R.id.shop_final_rate_cond_rv)
RecyclerView rateCondRv;
#BindView(R.id.shop_final_description_txt)
TextView descriptionTxt;
#Inject
ToolsManager toolsManager;
RateConditionsAdapter adapter;
private String getParams;
public static ShopFinalTermsFragment newInstance(String getParams, InfoModel shopInfoModel, RateModel RateModel) {
ShopFinalTermsFragment fragment = new ShopFinalTermsFragment();
Bundle args = new Bundle();
args.putString(SHOP_GET_PARAMS, shopGetParams);
args.putSerializable(INFO_MODEL_KEY, shopInfoModel);
args.putSerializable(MODEL_KEY, userCashbackRateModel);
fragment.setArguments(args);
return fragment;
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
this.GetParams = getArguments().getString(SHOP_GET_PARAMS);
this.InfoModel = (InfoModel) getArguments().getSerializable(INFO_MODEL_KEY);
this.RateModel = (RateModel) getArguments().getSerializable(RATE_MODEL_KEY);
}
}
#Override
protected void setupInOnCreateView() {
nestedScrollView.setVisibility(View.VISIBLE);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
conditionsTxt.setTypeface(Typeface.create(SANS_SERIF_FAMILY_NAME, Typeface.BOLD));
} else {
conditionsTxt.setTypeface(Typeface.create(SANS_SERIF_MEDIUM_FAMILY_NAME, Typeface.NORMAL));
}
}
#Override
protected void inject() {
ShopsComponent shopsComponent = DaggerShopsComponent.builder()
.applicationComponent(((BaseActivity) getActivity()).getApplicationComponent())
.build();
shopsComponent.inject(this);
}
public void setupWithData(InfoModel InfoModel, RateModel RateModel) {
//THIS METHOD IS COLLED FROM ACTIVITY'S onDataLoaded(InfoModel InfoModel, RateModel RateModel) method
setupShopInformation(shopInfoModel);
setCashBackRateModel(userCashbackRateModel);
}
}
You are using the dependency in a wrong way. It's not the activity that should call setupWithData on a fragment but it should be a fragment getting data from the activity (or other storage) instead. This way you will break this dependency on the fragment lifecycle which ends up being uninitialized.
Get the data from the server, store it where you need to, and update the UI from your activity. At this point you either show MyFragment1 or your TabLayout/ViewPager. If it's a TabLayout or a ViewPager, all you do is creating fragments and adding the to the layout or a corresponding pager adapter. That's it. You don't set the data at this point.
Now when your inner fragments populate in the pager adapter, they will go through onAttach, onCreate, onStart and onResume lifecycle methods. onResume is a good place to load the data. You either access it directly from the fragment, or get it from your outbound activity - depends on what makes more sense for you. If you need an activity reference, you can access it via getActivity() method in the fragment.
So in the fragment's onResume you will have something like:
setupShopInformation((YourActivity) getActivity()).getShopInfoModel());
setCashBackRateModel((YourActivity) getActivity()).getUserCashbackRateModel());
Although it would be even better to have it stored in some state class. But that will be a separate question.
Good luck!

Getting string resource from xml file outside onCreate method

I am trying to use a String from the string.xml file as a key in a key-value pair. However when I try to declare the variable before the onCreate() method, the program crashes. So if I use the following code I get an error:
public class MainActivity extends ActionBarActivity {
String MAX_SQUAT = getResources().getString(R.string.max_squat);
protected void onCreate(Bundle savedInstanceState) {
//blah blah blah
}
}
Whereas when I declare MAX_SQUAT inside the onCreate() method, there is no problem. I want to declare it outside of onCreate() method so I don't need to define it in other methods
You need a Context to get resources (as you can see in the Docs getResources() is a method of Context). Since the Context isn't available before onCreate(), you can't do this.
You can declare the variable before onCreate() but you can't initialize it until after onCreate() has been called.
Ex.
public class MainActivity extends ActionBarActivity {
String MAX_SQUAT;
protected void onCreate(Bundle savedInstanceState) {
// super call, set content view
// now you can get the string from strings.xml safely
MAX_SQUAT = getResources().getString(R.string.max_squat);
}
Declaring it as a member variable this way but initializing it in onCreate() will allow you to use it throughout the class and keep it from crashing.

Add view outside of onCreate in android

How can I add view bye function, outside of onCreate() in Android ?
My MainActivity.java
public class Main extends Activity {
static RelativeLayout mainRel;
static LinearLayout ll;
static TextView title;
static Context context;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
RelativeLayout mainRel=(RelativeLayout) findViewById(R.id.mainRel);
}
public static void refresh(){
LinearLayout ll = new LinearLayout(this); // actually "this" just works in onCreate;
TextView title = new TextView(this);// actually "this" just works in onCreate;
ll.setOrientation(LinearLayout.HORIZONTAL);
ll.addView(title);
title.setText("TV");
mainRel.addView(ll);
}
}
}
Thanks in advance
Usually, UI-related operations are not done in static methods. If you remove the static keyword, the this pointer will work even outside onCreate().
If you insist on keeping the static keyword (because you need the method to be static) then, you should pass a Context parameter to the method, by changing it to refresh(Context context)
Edit: if you need to call this method from another class, you might want to create a reference to your Main Activity and pass it to this other class, then call myMainActivity.refresh()
Calling static method is really bad idea.
Instead you can provide reference of the Activity to your AsyncTask in constructor. Then call non-static refresh() method from AsyncTask#onPostExecute().
When you store reference to Activity in AsyncTask use WeakReference. In case your activity is destroyed while background task is working, it won't be held in memory till background ends.
public class YourAsyncTask extends AsyncTask<Void, Void, Void> {
private WeakRefrence<Main> mainRef;
public YourAsyncTask(Main activity) {
mainRef = new WeakReference<Main>(activity);
}
protected void onPostExecute(Void result) {
Main main = mainRef.get();
if (main != null) {
main.refresh();
}
}
}

Data in arrays isn't persisted

In my Android activitity, I am using two different arrays. First, I am declaring them, and then in the onCreate() method, I am instantiating them. However, when I populate them and then change the orientation, they are getting instantiated again in the and the data is lost.
public class MainActivity extends Activity {
private JSONArray first;
private JSONArray second;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
interestedSections = new JSONArray();
productsBought = new JSONArray();
}
//...
}
I tried to add if (savedInstanceState != null) before initializing the arrays, so as to initialize them for the first time only, however when I change the orientation, they are being null. What can I do in order to persist the data in the arrays throughout the whole application lifecycle please?
Check out this answer as onCreate is called when the screen is rotated:
Activity restart on rotation Android
Edit: If you want a quick and dirty way to make it work, just have a static initialized boolean and set it to true onCreate. Don't set the arrays to new arrays if initialized is true.
See onSaveInstanceState(), this is where you are supposed to save your arrays to the bundle.
By the way, Android sometime can kill the process and restore the activities later; the static variables will not survive this.
I had to declare the arrays as static and in the onCreate() method, I initialize them only for the first time:
public class MainActivity extends Activity {
private static JSONArray first;
private static JSONArray second;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
if (savedInstanceState == null) {
first = new JSONArray();
second = new JSONArray();
}
}
//...
}

Why does not this work - Android - onCreate()

The following code does not work, and throws a RuntimeException caused by NullPointerException
public class ListFilteredActivity extends Activity {
LinearLayout typeSelector = new LinearLayout(this) ;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ScrollView sv = new ScrollView(this);
this.setContentView(sv);
//this.typeSelector = new LinearLayout(this);
this.typeSelector.setOrientation(LinearLayout.VERTICAL);
sv.addView(this.typeSelector);
}
When I moved the initialization of this.typeSelection inside onCreate() it works great.
#Override
public void onCreate(Bundle savedInstanceState) {
...
this.typeSelector = new LinearLayout(this);
...
}
Why is the null pointer error? The inline declaration in the first piece of code happens as soon as constructor is called, and then the onCreate() has access to the object, isn't it?
LinearLayout requires you pass in a Context. This is an Android lifecycle object and not a Java object. When declaring and initializing the field directly, this will be initialized using the Java default constructor. However you'll only get a context once the onCreate lifecycle method occurs, which is much, much later and part of Android, not Java. So when you call the LinearLayout constructor with this, Android is expecting a reference to a Context, which you only get after the call to onCreate.

Categories

Resources