I wanna add clickableItems to Listview. But my problem is, that my class extands Fragment and i can not do that easily. Additionaly i wanna by clicking the item change the page to another page. My code is:
public class MyCoursesFragment extends Fragment implements OnItemClickListener, OnClickListener {
private static final String TAG = MyCoursesFragment.class.getName();
private ListView listView;
String listItem[]={"Vl1", "VL2"};
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View layout = inflater.inflate(R.layout.mycourses_layout, container, false);
listView = (ListView) layout.findViewById(R.id.Course);
listView.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
Intent intent = new Intent(getActivity().getBaseContext(), DocumentFragment.class);
intent.putExtra("id", "1");
listView.getContext().startActivity(intent);
FrontPageFragment.this.startActivity(intent);
}
});
return layout;
}
#Override
public void onItemClick(AdapterView<?> adapter, View view, int position, long id) {
}
}
can you guys pls help me.
THX
Change this line because your context is wrong:
listView.getContext().startActivity(intent);
FrontPageFragment.this.startActivity(intent);
You need to start a new activity in the following way:
Intent intent = new Intent(getActivity(),DocumentFragment.class);
startActivity(intent);
What you can to do is set up a callback Interface and control everything from your parent Activity.
Your Activity should implement the interface and your Fragment should call those methods when your View or list item gets clicked.
Something along the lines of:
interface
public interface OnListItemClickCallback {
public void onListItemShortClick(View view);
public void onListItemLongClick(View view);
}
Fragment
public MyListFragment extends ListFragment
implements OnItemClickListener, OnItemLongClickListener {
private OnListItemClickCallback clickCallback;
...
#Override
public void onAttach(Activity activity)
{
super.onAttach(activity);
// make sure the parent activity implements your interface
try
{
clickCallback = (OnListItemClickCallback) activity;
}
catch (ClassCastException e)
{
Log.e(TAG, "Parent Activity doesn't implement OnListItemClickCallback");
throw new ClassCastException(activity.toString()
+ " must implement OnListItemClickCallback");
}
}
#Override
public View onCreateView(Bundle b) {
...
getListView().setOnListItemClickListener(this):
getListView().setOnListItemLongClickListener(this):
}
#Override
public void onItemClick(...) {
clickCallback.onListItemShortClick(view)
}
// same idea for long click if you want it
}
Activity
public MyActivity extends Activity
implements OnListItemClickCallback {
...
#Override
public void onListItemShortClick(View view) {
// do something like replace your fragment
}
#Override
public void onListItemLongClick(View view) {
// do something else
}
}
Related
I have an activity with some fragments of the same type.
In fragments I have a list. As soon as I click on a list item, I need to invoke an activity method, passing the fragment where the click took place.
I think this is a rather silly question, but I can't figure it out.
public class MapFragment extends Fragment {
Activity activity;
public void onAttach(Activity activity) {
super.onAttach(activity);
this.activity = activity;
}
public MapFragment() {
/* here I could refer to the fragment using "this" */
}
private class MyListOnItemClick implements AdapterView.OnItemClickListener {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
/* how can I refer to the fragment here? */
Fragment f = getFragmentSomeWay();
(CustomActivity)activity.doSomethingWith(f);
}
}
}
Just refer to the enclosing class this:
Fragment f = MapFragment.this;
Your Fragment can implement AdapterView.OnItemClickListener.
public class MapFragment extends Fragment implements AdapterView.OnItemClickListener {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
requireActivity().doSomethingWith(f);
}
Some people would actually just use an anonymous class here.
adapter.setOnItemClickListener(AdapterView.OnItemClickListener listener = new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(final AdapterView<?> adapterView, final View view, final int i, final long l) {
requireActivity().doStuff();
}
};
I would like to call activity function from Adapter. I am trying something like this:
((MainActivity)mCtx).SampleVoid();
But i've got the error: java.lang.ClassCastException: android.app.Application cannot be cast to
public void SampleVoid(){
Toast.makeText(this,"Testowa metoda",Toast.LENGTH_LONG).show();
}
That error is happening because you are trying to cast the Application context to the Activity context. First of all, I wouldn't recommend you sending and storing context inside the adapter. I would recommend you to create an interface for communication back to the Activity at specific action from the adapter. For example:
Activity code:
SomeAdapter adapter = new SomeAdapter();
adapter.setOnAdapterActionListener(new OnAdapterActionListener() {
#Override
public void onSomeAdapterAction() {
Toast.makeText(this,"Testowa metoda",Toast.LENGTH_LONG).show();
}
});
Adapter code:
public class SomeAdapter extends ArrayAdapter<String> { // extend from the same adapter that you are extending now.
private OnAdapterActionListener onAdapterActionListener;
public SomeAdapter(#NonNull Context context, int resource, #NonNull List<String> objects) {
super(context, resource, objects);
}
#NonNull
#Override
public View getView(int position, #Nullable View convertView, #NonNull ViewGroup parent) {
View view = super.getView(position, convertView, parent);
view.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(onAdapterActionListener != null) {
onAdapterActionListener.onSomeAdapterAction();
}
}
});
return view;
}
public void setOnAdapterActionListener(OnAdapterActionListener onAdapterActionListener) {
this.onAdapterActionListener = onAdapterActionListener;
}
}
interface OnAdapterActionListener {
void onSomeAdapterAction();
}
You can pass the activity through the Adapter constructor.
Generally you do this through interfaces
public class MainActivity extends AppCompatActivity implements MAdapter.Listener {
private MAdapter mAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mAdapter = new MAdapter(this);
}
#Override
public void onClick(int position) { }
}
Then
public class MAdapter {
private Listener listener;
MAdapter(Listener listener){
this.listener = listener;
}
interface Listener {
void onClick(int position);
}
}
I have Fragments with a play button in my fragment. Whenever the user presses the play button from the ViewPager fragment, it calls a function in host activity which plays the player.
I am trying to implement the live data by using a ViewModel but unsuccessful.
public class SlidePlayerFragment extends Fragment {
private MyViewModel viewModel;
#Override
public View onCreateView(#NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
final View view = inflater.inflate(R.layout.fragment_slide_player, container, false);
ImageView playBtn = view.findViewById(R.id.playBtn);
playBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
viewModel.getIsPlaying().setValue(true);
viewModel.getCheck().setValue("Checking");
}
});
return view;
}
}
}
Here's my PagerAdapter
public class MyViewPagerAdapter extends FragmentStatePagerAdapter {
private int pages;
public MyViewPagerAdapter(FragmentManager fm,int count) {
super(fm);
pages = count;
}
#Override
public Fragment getItem(int i) {
return new SlidePlayerFragment();
}
#Override
public int getCount() {
return pages;
}
}
Here is the view model function
private MutableLiveData<Boolean> isPlaying;
public MutableLiveData<Boolean> getIsPlaying() {
if (isPlaying == null)
isPlaying = new MutableLiveData<>();
Log.d("TAG","Checking "+isPlaying.getValue());
return isPlaying;
}
And here is the observer segment
final Observer<Boolean> isPlaying= isPlaying -> {
//code here if playing then do some task here
};
viewModel.getIsPlaying().observe(this,isPlaying);
Note I already tried to find the predefined solution but I didn't find anything.
You do not really have to have a ViewModel for this purpose. You might just consider having public functions in the Activity which hosts the Fragments. For example, let us consider you have the following public functions in your PlayerActivity which launches all the other fragments.
public void play(String songName) {
viewModel.getIsPlaying().setValue(true);
viewModel.getCheck().setValue("Checking");
// Other actions for playing
}
Now, you might just consider the following onClick function instead of the one you are having now.
playBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
((PlayerActivity) getActivity()).play(songName);
}
});
Hope that helps!
I'm pretty new at Android, so I've already seen similar questions like mine, but I still can't send a Text to another fragment. I get this following error:
java.lang.NullPointerException: Attempt to invoke virtual method '
Here's the code, for better understanding...
FragOne
public class FragOne extends Fragment {
SendDados enviar;
String NumPessoas;
public interface SendDados{
void setdados(String numPessoas);
}
#Override
public void onAttach(Activity activity){
super.onAttach(activity);
try{ enviar=(SendDados)activity;
}catch (ClassCastException e){
throw new ClassCastException("erro");
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
final View rootView = inflater.inflate(R.layout.reserva_layout, container, false);
final TextView numero=(TextView)rootView.findViewById(R.id.qtdPessoas);
reservar.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
NumPessoas= numero.getText().toString();
enviar.setdados("1");
}
});
FragTwo
public class FragTwo extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
final View rootView = inflater.inflate(R.layout.confirm_reserva_layout, container, false);
numeroPessoas=(TextView)rootView.findViewById(R.id.numPessoas);
return rootView;
}
public void UpdateDados(String numPessoas)
{
numeroPessoas.setText(numPessoas);
}
Activity
public class MenuActivity extends AppCompatActivity
implements NavigationView.OnNavigationItemSelectedListener,ReservaFragment.SendDados {
#Override
public void setdados(String numPessoas) {
ConfirmaReservaFragment cf= (ConfirmaReservaFragment)getSupportFragmentManager().findFragmentById(R.id.confirmaReserva);
cf.UpdateDados(numPessoas);
}
What I need to do is this, when I click the button, the textView from FragOne, must be copied to FragTwo, what am I doing wrong here? I always get this error:
java.lang.NullPointerException: Attempt to invoke virtual method '
I appreciate any help.
Since we are talking about simple TextViews, copying the whole TextView to send it to another fragment seems too complicated for a simple job. Just send a String and display the text inside a new TextView inside FragTwo.
I recommend reading this link for passing parameters to fragments before their construction.
If you insist on passing TextViews as parameters to fragments then you are going to have to find a way to serialize TextViews (I don't think they implement Parcelable) and that won't be a simple job.
Regarding your code:
Names of objects start with small caps (first snippet).
Names of methods start with small caps (last snippet).
Use instanceof in onAttach (first snippet).
I don't see what ConfirmaReservaFragment is?
Also I really really recommend you type your code in English.
Fragments should comunicate through an activity so i will post you a short example of how to correctly send data from one fragment to another using a host activity:
First we will use this layout named host activity layout with a framelayout as a parent called host_fragment_container :
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/host_fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
now we are going to load our host activity and set this layout as a content view and create a basic method to change fragments on this frame layout :
public class HostActivity extends AppCompatActivity
implements TextViewContainerFragment.textViewClickListener{
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.host_activity_layout);
}
private void switchFragment(Fragment fragment) {
getSupportFragmentManager().beginTransaction()
.replace(R.id.host_fragment_container, fragment)
.commit();
}
}
Now lets create our first fragment (the one who will send the text) :
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:id="#+id/text_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
we will use this same xml file for both sender and receiver fragments
public class TextViewContainerFragment extends Fragment {
public interface textViewClickListener {
void onTextViewClicked(String value);
}
private textViewClickListener mActivityCallback;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.text_view_container_fragment, container, false);
}
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
final TextView textView = (TextView) view.findViewById(R.id.text_view);
//search the view by id and cast it into a text view the set it on click lsitener
textView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// now if the cast was successful the activity callback will be valid and ready to use
// but we are going to check if its valid anyways
if (mActivityCallback != null) {
mActivityCallback.onTextViewClicked(textView.getText().toString());
}
}
});
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
// if context is extracted from an activity
// that means its safe to cast
if (context instanceof Activity) {
mActivityCallback =
(textViewClickListener) context;
}
}
// factory method
public static TextViewContainerFragment newInstance() {
return new TextViewContainerFragment();
}
}
now that we have our interface on the fragment we will implement it on the host activity to listen for callbacks & its going to call a sencond fragment ot display the sent text :
public class HostActivity extends AppCompatActivity
implements TextViewContainerFragment.textViewClickListener{
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.host_activity_layout);
if (savedInstanceState == null) {
switchFragment(TextViewContainerFragment.newInstance());
}
}
private void switchFragment(Fragment fragment) {
getSupportFragmentManager().beginTransaction()
.replace(R.id.host_fragment_container, fragment)
.commit();
}
#Override
public void onTextViewClicked(String value) {
switchFragment(TextReceiverFragment.newInstance(value));
}
}
Here is the code for the receiver fragment (older fragment will be replaced for this one) :
public class TextReceiverFragment extends Fragment {
public static final String ARG_TEXT_RECEIVED_FROM_ANOTHER_FRAGMENT = "text";
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.text_view_container_fragment, container, false);
}
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
((TextView) view.findViewById(R.id.text_view)).setText(getArguments() != null ?
getArguments().getString(ARG_TEXT_RECEIVED_FROM_ANOTHER_FRAGMENT)
: "No text was sent from another fragment");
}
public static TextReceiverFragment newInstance(String text) {
TextReceiverFragment fragment = new TextReceiverFragment();
Bundle argument = new Bundle();
argument.putString(ARG_TEXT_RECEIVED_FROM_ANOTHER_FRAGMENT,
text);
fragment.setArguments(argument);
return fragment;
}
}
If you really want to copy the textview from Fragment 1 to Fragment 2. I suggested you to send the config data (e.g. the text, clicked, color) of the textview instead of the whole object. As the response from Spidey ,sending the widget to other fragment will be a trouble.
To facilitate your work, A textview config model should be used to send the config data of the textview.
public class TextViewConfig implements Parcelable {
private String text;
private boolean selected;
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(this.text);
dest.writeByte(this.selected ? (byte) 1 : (byte) 0);
}
public TextViewConfig() {
}
protected TextViewConfig(Parcel in) {
this.text = in.readString();
this.selected = in.readByte() != 0;
}
public static final Parcelable.Creator<TextViewConfig> CREATOR = new Parcelable.Creator<TextViewConfig>() {
#Override
public TextViewConfig createFromParcel(Parcel source) {
return new TextViewConfig(source);
}
#Override
public TextViewConfig[] newArray(int size) {
return new TextViewConfig[size];
}
};
public String getText() {
return text;
}
public void setText(String pText) {
text = pText;
}
public boolean isSelected() {
return selected;
}
public void setSelected(boolean pSelected) {
selected = pSelected;
}
}
Since the model class can be implemented as Parcelable easily, you can use it to send the data of the textview. And then you can use the answer from Juan Hurtado to practice the communication between the fragments by sending the config data.
let's supose u wants to got to the fragment two from fragment one with text "hello" by a click event on fragment one,
your code look like this,
class FragOne extends Fragment{
onCreateView(){
.
.
<your view>.setOnClickListener(new OnClickListener(){
#cverride
onClick(){
Bundle bundle=new Bundle();
bundle.putString("msg","<ur text will gose here which u wants to send to fragment two>");
.
.
.
//now move to the fragment two here
FragTwo fragTwo=new FragTwo();
fragTwo.setArgument(bundle);
FragmentManager fragmentManager=getSupportFragmentManager();
fragmentManager.beginTransaction().add(<ur root layout is>,fragmentTwo).commit();
}
});
}
}
Now in ur Fragmnet Two,
class FragTwo extends Fragment{
onCreateView(){
.
.
//get text which is send by fragment one
Bundle bundle=new Bundle();
String text=bundle.getString("msg");//this is ur text which is send by fragment one
}
}
Hope this will help u,
I have a fragments that builds a songs ArrayList, i want to pass that ArrayList to the framgment's activity . I know i can use interface, but not sure how i could do it
public class SongsListFragment extends Fragment
{
public interface passArrayList {
public void onArticleSelected(Uri articleUri);
// from android guide i don't know what to do
}
}
Here is what i have so far, please let me know why im getting NullPointer
on MainActivity
#Override
public void onFragmentSetSongs(ArrayList<Song> songs){
songsArrayList = songs;
}
#Override
public void onSongListItemClick(int position) {
musicService.setSong(position);
Song playSong = songsArrayList.get(position);
txtCurrentSongTitle.setText(playSong.getTitle());
txtCurrentSongTitle.requestFocus();
musicService.playSong();
btnPlayPause.setImageDrawable(getResources().getDrawable(R.drawable.ic_action_pause));
if (playbackPaused) {
playbackPaused = false;
}
//setDownloaded();
}
on Fragment
OnFragmentInteractionListener songsCallBack;
OnFragmentInteractionListener songsItemClick;
public interface OnFragmentInteractionListener {
public void onFragmentSetSongs(ArrayList<Song> s);
public void onSongListItemClick(int position);
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
// This makes sure that the container activity has implemented
// the callback interface. If not, it throws an exception
try {
songsCallBack = (OnFragmentInteractionListener) getActivity();
songsItemClick = (OnFragmentInteractionListener) getActivity();
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement OnHeadlineSelectedListener");
}
}
#Override
public void onDetach() {
super.onDetach();
songsCallBack = null;
songsItemClick= null;
}
listView = (ListView) root.findViewById(R.id.listViewSongs);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
songsItemClick.onSongListItemClick(position);
}
});
on the method where i finish building the songArrayList, i did
songsCallBack.onFragmentSetSongs(songArrayList);
Error When i Click on ListView
at com..activities.MainActivity.onSongListItemClick(MainActivity.java:107)
at com..fragments.SongsListFragment$1.onItemClick(SongsListFragment.java:194)
at android.widget.AdapterView.performItemClick(AdapterView.java:308)
at android.widget.AbsListView.performItemClick(AbsListView.java:1478)
at android.widget.AbsListView$PerformClick.run(AbsListView.java:3480)
Error Position
musicService.setSong(position); //Main Activity (MainActivity.java:107)
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
songsItemClick.onSongListItemClick(position); < -- here
}
Change name of your interface so that it begins from capital letter. Then in your activity add this line to declaration of your activity: public class FragmentActivity extends Activity implements PassArrayList, override interface method. And in fragment add following:
PassArrayList mCallback;
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
mCallback = (PassArrayList) getActivity();
}
#Override
public void onDetach() {
super.onDetach();
mCallback = null;
}
And somewhere in your code, when you want to pass your list of songs back to the activity call the method onArticleSelected() on your mCallback object and pass to this method your arraylist. Then this arraylist will come as an argument to the method onArticleSelected() in your activity and you could make with it anything that you like. But don't forget to nullify link to mCallback in onDetach() hook method to prevent context leak