I have a main activity which consists of spinner + 3 fragments (tabs). I want to access spinner value from fragment. So I wrote this code into onActivityCreated inside my fragment:
final Spinner spinner = (Spinner) getView().findViewById(R.id.spinnerOblasti);
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parentView, View selectedItemView, int position, long id) {
/*TextView[] vystrahy = new TextView[1];
vystrahy[0] = (TextView) getView().findViewById(R.id.txtVystrahy);
(new htmlParser(vystrahy, 0) ).execute(new Integer[]{spinner.getSelectedItemPosition()});*/
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
but when I run my application spinner throws nullpointerexception. Any ideas on how to access it from fragment?
Here is my onCreateView which I believe is causing problem but I dont know how to fix it:
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_tab1, container, false);
return rootView;
}
Thanks in forward
Doesn't work like that, what do you mean for spinner value? If you want to access to the spinner object you have to setup an interface which will be implemented by your activity and then in onActivityCreated you can call the method of that interface to do something. For example:
public class MyClass implements MyInterface {
public interface MyInterface {
void doSomethingWithSpinner();
}
public void doSomethingWithSpinner() {
mySpinner.setVisibility(View.VISIBLE);
}
}
And your onActivityCreated:
if(getActivity() instanceof MyInterface) {
((MyInterface)getActivity()).doSomethingWithSpinner();
}
Related
I have just one fragment attached to an activity using replace. When the device locks the screen after a few seconds and then I unlock it, the onItemSelected method assigned to some spinner gets executed, even though the fragment views (EditTexts and so) and the spinner selected item remains the same.
public class MyFragment extends Fragment {
private Spinner mySpinner;
public static MyFragment newInstance() {
return new MyFragment();
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.some_layout, container, false);
mySpinner = (Spinner)view.findViewById(R.id.my_spinner);
List<String> items = new ArrayList<>();
items.add("Anything");
items.add("Anything");
items.add("Anything");
ArrayAdapter<String> adapter =
new ArrayAdapter<String>(
getContext(),
android.R.layout.simple_spinner_item,
items);
mySpinner.setAdapter(adapter);
mySpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
Toast.makeText(getContext(), "Hello World", Toast.LENGTH_LONG).show();
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
return view;
}
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
}
}
Every time I select an item I get the toast message "Hello World" (or any other method or action assigned to the listener), but when the device locks and then I unlock, I'm still getting the message as if the method onItemSelected was called.
I've been trying to mess around with booleans and Fragment's onSaveInstanceState and onActivityCreated methods, but I haven't figured out a way to stop onItemSelected method from executing when the device returns from a locked screen.
The problem is that onItemSelected is called after Spinner is initialised, solution is to put mySpinner.setSelection(position, false) before mySpinner.setOnItemSelectedListener
refer to this
I have a problem when try to add setOnItemClickListener into a Fragment.
This is my Fragment.
public class LocalesFragmento extends Fragment {
ListView locales_list;
private List localesList;
private Context context;
public LocalesFragmento() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View vista = inflater.inflate(R.layout.locales_list, container, false);
locales_list = (ListView) vista.findViewById(R.id.localesList);
new getLocalesAsyncTask().execute();
return vista;
}
private void setListAdapter() {
Log.e("Adapter","Adapter...");
locales_list.setAdapter(new LocalesAdapter(getActivity(), getActivity(), localesList));
locales_list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long l) {
//detailInstagram(list.get(position));
}
});
}
The setOnItemClickListener is never executed. Any ideas?
Do I need to implement some other method?
Thanks.
Best regards.
You start your AsyncTask on onActivityCreated method because here before attaching the layout you are starting an async and that may be the reason why the listener is setting up.
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
locales_list.setAdapter(new LocalesAdapter(getActivity(), getActivity(), localesList));
locales_list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long l) {
//detailInstagram(list.get(position));
}
});
new getLocalesAsyncTask().execute();
}
Your LocalesAdapter might be the cause. You are passing the context (getActivity()) to the adapter twice.
locales_list.setAdapter(new LocalesAdapter(getActivity(), getActivity(), localesList));
Make your that the arguments passed to the LocalesAdapter are correct.
I developed an app which fills a list. It works fine in the way I did it but I'm not conviced that I solved the problem in a recommended way. I read that you should override onActivityCreated in a Fragment and fill the list there instead of doing this in onCreateView. onCreateView should only be used to inflate static views. Is this true? If yes, how should these two methods look like in the end?
This is my Fragment class:
public class FragmentMain extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_main, container, false);
List<MyItem> items = createListItems();
ListView listView = (ListView) view.findViewById(R.id.list);
MyListAdapter adapter = new MyListAdapter(view.getContext(), items);
listView.setAdapter(adapter);
listView.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
Toast.makeText(view.getContext(),
"Clicked " + position, Toast.LENGTH_LONG)
.show();
}
});
return view;
}
.
.
.
}
My MainActivity just adds the fragment:
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
FragmentMain fm = new FragmentMain();
getFragmentManager().beginTransaction()
.add(R.id.fragment_main_container, fm).commit();
}
.
.
.
}
That is true to a certain extend only because onCreateView happens on the UI thread and you don't want anything slowing that down otherwise your UI will be slow and choppy. For example, in your fragment class you have a call to a method "createListItems()". I don't know how many items you're making but if it's a lot it could slow down your UI (especially if youre accessing a database and querying objects and so on). So you could do it in onActivityCreated but you could also use an AsyncTask. So your code would become something like this:
public class LoadListObjectsTask extend AsyncTask<Void, List<MyItem>, Void> {
private MyListAdapter myListAdapter;
private Context mContext;
public LoadListObjectsTask(Context context) {
this.mContext = context;
}
#Override
public void doInBackground(Void...params) {
//create your list objects here instead of on UI thread. This will run on a separate thread.
myListAdapter = new MyListAdapter(mContext, items);
return items; //return list of MyItems
}
//This is called when doInBackground is done. THIS WILL RUN ON THE UI THREAD So don't do
//anything slow here
#Override
public void onPostExecute(List<MyItem>...params //don't really need the list here//) {
listView.setAdapter(myListAdapter);
}
}
then in your fragment
public class FragmentMain extends Fragment {
private ListView listView;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_main, container, false);
List<MyItem> items = new ArrayList<MyItem>();
listView = (ListView) view.findViewById(R.id.list);
//new code
new LoadListObjectsTask(getActivity()).execute();
listView.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
Toast.makeText(view.getContext(),
"Clicked " + position, Toast.LENGTH_LONG)
.show();
}
});
return view;
}
public void onResume()... {
//also add the task here so your content is reloaded on resume..
new LoadListObjectsTask(getActivity()).execute();
}
.
.
.
}
If you don't want to do this just make your List of MyItems a private field and move
List<MyItem> items = createListItems();
to onActivityCreated().
Hope that helps!
I have seen Link1 for this issue but could understand it right. I have a fragment that loads a list. When i click the list item it opens another activity. But i press back button it loads the list again. I want it to be at the same scroll position where it was before. In above mentioned link it specifies to use flag but i haven't got the point.
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_dashboard);
android.app.Fragment fragment = new MeFragment();
getFragmentManager().beginTransaction().replace(R.id.layout_FragmentsContainer, fragment).addToBackStack(null).commit();
}
}
public class MeFragment extends Fragment
{
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
return inflater.inflate(R.layout.fragment_me, container, false);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
meLV = (ListView) getView().findViewById(R.id.lv_Inbox);
loadingListProgress = (ProgressBar) getView().findViewById(R.id.progress_LoadingList);
meList = new ArrayList<Message>();
meAdapter = new MessagesListAdapter(getActivity(), meList);
//addFooter();
meLV.setAdapter(meAdapter);
meLV.setOnItemClickListener(this);
pageCount = 0;
loadmoreProgressDialog = new ProgressDialog(getActivity());
loadmoreProgressDialog.setTitle("Please wait ...");
loadmoreProgressDialog.setMessage("Loading more ...");
loadmoreProgressDialog.setCancelable(true);
loadUserMessages();
meLV.setOnScrollListener(new EndlessScrollListener() {
#Override
public void onLoadMore(int page, int totalItemsCount) {
// TODO Auto-generated method stub
//addFooter();
loadmoreProgressDialog.show();
loadUserMessages();
}
});
}
#Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
// TODO Auto-generated method stub
Utils.showToast_msg(getActivity(), "MessageItemClicked");
ReferralDetailFragment fragment = new ReferralDetailFragment();
getFragmentManager().beginTransaction().replace(R.id.layout_FragmentsContainer, fragment).addToBackStack(null).commit();
}
}
public class ReferralDetailFragment extends Fragment implements OnClickListener {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
View view = inflater.inflate(R.layout.fragment_referraldetail,container, false);
linkToAcknowledge = (TextView) view.findViewById(R.id.lbl_Link_to_Acknowledge);
return view;
}
}
I implemented a simple solution for this in my app, basically when you press back to go to the fragment again, onCreateView() is called. Here in onCreateView() you have done all initialization, so we change
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
View view = inflater.inflate(R.layout.fragment_me, container, false);
/*
*Whatever you want to do
*
*/
return view;
}
to:
View view;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
if(view==null){
view = inflater.inflate(R.layout.fragment_me, container, false);
/*
*Whatever you want to do
*
*/
}
else{
((ViewGroup)view.getParent()).removeView(view);
}
return view;
}
Here, we move View view outside and make it a class variable. So if it is the first time the fragment is called, it is null and the initialization occurs, otherwise it goes to else black. Else block is required because onCreateView() adds whatever it returns as a child of the view's parent, so since view is already there, we remove it and onCreateView automatically adds it again.
According to our exchange in the comments, I completely deletde my answer and re-write a new one.
I copy/paste the code from one of my apps and removing the useless things and changing the names. Hope there is not too many typing mistakes, at that it is the minimum required to have it working.
When I pop back to FirstFragment from SecondFragment, the scroll position of FirstFragment is the same as when I clicked an item to load the SecondFragment.
Note that I don't extend FragmentActivity. I have an activity which loads the fragments.
Extend/modify to match your needs.
MainActivity :
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_layout);
}
}
FirstFragment Class :
public class FirstFragment extends Fragment implements OnItemClickListener {
private ListView mListView;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.first_fragment_layout, container, false);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mListView = (ListView) getView().findViewById(R.id.listview_first_fragment);
mListView.setAdapter(mAdapter); // depends on your adapter
mListView.setOnItemClickListener(this);
}
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
mListView.setItemChecked(position, true);
//in case you need, set the bundle here, for example pass the position
Bundle arguments = new Bundle();
arguments.putInt("position", position);
SecondFragment secondFragment = new SecondFragment();
secondFragment.setArguments(arguments);
getFragmentManager().beginTransaction().replace(R.id.fragment_container, secondFragment).addToBackStack(null).commit();
}
}
SecondFragment Class :
public class SecondFragment extends Fragment {
private Integer mPosition;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.second_fragment_layout, container, false);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
Bundle arguments = getArguments();
if (arguments == null) {
mPosition= 0;
} else {
mPosition= arguments.getInt("Position");
}
}
}
What you are trying to achieve may be done with help of savedInstanceState. i also had this kind of problem which i resolved by using add() method instead of replace() in transition.
If you can change your method or already not using add() than give it a shot.
and if add() method didn't do the trick then check the implementation of savedInstanceState.
correctly save instance state.
How to save states of fragment views.
I can not get setOnItemClickListener of gridView in Fragment. What can be the problem?
Here is my code::
public class MainMenuFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.main_menu_fragment, container, false);
itemsGridViewObj = (GridView) view.findViewById(R.id.itemsGridView);
itemsGridViewObj.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> arg0, View arg1, int position,
long arg3) {
Log.d(TAG, "--> onItemClick listener..."); // Can not getting this method.
/*if(position == 1) {
FruitMenuFragment fruitMenuFragment = new FruitMenuFragment();
fragmentTransaction.replace(android.R.id.content, fruitMenuFragment);
fragmentTransaction.commit();
}*/
}
});
return view;
}
}`
You may need to set the following in your ButtonView.
android:focusable="false"
android:focusableInTouchMode="false"
see adding CheckBox to list row loses my onItemClick events?
When using Fragments the initialisation of the view occurs over two stages.
The view is only inflated (and therefore accessible) after the onCreateView method. This method is only for inflating a view and returning it to the Fragment.
Therefore, any logic to do with finding views and setting up onClickListeners should be done in the onActivityCreated() function as this is the first point at which you can access the inflated view.
Have a look at the Google docs at http://developer.android.com/reference/android/app/Fragment.html#Lifecycle
Below is you code adjusted to comply to what I have described above:
public class MainMenuFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.main_menu_fragment, container, false);
}
#Override
public void onActivityCreated(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
GridView itemsGridViewObj = (GridView) findViewById(R.id.itemsGridView);
itemsGridViewObj.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> arg0, View arg1, int position,
long arg3) {
Log.d(TAG, "--> onItemClick listener..."); // You should see this now
/*if(position == 1) {
FruitMenuFragment fruitMenuFragment = new FruitMenuFragment();
fragmentTransaction.replace(android.R.id.content, fruitMenuFragment);
fragmentTransaction.commit();
}*/
}});
}
}