I haven't found similar questions, so I'm writing a new one.
I'm developing a little Android app and I have some problems with an interface. The app consists of 3 fragments and a ViewPager. Clicking a button, I show a custom dialog (made my extending the AlertDialog.Builder class). To retrieve data back from the target fragment, I made an interface that I implement in the fragment.
Everything seems to work, but when I try to access fragment class variables inside the overridden methods, they are null! Class variables are initialized in onCreateView fragment method.
Thanks
import android.content.DialogInterface;
public interface BandDialogInterface{
public void onActionCreate(DialogInterface dialog, String name, MyColor color);
public void onActionEdit(DialogInterface dialog, int id, String name, MyColor color);
}
It's a bit messy because I was trying something:
public class EditBandDialog extends AlertDialog.Builder {
private final Band band;
private Spinner listColor;
private EditText inputName;
private DatabaseHelper dbHelper;
private BandDialogInterface bandDialogInterface;
public EditBandDialog(Context context, final Band band){
super(context);
this.band = band;
try{
bandDialogInterface = ((MercenAppActivity)context).getBandsFragment();
Log.d("CONTEXT", ((MercenAppActivity)context).getBandsFragment().toString());
}catch (Exception e){
e.printStackTrace();
}
View dialogView = ((Activity)context).getLayoutInflater().inflate(R.layout.dialog_edit_band, null);
setView(dialogView);
setCancelable(false);
dbHelper = new DatabaseHelper(context);
listColor = (Spinner)dialogView.findViewById(R.id.dialog_edit_band_color);
inputName = (EditText)dialogView.findViewById(R.id.dialog_edit_band_name);
BandColorAdapter adapter = new BandColorAdapter(context);
listColor.setAdapter(adapter);
if(isNewBand()) {
setTitle(R.string.title_new_band);
setPositiveButton("Crea", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
//bandAdapter.insert(new Band(-1, inputName.getText().toString(), ((MyColor) listColor.getSelectedItem())));
//Toast.makeText(getContext(), R.string.toast_band_added, Toast.LENGTH_SHORT).show();
bandDialogInterface.onActionCreate(dialog, inputName.getText().toString(), (MyColor)listColor.getSelectedItem());
}
});
}else{
setTitle(R.string.title_edit_band);
inputName.setText(band.getName());
int pos = 0;
while(((MyColor)listColor.getAdapter().getItem(pos)).getColor() != band.getColor())
pos++;
listColor.setSelection(pos);
setPositiveButton("Modifica", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
//dbHelper.updateBand(dbHelper.getWritableDatabase(), band.getId(), inputName.getText().toString(), ((MyColor) listColor.getSelectedItem()).getColor());
//bandAdapter.update(new Band(band.getId(), inputName.getText().toString(), ((MyColor) listColor.getSelectedItem())));
//Toast.makeText(getContext(), R.string.toast_band_edited, Toast.LENGTH_SHORT).show();
bandDialogInterface.onActionEdit(dialog, band.getId(), inputName.getText().toString(), (MyColor)listColor.getSelectedItem());
}
});
}
setNegativeButton("Annulla", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
}
private boolean isNewBand(){
return band == null;
}
}
class MyColor{
int color;
public MyColor(int color){
this.color = color;
}
public static MyColor fromString(String s){
return new MyColor(Color.parseColor(s));
}
public int getColor(){
return color;
}
}
class BandColorAdapter extends ArrayAdapter<MyColor> implements SpinnerAdapter {
private static final MyColor[] colors = {MyColor.fromString("#D60000"), //ROSSO
MyColor.fromString("#0080FF"), //AZZURRO
MyColor.fromString("#00AD37"), //VERDE
MyColor.fromString("#FFF700"), //GIALLO
MyColor.fromString("#FF8400"), //ARANCIO
MyColor.fromString("#10009C")}; //BLU
public BandColorAdapter(Context context) {
super(context, R.layout.row_band_color, colors);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = LayoutInflater.from(getContext()).inflate(R.layout.row_band_color, parent, false);
}
View bandColor = convertView.findViewById(R.id.band_color_item);
bandColor.setBackgroundColor(getItem(position).getColor());
return convertView;
}
#Override
public View getDropDownView(int position, View convertView, ViewGroup parent) {
if (convertView == null)
{
convertView = LayoutInflater.from(getContext()).inflate(R.layout.row_band_color, parent, false);
}
View bandColor = convertView.findViewById(R.id.band_color_item);
bandColor.setBackgroundColor(getItem(position).getColor());
return convertView;
}
}
And this is the class where I implement the interface:
public class BandsFragment extends Fragment implements BandDialogInterface{
private static final String TAG = "BandsFragment";
private static final boolean D = true;
private DatabaseHelper dbHelper;
private BandAdapter bandAdapter;
private String s;
public BandsFragment(){
}
#Override
public void onActionCreate(DialogInterface dialog, String name, MyColor color) {
//Toast.makeText(getActivity(), "CREATE", Toast.LENGTH_SHORT).show();
//bandAdapter.insert(new Band(0, name, color));
Log.d("CREATE", s);
}
#Override
public void onActionEdit(DialogInterface dialog, int id, String name, MyColor color) {
Toast.makeText(getActivity(), "EDITED", Toast.LENGTH_SHORT).show();
}
/**
* Returns a new instance of this fragment for the given section
* number.
*/
public static BandsFragment newInstance() {
BandsFragment fragment = new BandsFragment();
return fragment;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_bands, container, false);
if (D) Log.d(TAG, "--- onCreateView ---");
dbHelper = new DatabaseHelper(getActivity());
ListView listBands = (ListView)rootView.findViewById(R.id.list_bands);
TextView noBands = (TextView)rootView.findViewById(R.id.no_bands);
bandAdapter = new BandAdapter(getActivity(), noBands);
listBands.setAdapter(bandAdapter);
// if(dbList.size() == 0){
// noBands.setVisibility(View.VISIBLE);
// }else{
// noBands.setVisibility(View.GONE);
// }
listBands.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
//TODO something
}
});
registerForContextMenu(listBands);
return rootView;
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
if (D) Log.d(TAG, "--- onAttach ---");
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (D) Log.d(TAG, "--- onCreate ---");
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
if (D) Log.d(TAG, "--- onViewCreated ---");
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (D) Log.d(TAG, "--- onActivityCreated ---");
}
#Override
public void onStart() {
super.onStart();
if (D) Log.d(TAG, "--- onStart ---");
}
#Override
public void onResume() {
super.onResume();
if (D) Log.d(TAG, "--- onResume ---");
}
#Override
public void onPause() {
super.onPause();
if (D) Log.d(TAG, "--- onPause ---");
}
#Override
public void onStop() {
super.onStop();
if (D) Log.d(TAG, "--- onStop ---");
}
#Override
public void onDestroyView() {
super.onDestroyView();
if (D) Log.d(TAG, "--- onDestroyView ---");
}
#Override
public void onDestroy() {
super.onDestroy();
if (D) Log.d(TAG, "--- onDestroy ---");
}
#Override
public void onDetach() {
super.onDetach();
if (D) Log.d(TAG, "--- onDetach ---");
}
#Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo)menuInfo;
menu.setHeaderTitle(bandAdapter.getItem(info.position).getName());
getActivity().getMenuInflater().inflate(R.menu.context_band, menu);
MenuItem.OnMenuItemClickListener l = new MenuItem.OnMenuItemClickListener() {
#Override
public boolean onMenuItemClick(MenuItem item) {
onContextItemSelected(item);
return true;
}
};
for(int i = 0; i < menu.size(); ++i){
menu.getItem(i).setOnMenuItemClickListener(l);
}
}
#Override
public boolean onContextItemSelected(MenuItem item) {
AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo)item.getMenuInfo();
switch (item.getItemId()){
case R.id.context_band_edit:
new EditBandDialog(getActivity(), bandAdapter.getItem(info.position)).show();
//Log.d("D",bandAdapter.getItem(info.position).getName());
break;
case R.id.context_band_delete:
/*dbHelper.deleteBand(dbHelper.getWritableDatabase(), bandAdapter.getItem(info.position).getId());
bandAdapter.remove(bandAdapter.getItem(info.position));
bandAdapter.notifyDataSetChanged();*/
bandAdapter.delete(bandAdapter.getItem(info.position));
Toast.makeText(getActivity(), R.string.toast_band_deleted, Toast.LENGTH_SHORT).show();
break;
}
return true;
}
}
class BandAdapter extends ArrayAdapter<Band> implements SpinnerAdapter{
private DatabaseHelper dbHelper;
private TextView noBands;
public BandAdapter(Context context, TextView noBands) {
super(context, R.layout.row_band);
this.noBands = noBands;
dbHelper = new DatabaseHelper(context);
updateAdapter();
}
private void updateAdapter(){
clear();
addAll(dbHelper.getAllBands());
if(noBands != null) {
if (isEmpty()) {
noBands.setVisibility(View.VISIBLE);
} else {
noBands.setVisibility(View.GONE);
}
}
notifyDataSetChanged();
}
public void insert(Band band){
//dbHelper.insertBand(dbHelper.getWritableDatabase(), band.getName(), band.getColor());
Toast.makeText(getContext(), "ADDED", Toast.LENGTH_SHORT).show();
updateAdapter();
}
public void update(Band band){
dbHelper.updateBand(dbHelper.getWritableDatabase(), band.getId(), band.getName(), band.getColor());
updateAdapter();
}
public void delete(Band band){
dbHelper.deleteBand(dbHelper.getWritableDatabase(), band.getId());
updateAdapter();
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// Get the data item for this position
Band band = getItem(position);
// Check if an existing view is being reused, otherwise inflate the view
if (convertView == null) {
convertView = LayoutInflater.from(getContext()).inflate(R.layout.row_band, parent, false);
}
// Lookup view for data population
TextView bandName = (TextView) convertView.findViewById(R.id.band_name);
View bandColor = (View) convertView.findViewById(R.id.band_color);
bandColor.setBackgroundColor(band.getColor());
// Populate the data into the template view using the data object
bandName.setText(band.getName());
// Return the completed view to render on screen
return convertView;
}
#Override
public View getDropDownView(int position, View convertView, ViewGroup parent) {
if (convertView == null)
{
convertView = LayoutInflater.from(getContext()).inflate(R.layout.row_band, parent, false);
}
Band band = getItem(position);
TextView bandName = (TextView) convertView.findViewById(R.id.band_name);
View bandColor = (View) convertView.findViewById(R.id.band_color);
bandColor.setBackgroundColor(band.getColor());
// Populate the data into the template view using the data object
bandName.setText(band.getName());
return convertView;
}
}
Related
My fragment has a Recycler View. Therefore I have a RecyclerView Adapter too. From this Adapter, I am opening an AlertDialog. When I click OK, I need to pass the onclick event from my DialogFragment back to my RecyclerView Adapter.
Currently, I am doing it like here, but this passes the event back to the activity and not to the RecyclerView Adapter.
public class FreshwaterRecyclerViewAdapter extends RecyclerView.Adapter<FreshwaterRecyclerViewAdapter.ViewHolder> implements BiotopeDialogFragment.NoticeDialogListener {
private List<Biotope> data;
private LayoutInflater layoutInflater;
FreshwaterRecyclerViewAdapter(Context context, List<Biotope> data) {
this.layoutInflater = LayoutInflater.from(context);
this.data = data;
}
//The dialog fragment receives a reference to this Activity through the
//Fragment.onAttach() callback, which it uses to call the following methods
//defined by the NoticeDialogFragment.NoticeDialogListener interface
#Override
public void onDialogPositiveClick(DialogFragment dialog) {
notifyItemInserted(getItemCount()-1);
}
#Override
public void onDialogNegativeClick(DialogFragment dialog) {
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView;
if (viewType == R.layout.biotope_cardview){
itemView = layoutInflater.inflate(R.layout.biotope_cardview, parent, false);
} else {
itemView = layoutInflater.inflate(R.layout.biotope_add_button, parent, false);
}
return new ViewHolder(itemView);
}
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
if (position == data.size()) {
holder.imageButtonAddBiotope.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
FragmentManager fragmentManager = ((AppCompatActivity) layoutInflater.getContext()).getSupportFragmentManager();
DialogFragment dialog = new BiotopeDialogFragment();
dialog.show(fragmentManager, "NoticeDialogFragment");
}
});
} else {
holder.textViewBiotopeTitle.setText(getItem(position).name);
Picasso.get().load(Uri.parse(getItem(position).imageUri)).into(holder.imageViewBiotope);
LastValuesRecyclerViewAdapter recyclerAdapter = new LastValuesRecyclerViewAdapter(layoutInflater.getContext(), getData());
holder.recyclerViewLastValues.setLayoutManager(new LinearLayoutManager(layoutInflater.getContext(), LinearLayoutManager.HORIZONTAL, false));
holder.recyclerViewLastValues.setAdapter(recyclerAdapter);
}
}
//total number of rows
#Override
public int getItemCount() {
return data.size() + 1; //+1 for the add button
}
#Override
public int getItemViewType(int position) {
return (position == data.size()) ? R.layout.biotope_add_button : R.layout.biotope_cardview;
}
public static class ViewHolder extends RecyclerView.ViewHolder {
private TextView textViewBiotopeTitle;
private ImageView imageViewBiotope;
private RecyclerView recyclerViewLastValues;
private ImageButton imageButtonAddBiotope;
public ViewHolder(View view) {
super(view);
textViewBiotopeTitle = (TextView) view.findViewById(R.id.textViewBiotopeTitle);
imageViewBiotope = (ImageView) view.findViewById(R.id.imageViewBiotopeCardview);
recyclerViewLastValues = (RecyclerView) view.findViewById(R.id.recyclerViewLastValues);
imageButtonAddBiotope = (ImageButton) view.findViewById(R.id.imageButtonAddBiotope);
}
}
Biotope getItem(int id) {
return data.get(id);
}
private List<String> getData() {
List<String> data = new ArrayList<>();
data.add("PO4");
data.add("NO3");
return data;
}
}
This is my dialog.
public class BiotopeDialogFragment extends DialogFragment {
private NoticeDialogListener listener;
public interface NoticeDialogListener {
public void onDialogPositiveClick(DialogFragment dialog);
public void onDialogNegativeClick(DialogFragment dialog);
}
//Override the Fragment.onAttach() method to instantiate the NoticeDialogListener
#Override
public void onAttach(#NonNull Context context) {
super.onAttach(context);
//Verify that the host activity implements the callback interface
try {
//Instantiate the NoticeDialogListener so we can send events to the host
listener = (NoticeDialogListener) context;
} catch (ClassCastException e) {
//The activity doesn't implement the interface, throw exception
throw new ClassCastException("FreshwaterRecyclerViewAdapter must implement NoticeDialogListener | Context: " + context.toString());
}
}
public static final String TAG = "biotope_dialog_fragment";
private ActivityResultLauncher<Intent> activityResultLauncher;
private Uri imageUri = null;
#NonNull
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(getContext());
LayoutInflater inflater = requireActivity().getLayoutInflater();
//Inflate and set the layout for the dialog
//Pass null as the parent view because its going in the dialog layout
View view = inflater.inflate(R.layout.fragment_dialog_biotope, null, false);
builder.setView(view);
View colorPickerPreviewView = view.findViewById(R.id.colorPickerPreviewView);
ColorPickerView colorPickerView = view.findViewById(R.id.colorPickerView);
ImageView imageViewBiotope = view.findViewById(R.id.imageViewBiotopePreview);
TextInputEditText textFieldBiotopeName = view.findViewById(R.id.textFieldBiotopeName);
builder.setTitle("New biotope")
.setPositiveButton("ok", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int id) {
BiotopeDatabase database = BiotopeDatabase.getDbInstance(requireContext().getApplicationContext());
Biotope biotope = new Biotope();
if (textFieldBiotopeName.getText() != null) {
biotope.name = textFieldBiotopeName.getText().toString();
} else {
biotope.name = "";
}
if (imageUri != null) {
biotope.imageUri = imageUri.toString();
} else {
biotope.imageUri = "";
}
biotope.color = colorPickerView.getColor();
database.biotopeDao().insertAll(biotope);
//Send the positive button event back to the host activity
listener.onDialogPositiveClick(BiotopeDialogFragment.this);
}
})
.setNegativeButton("noke", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
//Send the negative button event back to the host activity
listener.onDialogNegativeClick(BiotopeDialogFragment.this);
Objects.requireNonNull(BiotopeDialogFragment.this.getDialog()).cancel();
}
});
return builder.create();
}
public static BiotopeDialogFragment display(FragmentManager fragmentManager) {
BiotopeDialogFragment fragment = new BiotopeDialogFragment();
fragment.show(fragmentManager, TAG);
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public void onViewCreated(#NonNull View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
}
}
This is my fragment building the RecyclerView. Alternatively, I can pass the event back to the fragment if it is not possible to pass it to the adapter.
public class BiotopesFragment extends Fragment {
private FreshwaterRecyclerViewAdapter recyclerAdapter;
public static BiotopesFragment newInstance(String param1, String param2) {
BiotopesFragment fragment = new BiotopesFragment();
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.fragment_biotopes, container, false);
RecyclerView recyclerViewFreshwater = (RecyclerView) root.findViewById(R.id.recyclerViewFreshwater);
recyclerAdapter = new FreshwaterRecyclerViewAdapter(getContext(), getData());
recyclerViewFreshwater.setLayoutManager(new LinearLayoutManager(getContext(), LinearLayoutManager.HORIZONTAL, false));
recyclerViewFreshwater.setAdapter(recyclerAdapter);
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(getContext(), DividerItemDecoration.VERTICAL);
recyclerViewFreshwater.addItemDecoration(dividerItemDecoration);
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(ItemTouchHelper.START | ItemTouchHelper.END, 0) {
#Override
public boolean onMove(#NonNull RecyclerView recyclerView, #NonNull RecyclerView.ViewHolder viewHolder, #NonNull RecyclerView.ViewHolder target) {
int fromPosition = viewHolder.getAdapterPosition();
int toPosition = target.getAdapterPosition();
Collections.swap(getData(), fromPosition, toPosition);
recyclerView.getAdapter().notifyItemMoved(fromPosition, toPosition);
return false;
}
#Override
public void onSwiped(#NonNull RecyclerView.ViewHolder viewHolder, int direction) {
}
});
itemTouchHelper.attachToRecyclerView(recyclerViewFreshwater);
return root;
}
private List<Biotope> getData() {
BiotopeDatabase database = BiotopeDatabase.getDbInstance(requireContext().getApplicationContext());
BiotopeDao biotopeDao = database.biotopeDao();
return biotopeDao.getAll();
}
}
Ideal Way to do this to create all UI component in Fragment not in the adapter . Create an interface to handle events in the fragment and provide callback to the fragment from adapter. now your Fragment should create all the UI component .
Now coming to the
How to provide callback from dialog fragment to Fragment.
You can use setTargetFragment but its deprecated . Now you can use setFragmentResultListener instead of setTargetFragment(), its the safest way i think. Once you get the result back in fragment you can call any method of your adapter.
I'm displaying three recyclerviews inside a fragment. I have recently changed my implementation so I can display some feature on a dropdown menu while long pressing on an item inside one of the three recyclerview.
Since then my app treats the click event on the two first recyclerview incorrectly (out of bound issue) and I know from debbuging that those click events are managed onely by the third adapter.
Here's my fragment code displaying the three recyclerviews:
public class ActivityFragment extends Fragment {
private int Index;
private ForecastRecyclerAdapter FirstView_Adapter;
private ForecastRecyclerAdapter SecondView_Adapter;
private ForecastRecyclerAdapter ThirdView_Adapter;
private CardView FirstCard, SecondCard, ThirdCard;
private LinearLayout SeparatorLayout1, SeparatorLayout2;
private ArrayList<MainViewArrayListRecycler> ListFirstView;
private ArrayList<MainViewArrayListRecycler> ListSecondView;
private ArrayList<MainViewArrayListRecycler> ListThirdView;
public static ActivityFragment newInstance(int Index) {
Bundle args = new Bundle();
ActivityFragment fragment = new ActivityFragment();
args.putInt(GETINDEX, Index);
fragment.setArguments(args);
return fragment;
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View mview = inflater.inflate(R.layout.fragment_mainactivity_forecast, container, false);
if (getArguments() != null) {
Index = getArguments().getInt(GETINDEX);
}
ViewModel viewModel = new ViewModelProvider(this).get(ViewModel.class);
viewModel.getInfo().observe(getViewLifecycleOwner(), Informations -> {
if (Informations != null) {
FillUpArray(Informations.get(Index));
}
});
FirstCard = mview.findViewById(R.id.FirstCard);
SecondCard = mview.findViewById(R.id.SecondCard);
ThirdCard = mview.findViewById(R.id.ThirdCard);
SeparatorLayout1 = mview.findViewById(R.id.SeparatorLayout1);
SeparatorLayout2 = mview.findViewById(R.id.SeparatorLayout2);
RecyclerView FirstView = mview.findViewById(R.id.First_Inside_Recycler);
RecyclerView SecondView = mview.findViewById(R.id.Second_Inside_Recycler);
RecyclerView ThirdView = mview.findViewById(R.id.Third_Inside_Recycler);
FirstView_Adapter = new ForecastRecyclerAdapter();
SecondView_Adapter = new ForecastRecyclerAdapter();
ThirdView_Adapter = new ForecastRecyclerAdapter();
FirstView.setLayoutManager(new LinearLayoutManager(getContext()));
SecondView.setLayoutManager(new LinearLayoutManager(getContext()));
ThirdView.setLayoutManager(new LinearLayoutManager(getContext()));
FirstView.setAdapter(FirstView_Adapter);
SecondView.setAdapter(SecondView_Adapter);
ThirdView.setAdapter(ThirdView_Adapter);
FirstView_Adapter.setOnItemClickListener(new ActivityFragmentAdapter.ActivityFragmentAdapterListener() {
#Override
public void onFirstClick(int position) {
//...
}
#Override
public void onSecondClick(int position) {
//...
}
#Override
public void onThirdClick(int position, boolean isChecked) {
if (isChecked) {
//...
}
}
});
SecondView_Adapter.setOnItemClickListener(new ActivityFragmentAdapter.ActivityFragmentAdapterListener() {
#Override
public void onFirstClick(int position) {
//...
}
#Override
public void onSecondClick(int position) {
//...
}
#Override
public void onThirdClick(int position, boolean isChecked) {
if (isChecked) {
//...
}
}
});
ThirdView_Adapter.setOnItemClickListener(new ActivityFragmentAdapter.ActivityFragmentAdapterListener() {
#Override
public void onFirstClick(int position) {
//...
}
#Override
public void onSecondClick(int position) {
//...
}
#Override
public void onThirdClick(int position, boolean isChecked) {
if (isChecked) {
//...
}
}
});
return mview;
}
private void FillUpArray(Information Info) {
/* Fill up the different arraylist and call setData frome the adapter */
}
}
Here's the recycler adapter class used:
public class ActivityFragmentAdapter extends RecyclerView.Adapter<ActivityFragmentAdapter.InsideRecyclerHolder> {
private ArrayList<MainViewArrayListRecycler> mRecyclerArrayListType;
private static ActivityFragmentAdapterListener mListener;
private String mUnit;
private int mAverageDistance;
private int mCurrentDistance;
private int mPeriodInterval;
public void setData(ArrayList<MainViewArrayListRecycler> RecyclerArrayListType) {
mRecyclerArrayListType = RecyclerArrayListType;
notifyDataSetChanged();
}
#NonNull
#Override
public InsideRecyclerHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
LayoutInflater myInflater = LayoutInflater.from(parent.getContext());
View myOwnView = myInflater.inflate(R.layout.forecast_recycler, parent, false);
return new InsideRecyclerHolder(myOwnView, mListener);
}
#Override
public void onBindViewHolder(#NonNull InsideRecyclerHolder holder, int position) {
MainViewArrayListRecycler currentItem = mRecyclerArrayListType.get(position);
String tmpConcatDistance;
holder.t1.setText(currentItem.getTitle()));
holder.t2.setText(currentItem.getText());
}
#Override
public int getItemCount() {
return mRecyclerArrayListType.size();
}
public static class InsideRecyclerHolder extends RecyclerView.ViewHolder implements View.OnCreateContextMenuListener, MenuItem.OnMenuItemClickListener{
final TextView t1;
final TextView t2;
final CheckBox cb1;
public InsideRecyclerHolder(#NonNull View itemView, final ForecastRecyclerAdapterListener listener) {
super(itemView);
t1 = itemView.findViewById(R.id.t1);
t2 = itemView.findViewById(R.id.t2);
cb1 = itemView.findViewById(R.id.cb1);
cb1.setOnCheckedChangeListener((buttonView, isChecked) -> {
if (listener != null) {
int position = getBindingAdapterPosition();
if (position != RecyclerView.NO_POSITION) {
listener.onThirdClick(position, isChecked);
cb1.setChecked(false);
}
}
});
itemView.setOnCreateContextMenuListener(this);
}
#Override
public boolean onMenuItemClick(MenuItem item) {
if (mListener != null) {
int position = getBindingAdapterPosition();
if (position != RecyclerView.NO_POSITION) {
switch (item.getItemId()) {
case 1:
mListener.onFirstClick(position);
return true;
case 2:
mListener.onSecondClick(position);
return true;
}
}
}
return false;
}
#Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
menu.setHeaderTitle(R.string.dropdown_menu_title);
MenuItem firstItem = menu.add(Menu.NONE, 1, 1, R.string.dropdown_menu_firstItem);
MenuItem secondItem = menu.add(Menu.NONE, 2, 2, R.string.dropdown_menu_secondItem);
firstItem.setOnMenuItemClickListener(this);
secondItem.setOnMenuItemClickListener(this);
}
}
public interface ActivityFragmentAdapterListener {
void onFirstClick(int position);
void onSecondClick(int position);
void onThirdClick(int position, boolean isChecked);
}
public void setOnItemClickListener(ActivityFragmentAdapterListener listener) {
mListener = listener;
}
}
What can be the issue ?
I am using contextual action bar in my fragment("UnitsFragment.java") to delete and edit items of recyclerview. But when I come back from recyclerview adapter class("UnitsRv.java"). The context seems to be null. I tried returning context from adapter and it worked for function "prepareSelection". However for "onActionItemClicked" under ActionMode.callback, I need to get context so that I can use alertdialog for editing the items.
The "requireContext()" throws this error: Fragment UnitsFragment{e3a36c8 (b4957397-055a-4b1c-8af2-fee89a3e9b35)} not attached to a context.
Here are my codes.
UnitsFragment.java
public class UnitsFragment extends Fragment {
private static final String TAG = "UnitsFragment";
private RecyclerView recyclerView;
private RecyclerView.Adapter mAdapter;
private RecyclerView.LayoutManager layoutManager;
ArrayList<UnitsList> unitsLists = new ArrayList<>();
Activity mcontext = getActivity();
Context dcontext;
ActionMode actionMode;
public static ArrayList<UnitsList> selectionList = new ArrayList<>();
public static boolean isInActionMode = false;
List<String> list = DatabaseClient.getInstance(getContext())
.getUserDatabase()
.getUnitDao().findUnitNameList();
public UnitsFragment() {
}
private ActionMode.Callback actionModeCallback = new ActionMode.Callback() {
#Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
mode.getMenuInflater().inflate(R.menu.menu_item_action, menu);
return true;
}
#Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return false;
}
#Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_item_edit:
if (selectionList.size() == 1) {
final EditText editText = new EditText(requireContext());
new AlertDialog.Builder(requireContext())
.setTitle("Rename unit name").setView(editText)
.setPositiveButton("Rename", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
UnitsList unitsList = selectionList.get(0);
unitsList.setUnit_name(editText.getText().toString().trim());
isInActionMode = false;
((UnitsRv) mAdapter).changeDataItem(getCheckedLastPosition(), unitsList);
actionMode.finish();
selectionList.clear();
}
})
.create()
.show();
Toast.makeText(getContext(), "Edit", Toast.LENGTH_SHORT).show();
mode.finish();
return true;
}
case R.id.menu_item_delete:
isInActionMode = false;
((UnitsRv) mAdapter).removeData(selectionList);
Toast.makeText(getContext(), "Delete", Toast.LENGTH_SHORT).show();
actionMode.finish();
selectionList.clear();
return true;
default:
return false;
}
}
#Override
public void onDestroyActionMode(ActionMode mode) {
actionMode = null;
}
};
private int getCheckedLastPosition() {
ArrayList<UnitsList> dataSet = UnitsRv.getDataSet();
for (int i = 0; i < dataSet.size(); i++) {
if (dataSet.get(i).equals(selectionList.get(0))) {
return i;
}
}
return 0;
}
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_units, container, false);
setHasOptionsMenu(true);
dcontext = rootView.getContext();
Log.d(TAG, "onCreateView1: " + dcontext);
recyclerView = rootView.findViewById(R.id.rv_units);
recyclerView.setHasFixedSize(true);
recyclerView.addItemDecoration(new DividerItemDecoration(getContext(),
DividerItemDecoration.HORIZONTAL));
recyclerView.addItemDecoration(new DividerItemDecoration(getContext(),
DividerItemDecoration.VERTICAL));
layoutManager = new GridLayoutManager(getContext(), 2);
recyclerView.setLayoutManager(layoutManager);
for (String string : list) {
unitsLists.add(new UnitsList(string));
}
Log.d(TAG, "onCreateView: " + getContext());
mAdapter = new UnitsRv(mcontext,unitsLists);
recyclerView.setAdapter(mAdapter);
return rootView;
}
#Override
public void onCreateOptionsMenu(#NonNull Menu menu, #NonNull MenuInflater inflater) {
inflater.inflate(R.menu.add, menu);
super.onCreateOptionsMenu(menu, inflater);
}
#Override
public boolean onOptionsItemSelected(#NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_item_new:
final View customLayout = getLayoutInflater().inflate(R.layout.add_unit_dialog, null);
final EditText edt_unit_name = customLayout.findViewById(R.id.edt_new_unit_name);
final AlertDialog dialog = new AlertDialog.Builder(getContext())
.setView(customLayout)
.setTitle("Unit name")
.setPositiveButton(android.R.string.ok, null) //Set to null. We override the onclick
.setNegativeButton(android.R.string.cancel, null)
.create();
dialog.setOnShowListener(new DialogInterface.OnShowListener() {
#Override
public void onShow(DialogInterface dialogInterface) {
Button ok_btn = dialog.getButton(AlertDialog.BUTTON_POSITIVE);
Button cancel_btn = dialog.getButton(AlertDialog.BUTTON_NEGATIVE);
ok_btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
String unit_name = edt_unit_name.getText().toString().trim();
if (!TextUtils.isEmpty(unit_name)) {
String old_unit_name = DatabaseClient.getInstance(getContext())
.getUserDatabase()
.getUnitDao()
.findByUnitName(unit_name);
if (old_unit_name == null) {
DatabaseClient.getInstance(getContext())
.getUserDatabase()
.getUnitDao()
.insertUnits(new UnitsList(unit_name));
unitsLists.add(new UnitsList(unit_name));
dialog.dismiss();
} else {
edt_unit_name.setError("Unit already exists");
}
} else {
edt_unit_name.setError("Can't be empty");
}
}
});
cancel_btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
dialog.dismiss();
}
});
}
});
dialog.show();
return true;
}
return super.onOptionsItemSelected(item);
}
public void prepareSelection(Context context,int position) {
if(actionMode == null) {
isInActionMode = true;
for (String string : list) {
unitsLists.add(new UnitsList(string));
}
mAdapter = new UnitsRv(context, unitsLists);
Log.d(TAG, "prepareSelection: " + mAdapter);
Log.d(TAG, "prepareSelection1: " + dcontext);
mcontext = (Activity)context;
actionMode = mcontext.startActionMode(actionModeCallback);
mAdapter.notifyDataSetChanged();
if (!selectionList.contains(unitsLists.get(position))) {
selectionList.add(unitsLists.get(position));
}
updateViewCounter();
}
}
private void updateViewCounter() {
int counter = selectionList.size();
if (counter == 1) {
actionMode.setTitle(counter + "item selected");
} else {
actionMode.setTitle(counter + "items selected");
}
}
}
This is my Adapter class.
UnitsRv.java
public class UnitsRv extends RecyclerView.Adapter<UnitsRv.ViewHolder> {
private static final String TAG = "UnitsRv";
private static ArrayList<UnitsList> munitsLists = new ArrayList<>();
UnitsFragment unitsFragment = new UnitsFragment();
Context mcontext;
public UnitsRv(Context context,ArrayList<UnitsList> unitsLists) {
mcontext = context;
munitsLists = unitsLists;
}
class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener {
TextView unit_name;
public ViewHolder(View v) {
super(v);
unit_name = v.findViewById(R.id.unit_name);
v.setOnLongClickListener(this);
}
#Override
public void onClick(View view) {
if (UnitsFragment.isInActionMode){
unitsFragment.prepareSelection(mcontext,getAdapterPosition());
notifyItemChanged(getAdapterPosition());
}
}
#Override
public boolean onLongClick(View view) {
Log.d(TAG, "onLongClick: " + getAdapterPosition());
unitsFragment.prepareSelection(view.getContext(),getAdapterPosition());
return true;
}
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.units_item, parent, false);
return new ViewHolder(itemView);
}
#Override
public void onBindViewHolder(#NonNull final ViewHolder holder, final int position) {
holder.unit_name.setText(munitsLists.get(position).getUnit_name());
if (UnitsFragment.isInActionMode){
if (UnitsFragment.selectionList.contains(munitsLists.get(position))){
holder.itemView.setBackgroundResource(R.color.colorSelected);
}
}
}
#Override
public int getItemCount() {
return munitsLists.size();
}
public static ArrayList<UnitsList> getDataSet() {
return munitsLists;
}
public void changeDataItem(int position, UnitsList unitsList) {
munitsLists.set(position, unitsList);
notifyDataSetChanged();
}
public void removeData(ArrayList<UnitsList> list) {
for (UnitsList unitsList : list) {
munitsLists.remove(unitsList);
}
notifyDataSetChanged();
}
}
First, you should not create instance of your UnitsFragment inside your adapter.
You can use EventBus to communicate between Activities, Fragments, Adapters, etc.
Or You can do your task using interface. like below.
Create an interface like this
public interface AdapterCallback {
void prepareSelection(Context context,int position);
}
In your UnitsFragment implement the above interface. like the following
public class UnitsFragment extends Fragment implements AdapterCallback{
// your other codes
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_units, container, false);
setHasOptionsMenu(true);
// .... your other codes
Log.d(TAG, "onCreateView: " + getContext());
// modify below line like this
mAdapter = new UnitsRv(mcontext, unitsLists, this); // here you have to pass an extra parameter that will implement your callback method from adapter.
recyclerView.setAdapter(mAdapter);
return rootView;
}
// ... you other codes
#Override
public void prepareSelection(Context context,int position) {
if(actionMode == null) {
isInActionMode = true;
for (String string : list) {
unitsLists.add(new UnitsList(string));
}
mAdapter = new UnitsRv(context, unitsLists,this); // add this as parameter.
Log.d(TAG, "prepareSelection: " + mAdapter);
Log.d(TAG, "prepareSelection1: " + dcontext);
mcontext = (Activity)context;
actionMode = mcontext.startActionMode(actionModeCallback);
mAdapter.notifyDataSetChanged();
if (!selectionList.contains(unitsLists.get(position))) {
selectionList.add(unitsLists.get(position));
}
updateViewCounter();
}
}
// other codes
}
Now, inside your Adapter you need to add an extra argument in constructor of UnitsRv and call your interface method from adapter ussing mAdapterCallback.
public class UnitsRv extends RecyclerView.Adapter<UnitsRv.ViewHolder> {
private static final String TAG = "UnitsRv";
private static ArrayList<UnitsList> munitsLists = new ArrayList<>();
UnitsFragment unitsFragment = new UnitsFragment(); // remove this line
private AdapterCallback mAdapterCallback; // add this line
Context mcontext;
public UnitsRv(Context context,ArrayList<UnitsList> unitsLists, AdapterCallback callback) {
mcontext = context;
munitsLists = unitsLists;
this.mAdapterCallback = callback; // add this line
}
class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener {
TextView unit_name;
public ViewHolder(View v) {
super(v);
unit_name = v.findViewById(R.id.unit_name);
v.setOnLongClickListener(this);
}
#Override
public void onClick(View view) {
if (UnitsFragment.isInActionMode){
mAdapterCallback.prepareSelection(mcontext,getAdapterPosition()); // modify this line
notifyItemChanged(getAdapterPosition());
}
}
#Override
public boolean onLongClick(View view) {
Log.d(TAG, "onLongClick: " + getAdapterPosition());
mAdapterCallback.prepareSelection(view.getContext(),getAdapterPosition()); // modify this line
return true;
}
}
// your other codes....
}
You should check for your fragment is attached or not with isAdded()
place if(!isAdded()) return in your onActionItemClicked. and replace requireContext() with getContext() because requireContext() always throws IllegalStateException if fragment is not attached.
override onAttach method to save context in your fragment.
#Override
public void onAttach(Context context) {
super.onAttach(context);
this.context= context;
}
Hope this helps.
The value returned by id parameter of setOnItemClickListener is always 0(zero) no matter which position i click on the value returned is always 0
but the value of position of correct and i have also tried adapterView.getItemIdAtPosition(i) and still the value on clicking each item in list is zero
public class ListFragment extends Fragment implements LoaderManager.LoaderCallbacks<Cursor>{
ListView onlineList;
FloatingActionButton onlineListFab;
private static final int mLoaderId = 1;
ListAdapter listAdapter;
public ListFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_list, container, false);
initilize(v);
return v;
}
private void initilize(View v) {
onlineList = (ListView)v.findViewById(R.id.onlineList);
onlineListFab = (FloatingActionButton)v.findViewById(R.id.onlineListFab);
onlineListFab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startActivity(new Intent(getActivity(),AddItem.class));
}
});
listAdapter = new ListAdapter(getActivity(),null);
onlineList.setAdapter(listAdapter);
onlineList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
Intent details = new Intent(getActivity(),AddItem.class);
details.setData(Uri.withAppendedPath(TableName.mContentUri,String.valueOf(l)));
Toast.makeText(getActivity(),l+"",Toast.LENGTH_SHORT).show();
//startActivity(details);
}
});
loadItems();
}
#Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
switch (id){
case mLoaderId:
return new CursorLoader(getContext(), TableName.mContentUri,null,null,null,null);
}
return null;
}
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
listAdapter.swapCursor(data);
}
#Override
public void onLoaderReset(Loader<Cursor> loader) {
listAdapter.swapCursor(null);
}
private void loadItems() {
if (getActivity().getSupportLoaderManager().getLoader(mLoaderId) == null) {
getActivity().getSupportLoaderManager().initLoader(mLoaderId, null, this).forceLoad();
} else {
getActivity().getSupportLoaderManager().restartLoader(mLoaderId, null, this).forceLoad();
}
}
}
AdapterCode :
public class ListAdapter extends CursorAdapter{
public ListAdapter(Context context, Cursor c) {
super(context, c);
}
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
View v = LayoutInflater.from(context).inflate(R.layout.item_layout,parent,false);
return v;
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
TextView name,price;
name = (TextView)view.findViewById(R.id.itemName);
price = (TextView)view.findViewById(R.id.itemPrice);
name.setText(cursor.getString(cursor.getColumnIndex(TableName.table1.mName)));
price.setText(String.valueOf(cursor.getInt(cursor.getColumnIndex(TableName.table1.mPrice))));
}
}
You're doing new ListAdapter(getActivity(),null); which is a custom class seeing as you can't do that with an interface. Have you updated the default getItemId method? I'd gamble not.
Off the top of my head, your adapter will need an implementation similar to:
#Override
public long getItemId(int position) {
long result = 0;
if (mCursor.moveToPosition(position)) {
Log.d("SO", DatabaseUtils.dumpCurrentRowToString(mCursor);
result = mCursor.getLong(mCursor.getColumnIndex(TableName.table1.mId));
}
return result;
}
If you can't resolve the problem take a look at the data itself in your cursors using DatabaseUtils
I am implementing a music player app. I am able to fetch the songs from the sd card. But stuck in something from hours i.e. I am unable to make the songs play inside the fragment.
Here is the MainActivity class which is having 3 tab fragments.
public class MainActivity extends AppCompatActivity {
private final String[] TITLES = {"Now playing", "Library", "Groups"};
private static boolean isInForeground = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//if (savedInstanceState == null) {}
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
// Initialize the ViewPager and set an adapter
ViewPager pager = (ViewPager) findViewById(R.id.pager);
pager.setAdapter(new PagerAdapter(getSupportFragmentManager(), getBaseContext()));
// Bind the tabs to the ViewPager
PagerSlidingTabStrip tabs = (PagerSlidingTabStrip) findViewById(R.id.tabs);
tabs.setShouldExpand(true);
tabs.setViewPager(pager);
//Whenever the user changes tab, we want the title to change too
tabs.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrollStateChanged(int arg0) {
// TODO Auto-generated method stub
}
#Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
// TODO Auto-generated method stub
}
#Override
public void onPageSelected(int position) {
setTitle(TITLES[position]);
}
});
//We want to have the library as default view
pager.setCurrentItem(1);
setTitle(TITLES[1]);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
/**
* A placeholder fragment containing a simple view.
*/
public static class MainFragment extends Fragment {
public MainFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_song_library, container, false);
return view;
}
}
public class PagerAdapter extends FragmentPagerAdapter
implements PagerSlidingTabStrip.CustomTabProvider {
private ArrayList<Integer> tab_icon = new ArrayList<Integer>();
Context myContext;
public PagerAdapter(FragmentManager fm, Context context) {
super(fm);
myContext = context;
tab_icon.add(context.getResources().getIdentifier("ic_play_arrow_white_36dp", "drawable", context.getPackageName()));
tab_icon.add(context.getResources().getIdentifier("ic_list_white_36dp", "drawable", context.getPackageName()));
tab_icon.add(context.getResources().getIdentifier("ic_group_white_36dp", "drawable", context.getPackageName()));
}
#Override
public CharSequence getPageTitle(int position) {
return TITLES[position];
}
#Override
public int getCount() {
return TITLES.length;
}
#Override
public Fragment getItem(int position) {
if(position == 0){
return SongNowPlayingFragment.newInstance();
} else if (position == 1){
return SongLibraryFragment.newInstance();
} else if(position == 2){
return GroupFragment.newInstance();
}
System.err.println("Invalid tab fragment!");
return new Fragment();
}
#Override
public View getCustomTabView(ViewGroup viewGroup, int position) {
LinearLayout imageView = (LinearLayout) LayoutInflater.from(myContext)
.inflate(R.layout.tab_layout, null, false);
ImageView tabImage = (ImageView) imageView.findViewById(R.id.tabImage);
tabImage.setImageResource(tab_icon.get(position));
return imageView;
}
}
#Override
protected void onResume()
{
super.onResume();
isInForeground = true;
}
#Override
protected void onPause()
{
super.onPause();
isInForeground = false;
}
static boolean isInForeground(){
return isInForeground;
}
}
This is the SongLibraryFragment in which I have added the songs from the user device. Now I want to play those songs.
public class SongLibraryFragment extends Fragment implements MediaPlayerControl {
private ArrayList<SongItem> songList;
private ListView songView;
private MusicService musicSrv;
private Intent playIntent;
private boolean musicBound=false;
private MusicController controller;
private boolean paused=false, playbackPaused=false;
private MainActivity mainActivity = null;
public static SongLibraryFragment newInstance() {
SongLibraryFragment f = new SongLibraryFragment();
Bundle b = new Bundle();
f.setArguments(b);
return f;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_song_library, container, false);
return rootView;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mainActivity = (MainActivity) SongLibraryFragment.this.getActivity();
songView = (ListView) getView().findViewById(R.id.library_song_list);
songList = new ArrayList<SongItem>();
getSongList();
SongAdapter songAdt = new SongAdapter(getActivity(), songList);
songView.setAdapter(songAdt);
Collections.sort(songList, new Comparator<SongItem>() {
public int compare(SongItem a, SongItem b) {
return a.getTitle().compareTo(b.getTitle());
}
});
setController();
}
//connect to the service
private ServiceConnection musicConnection = new ServiceConnection(){
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
MusicBinder binder = (MusicBinder)service;
//get service
musicSrv = binder.getService();
//pass list
musicSrv.setList(songList);
musicBound = true;
}
#Override
public void onServiceDisconnected(ComponentName name) {
musicBound = false;
}
};
#Override
public void onStart() {
super.onStart();
if(playIntent==null){
playIntent = new Intent(getActivity(), MusicService.class);
this.getActivity().bindService(playIntent, musicConnection, Context.BIND_AUTO_CREATE);
this.getActivity().startService(playIntent);
}
}
public void songPicked(View view){
musicSrv.setSong(Integer.parseInt(view.getTag().toString()));
musicSrv.playSong();
if(playbackPaused){
setController();
playbackPaused=false;
}
controller.show(0);
}
public void getSongList() {
//retrieve song info
ContentResolver musicResolver = getActivity().getContentResolver();
Uri musicUri = android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
Cursor musicCursor = musicResolver.query(musicUri, null, null, null, null);
if(musicCursor!=null && musicCursor.moveToFirst()){
//get columns
int titleColumn = musicCursor.getColumnIndex
(android.provider.MediaStore.Audio.Media.TITLE);
int idColumn = musicCursor.getColumnIndex
(android.provider.MediaStore.Audio.Media._ID);
int artistColumn = musicCursor.getColumnIndex
(android.provider.MediaStore.Audio.Media.ARTIST);
//add songs to list
do {
long thisId = musicCursor.getLong(idColumn);
String thisTitle = musicCursor.getString(titleColumn);
String thisArtist = musicCursor.getString(artistColumn);
songList.add(new SongItem(thisId, thisTitle, thisArtist));
}
while (musicCursor.moveToNext());
}
}
#Override
public boolean canPause() {
return true;
}
#Override
public boolean canSeekBackward() {
return true;
}
#Override
public boolean canSeekForward() {
return true;
}
#Override
public int getAudioSessionId() {
return 0;
}
#Override
public int getBufferPercentage() {
return 0;
}
#Override
public int getCurrentPosition() {
if(musicSrv!=null && musicBound && musicSrv.isPng())
return musicSrv.getPosn();
else return 0;
}
#Override
public int getDuration() {
if(musicSrv!=null && musicBound && musicSrv.isPng())
return musicSrv.getDur();
else return 0;
}
#Override
public boolean isPlaying() {
if(musicSrv!=null && musicBound)
return musicSrv.isPng();
return false;
}
#Override
public void pause() {
playbackPaused=true;
musicSrv.pausePlayer();
}
#Override
public void seekTo(int pos) {
musicSrv.seek(pos);
}
#Override
public void start() {
musicSrv.go();
}
private void setController(){
//set the controller up
controller = new MusicController(getActivity());
controller.setPrevNextListeners(new View.OnClickListener() {
#Override
public void onClick(View v) {
playNext();
}
}, new View.OnClickListener() {
#Override
public void onClick(View v) {
playPrev();
}
});
controller.setMediaPlayer(this);
controller.setAnchorView(getActivity().findViewById(R.id.library_song_list));
controller.setEnabled(true);
}
//play next
private void playNext(){
musicSrv.playNext();
if(playbackPaused){
setController();
playbackPaused=false;
}
controller.show(0);
}
//play previous
private void playPrev(){
musicSrv.playPrev();
if(playbackPaused){
setController();
playbackPaused=false;
}
controller.show(0);
}
#Override
public void onPause(){
super.onPause();
paused=true;
}
#Override
public void onResume(){
super.onResume();
if(paused){
setController();
paused=false;
}
}
#Override
public void onStop() {
controller.hide();
super.onStop();
}
#Override
public void onDestroy() {
this.getActivity().stopService(playIntent);
musicSrv=null;
super.onDestroy();
}
SongAdapter class
public class SongAdapter extends BaseAdapter {
private ArrayList<SongItem> songs;
private LayoutInflater songInf;
public SongAdapter(Context c, ArrayList<SongItem> theSongs){
songs=theSongs;
songInf=LayoutInflater.from(c);
}
#Override
public int getCount() {
// TODO Auto-generated method stub
return songs.size();
}
#Override
public Object getItem(int arg0) {
// TODO Auto-generated method stub
return null;
}
#Override
public long getItemId(int arg0) {
// TODO Auto-generated method stub
return 0;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
//map to song layout
LinearLayout songLay = (LinearLayout)songInf.inflate
(R.layout.song, parent, false);
//get title and artist views
TextView songView = (TextView)songLay.findViewById(R.id.song_title);
TextView artistView = (TextView)songLay.findViewById(R.id.song_artist);
//ImageView imageView = (ImageView)songLay.findViewById(R.id.song_image);
//get song using position
SongItem currSong = songs.get(position);
//get title and artist strings
songView.setText(currSong.getTitle());
artistView.setText(currSong.getArtist());
//imageView.setImage(currSong.getImage());
//set position as tag
songLay.setTag(position);
return songLay;
}
Song.xml file
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="5dp"
android:onClick="songPicked">
<TextView
android:id="#+id/song_title"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
style="#style/Base.TextAppearance.AppCompat.Title"
android:textColor="#color/primary_text_default_material_light"/>
<TextView
android:id="#+id/song_artist"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
style="#style/Base.TextAppearance.AppCompat.Subhead"
android:textColor="#color/secondary_text_default_material_light"/>
</LinearLayout>
Error
java.lang.IllegalStateException: Could not find a method
songPicked(View) in the activity class
co.adrianblan.noraoke.MainActivity for onClick handler on view class
android.widget.LinearLayout
So the main problem is with the songPicked method inside SongFragmentLibrary. I have added the onClick: songPicked in the song.xml file but it is searching for the songPicked method inside the MainActivity. I am not getting what is the problem.
Please can anyone help me with this?
You are trying to set onclick listener from your fragment xml android:onClick="songPicked", you can't set onclick listener for a view which is part of fragment, in your getView() setOnClickListener:
LinearLayout songLay = (LinearLayout)songInf.inflate
(R.layout.song, parent, false);
songLay.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
//Handle click event
}
})
OR
You can simply set OnItemClickListener on your listview
list.setOnItemClickListener(this);// implement OnItemClickListener in your fragment class