Reputation: 6778
I have a Fragment
with a TableLayout
. The data in the table is from a SQLite db. The SQLite db is populated from a RESTful webservice in an AsyncTask
in the MainActivity
. The Fragment
must wait for the task to complete before populating the table. The Fragment
listens for the task onPostExecute()
method to be called. When it is, the method onLoadAndStoreComplete()
in the Fragment
is called. This all works.
I need to get a view of a TableLayout
outside the OnCreateView()
method of a Fragment. If I could get the View of the fragment in onLoadAndStoreComplete
that would get me there.
Same code as here.
I've got mContext
from the MainActivity, but that has no getView()
method associated with it.
I've tried:
- making a class member rootView and assigning in onCreateView(), but in onLoadAndStoreComplete()
, it is null.
- making a class member tableLayout and assigning in onCreateView(), but in onLoadAndStoreComplete()
, it is null.
- calling this.getView() again in onLoadAndStoreComplete()
, but it returns null.
- calling the inflator inside onLoadAndStoreComplete()
, which works, but then I don't know what to use for container in the .inflate()
call
I don't understand why the class member values of rootView and tableLayout are null in onLoadAndStoreComplete()
public class MyFragment extends Fragment implements OnLoadAndStoreCompleteListener {
private TableLayout tableLayout;
private View rootView;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
mContext = this.getActivity();
rootView = inflater.inflate(R.layout.fragment_permits, container, false); // this works
tableLayout = (TableLayout) rootView.findViewById(R.id.main_table); // and this
...
}
@Override
public void onLoadAndStoreComplete() {
// rootView is null, ie not remembered from OnCreateView
View view = getView(); // null
LayoutInflater inflater = LayoutInflater.from(getActivity());
rootView = inflater.inflate(R.layout.fragment_permits, container, false); // container? don't know what it should be
// tableLayout is null
tableLayout.addView(tableRow, new TableLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
}
...
}
Upvotes: 16
Views: 22268
Reputation: 1635
If I understand your code correctly, there is something wrong either with your code not respecting Fragment lifecycle or a different Fragment instance failure.
A. Lifecycle problem
Android framework expects your Fragment to create its view inside onCreateView()
method. View becomes available after framework calls this method.
It is possible that your code called onLoadAndStoreComplete()
before onCreateView()
, and this has caused the problem.
You need to extract method for populating actual views with data, as it can have 2 entry points. Please see code below:
public class MyFragment extends Fragment implements OnLoadAndStoreCompleteListener {
private TableLayout tableLayout;
private View rootView;
private SomeDataClass loadedData;
@Override
public View onCreateView(LayoutInflater inflater,
ViewGroup container,
Bundle savedInstanceState) {
mContext = this.getActivity();
rootView = inflater.inflate(R.layout.fragment_permits, container, false);
tableLayout = (TableLayout) rootView.findViewById(R.id.main_table);
updateUi(); // If onLoadAndStoreComplete() was already called
// this will plug newly created view to returned data
}
@Override
public void onLoadAndStoreComplete() {
loadedData = ...; // Save loaded data here
updateUi(); // If onCreateView() was already called
// this will plug loaded data to the view
}
private void updateUi() {
if (rootView == null) { // Check if view is already inflated
return;
}
if (loadedData != null) {
// View is already inflated and data is ready - update the view!
...
}
}
}
B. Different instance failure
This may occur when you're operating on 2 different instances of before mentioned fragment.
At first everything will look in order: onCreateView()
called before onLoadAndStoreComplete()
. Therefore check these:
onCreateView()
is the exact same object that called onLoadAndStoreComplete()
, you can use System.identityHashCode(this)
, getting different values within this two methods is a bad signIf this is what happens, cause is probably hidden a bit deeper, and without code I cannot give you accurate advice on this. How do you create your fragment? Via XML or manually then adding via FragmentManager or via ViewPager?
Upvotes: 11
Reputation: 1170
From your code fragment, if fields rootView
and tableLayout
are initialized after calling onCreateView(..)
, if both fields are not setted to null after that then they must be not null when you call onLoadAndStoreComplete(..)
.
Said that, I think you are calling that method in a different instance of your fragment. Review your activity code and check that you are using the same instance from the fragment all the time.
Upvotes: 2
Reputation: 196
You can make several fixes :
If the async task is called before the fragment is launched, then your callback onLoadAndStoreComplete may be called before the onCreateView (and all your views are not inflated)
You can execute the asyncTask from onCreateView, but you have to display a loader to tell user that app is syncing
You can also use a listview and not a tableLayout :
public class MyFragment extends Fragment implements OnLoadAndStoreCompleteListener {
private ListView listView;
private View rootView;
private MyAdapter adapter;
private List<T> mDatas; /// This one is populated like you want, from onLoadAndStoreComplete
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
mContext = this.getActivity();
rootView = inflater.inflate(R.layout.fragment_permits, container, false); // this works
listView = (ListView) rootView.findViewById(R.id.main_table); // and this
mDatas = new List<>();
adapter = new MyAdapter();
tableLayout.setAdapter(adapter);
}
@Override
public void onLoadAndStoreComplete() {
adapter.notifyDataSetChanged();
}
private class MyAdapter extends BaseAdapter{
@Override
public int getCount() {
// TODO Auto-generated method stub
return mDatas.size() == 0 ? 1 : mDatas.size();
}
@Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return mDatas.get(position);
}
@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (mDatas.size()==0){
// inflate new view with only a progressbar indefinite
LayoutInflater inflater = (LayoutInflater) getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.row_loading, parent, false);
return convertView;
}
else{
// list is populated
LayoutInflater inflater = (LayoutInflater) getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.row_datas, parent, false);
// do inflating view stuff
return convertView;
}
}
}
You need to modify your tableLayout to a ListView (inside RelativeLayout?)
Upvotes: 1
Reputation: 719
Are you sure that onLoadAndStoreComplete() is called after onCreateView()? The only reason for instance variables to be null is that the method which initializes them is not being called.
I suggest you to put a call to Log.d in onAttach, onDetach, onCreate, onCreateView, onStart, onStop,onLoadAndStoreComplete to see the in which order are called. After that, update your question with the log output to see which could be the problem and probably I could give you a more concise answer.
Upvotes: 1
Reputation: 10038
getView()
gives rootView of Fragment which is returned from onCreatedView()
. So if onLoadAndStoreComplete()
gets called before onCreatedView()
is finished (which it can't return your rootView), you get null
since there is not view created yet.
I have tried calling getView()
inside onViewCreated()
which is NOT null:
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
View viewer=getView();
if(viewer==null){
Itu.showToast("null",getActivity(), Toast.LENGTH_LONG);
}else{
Itu.showToast(viewer.toString(),getActivity(), Toast.LENGTH_LONG);//This is called
}
}
Upvotes: 8
Reputation: 519
I need to get a view of a TableLayout outside the OnCreateView() method of a Fragment. If I could get the View of the fragment in onLoadAndStoreComplete that would get me there.
Try changing the definition of onLoadAndStoreComplete to take a View and then passing in a view of the fragment.
Upvotes: 1