Alternative for interfaces for communication between components - java

I would like to call notifyDataSetChanged() but my code structure is a mess and I cannot get my way around it. I have a fragment, a custom dialog class, and MainActivity.
MainActivity.java
Fragment is created here along with 3 other fragments. Dialog is also created here
private BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener
= new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.navigation_home:
fragment = new FragmentHome();
loadFragment(fragment);
loadCustomActionBar("Home", false);
return true;
case R.id.navigation_foods:
fragment = new FragmentFood();
loadFragment(fragment);
loadCustomActionBar("Foods", true);
return true;
case R.id.navigation_drinks:
fragment = new FragmentDrink();
loadFragment(fragment);
loadCustomActionBar("Beverages", true);
return true;
case R.id.navigation_cart:
fragment = new FragmentCart();
loadFragment(fragment);
loadCustomActionBar("Cart", false);
return true;
}
return false;
}
};
private void loadCustomActionBar(String titleTxt, boolean bool) {
CustomDialog dialog = new CustomDialog()
.....
}
CustomDialog
CustomDialog is responsible for updating database.
I want to call notifyDataSetChanged() here after updating database to update view as well.
Button addItem = .....
addItem.setOnClickListener(new OnClickListener() {
public void onClick() {
dialog.show();
}
});
Fragment.java
ListAdapter is located here
I have tried using interfaces, but either I did it wrong or it doesn't work. Kindly help please. What are other alternatives for interfaces?
EDIT :
It seems you do not get my problem. I JUST WANT TO ACCESS THE LISTADAPTER CONTAINED IN THE FRAGMENT FROM MY CUSTOM DIALOG, PEOPLE OF THIS SITE.

As I see in your code you have a variable fragment. For your case you can define some BaseFragment class in which you will have abstract method datasetChanged(). All your separate fragments will be derivatives of BaseFragment and your variable fragment will be of type BaseFragment. Derivative fragments will implement function datasetChanged() in which they will call notifyDatasetChanged for their own adapters.
Then you can have a callback in your CustomDialog which will call datasetChanged of your variable fragment.
class BaseFragment extends Fragment {
...
abstract void datasetChanged();
...
}
class CustomDialog extends Dialog {
...
var notifyCallback: Function;
public setCallback(Function callback) {
notifyCallback = callback;
}
}
Then when you will create CustomDialog just set the callback to your fragments method datasetChanged():
customDialog.setCallback(fragment::datasetChanged());
After that, when your customDialog will need to notify for updates it will call for callback function.
notifyCallback.apply()

There are multiple approaches to achieve this
Send the instance of the fragment to the CustomDialog like CustomDialog dialog = new CustomDialog(fragment). Now that the CustomDialog has the reference to the fragment you can call a method in the fragment that would fetch the new data from the db and update it's views
Use EventBus library. You would register the Fragment as a listener to EventBus and implement onEventMainThread(YourEventName event).And the CustomDialog would post the YourEventName event to the EventBus after it updates the db. The EventBus will deliver this event to the fragment since it is registered to listen to YourEventName
Try to refresh the views in the onResume of the fragment. This would work in the case where the dialog and fragment are not accessible simultaneously

Related

SetText in fragment from outside class

I have a fragment that displays data from APIs, but i dont want to be calling apis everytime the fragment is called.. so am making api call from a different class and and calling a method in the fragment to update UI (textViews)
but am getting null exception for the textViews but data is 100% there
and if i try to hardcode textView.setText("Hello") it works..
one of the task of fragment is change ui !!! you must change ui in activity or fragment
you must use interface . your server class :
public class server {
.
.
.
public void callServer(IServerResponse iResponse){
.
.
.
iResponse.onResponse(//your data such as List or string or json and etc);
}
public interface IServerResponse{
// use parameter type as you want like List or string ,etc..
void onResponse(String data);
}
}
your fragment or activity implement your interface :
public class SomeFragment extends Fragment implements Server.IServerResponse{
....
#Override
public View onCreateView(...){
...
Server server=new Server();
server.callServer(this);
}
#Override
public void IServerResponse(String data){
textview.SetText(data);
}
}
You should create a FrameLayout in your activity
And use this code:
FragmentA newFragment = new FragmentA ();
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.container, newFragment).commit();
and than set your text
String editValueName= editName.getText().toString();
String lastStatus = valueStatus.getText().toString();
newFragment .setText(editValueName, lastStatus);
Try for quick fix if it is working for the output of your desire
Make Textview static in class(youractivity) where textview is originated like
public static TextView textview;
And in fragment
if(youractivity.textView!=null){ youractivity.textView.setText("your desire text"); }

How can i listen for Fragment change in my Activity?

I have an Activity which based on intent opens Fragment1 or Fragment2.
From the activity after some stuff are done if the user is in Fragment1 i replace the fragment to Fragment2 and that can be done even from the Fragment1 diretly.
For each Fragment i have to change items in my BottomAppBar, till i'm in Activity i have no problems with it as i've made just a function which changes the bottomAppBar items based on value passed it in.
The issue is when the .replace is called directly from the fragment.
So i tought if it was possible to set in anyway a 'FragmentListener' which listens for fragment change in my Activity and call that function from it..
My function looks like this:
private fun changeBottomBar(corpo: Boolean = false) {
if (corpo) {
binding.bottomAppBar.navigationIcon = ContextCompat.getDrawable(
this,
R.drawable.ic_baseline_menu_24
)
binding.bottomAppBar.menu.findItem(R.id.filter).isVisible = false
binding.bottomSheetTestata.titleBottomSheet.text = "Modifica Documento"
bottomSheetTestataBehavior.state = BottomSheetBehavior.STATE_COLLAPSED
binding.bottomAppBar.menu.findItem(R.id.testata).isVisible = tipo != "Etichette"
}else {
binding.bottomAppBar.navigationIcon = null
binding.bottomAppBar.menu?.findItem(R.id.testata)?.isVisible = false
binding.bottomAppBar.menu?.findItem(R.id.filter)?.isVisible = true
binding.bottomSheetTestata.titleBottomSheet.text = "Nuovo Documento"
clearTestata()
bottomSheetBehavior.state = BottomSheetBehavior.STATE_COLLAPSED
}
}
And i call it for every .replace where if the Fragment is Fragment2 i pass to it corpo = true
You can use EventBus Open source library for subscribing and publishing events.
https://greenrobot.org/eventbus/
For Publishing Event
//In fragment
EventBus.getDefault().post(new MessageEvent());
For Subscribing Event in Activity
//In Activity
#Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(MessageEvent event) {/* Do something */};
Define you custom model class for event
public static class MessageEvent { /* Additional fields if needed */ }

Communication between Fragments without Using Interface

I was trying to communicate between two fragments, but I'm just a beginner so I want to know if there is any solution not using interface....
If there are Fragment A, B, and their Activity:
Sending values from Fragment A to Activity
(In here, Fragment A is a current state)
Sending values from Activity to Fragment B
I know direct communication between two fragments is almost impossible,
but I don't think that makes me to use an interface.
Also, is there any method to use like putExtra() for fragment? I only know using Serializable.
Have a look at the Android deverlopers page: http://developer.android.com/training/basics/fragments/communicating.html#DefineInterface
Basically, you define an interface in your Fragment A, and let your Activity implement that Interface. Now you can call the interface method in your Fragment, and your Activity will receive the event. Now in your activity, you can call your second Fragment to update the textview with the received value
// You Activity implements your interface
public class YourActivity implements FragmentA.TextClicked{
#Override
public void sendText(String text){
// Get Fragment B
FraB frag = (FragB)
getSupportFragmentManager().findFragmentById(R.id.fragment_b);
frag.updateText(text);
}
}
// Fragment A defines an Interface, and calls the method when needed
public class FragA extends Fragment{
TextClicked mCallback;
public interface TextClicked{
public void sendText(String text);
}
#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 {
mCallback = (TextClicked) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement TextClicked");
}
}
public void someMethod(){
mCallback.sendText("YOUR TEXT");
}
#Override
public void onDetach() {
mCallback = null; // => avoid leaking, thanks #Deepscorn
super.onDetach();
}
}
// Fragment B has a public method to do something with the text
public class FragB extends Fragment{
public void updateText(String text){
// Here you have it
}
}
You can communicate between fragments directly by using EventBus - send ordinary or sticky events by one fragment and subscribe to that event in another one.
If don't want message to be lost, use sticky events - it work as sticky Intent in Android. It will be around until it is removed by targer fragment or because another event is pending.
Yes you can transfer data between fragments using bundle like you do in Activity using putExtra
Bundle = bundle = new Bundle();
bundle.putString("key","value");
bundle.putSerializable("serialzedKey",SerializedValue);
FragmentTransaction fts = ((BaseActivity) mContext).getSupportFragmentManager().beginTransaction();
fragment.setArguments(bundle);
fts.add(R.id.fragmentHolder, fragment);
fts.addToBackStack(fragment.getClass().getSimpleName());
fts.commit();
In other fragment you can retrieve data using getArguments()
String key = getArguments().getString("key");
SerializedModel = getArguments().getSerializable("serialzedKey");
you can call a method from the parent activity class that calls a method from fragment B like ((YourActivity)getActivity()).callMethod(T yourData)
Take a look at my Github repo on using interfaces to communicate between fragments.
This is just a really simple example but displays the key concepts.
https://github.com/stoddayy/FragmentInteractionExample

Refresh adapter in a Fragment after DialogFragment dbflow insert

I have an activity that has 3 fragments on it with Tabs, one of them is called "TaskFragment".
In my main Activity i only load the fragments.
In TaskFragment i have a RecyclerView that is working fine and is showing the items as intended.
The problem comes, when i insert data using a DialogFragment, because it does insert data (i am using DbFlow ORM), but it does not (of course) refresh the adapter since it is in the TaskFragment fragment inside the DetailMainActivity activity as i said.
I have tried to use onResume() and onPause() in order to refresh the adapter, but they are never called since the activity does not get paused or in onresume for a DialogFragment.
I have tried aswell to use an interface, but it does not work and i have searched all over stackoverflow and google with no luck.
I leave here some of my code for you to understand better:
DetailMainActivity.java
Here in the onClick interface i show the DialogFragment to the user to input the information.
FragmentManager fm = getSupportFragmentManager();
AddSimpleTask sptask = new AddSimpleTask();
sptask.show(fm, "tag");
TaskFragment.java
In this fragment i have my RecyclerView
private void setupRecyclerView() {
mRecyclerView.setAdapter(adapter);
mRecyclerView.setLayoutManager(new GridLayoutManager(getActivity(), 2));
mRecyclerView.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (DetailMainActivity.FAB_Status) {
DetailMainActivity.hideFAB();
DetailMainActivity.FAB_Status = false;
}
return false;
}
});
}
private void setupAdapter() {
adapter = new DetailMainTaskAdapter(simpleTaskList, this);
}
AddSimpleTask
And this is my DialogFragment. I have set a setOnShowListener() in order to avoid the DialogFragment to get dismiss early.
#Override
public void onShow(DialogInterface dialogInterface) {
final AlertDialog dialog =(AlertDialog) getDialog();
if (dialog != null){
Button positiveButton = dialog.getButton(Dialog.BUTTON_POSITIVE);
Button negativeButton = dialog.getButton(Dialog.BUTTON_NEGATIVE);
positiveButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (mEditTextName.getText().toString().trim().isEmpty() ||
mEditTextContent.getText().toString().trim().isEmpty() ) {
if (mEditTextName.getText().toString().trim().isEmpty()) {
mEditTextName.setError("Can not be empty");
}
if (mEditTextContent.getText().toString().trim().isEmpty()) {
mEditTextContent.setError("Can not be empty");
}
}else {
presenter.beingInsertion(mEditTextName.getText().toString().trim(), mEditTextContent.getText().toString().trim()
, foreignId);
}
}
});
negativeButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
dismiss();
}
});
}
}
If the insert is successfully achieved the onInsertSuccess method is called (i am using MVP)
#Override
public void onInsertSuccess() {
Snackbar.make(getActivity().findViewById(R.id.containerMainDetail), "Actividad agregada", Snackbar.LENGTH_SHORT).show();
dismiss();
}
I have called adapter.notifyDataSetChanged() in many places, and i also tried with a custom interface, but i can not make this work.
Sorry for the long post, but thanks in advance for your help.
There are some errors in your statement but I'll get to that later. notifyDataSetChanged() only notifies the adapter that the underlying list (or array) has changed. The implication is that you first need to requery your database and obtain the new list before calling notifyDataSetChanged() on the adapter else there is no point as the underlying list will still be the same and it will not update the adapter.
The correct way of calling this will be through your custom listener interface and not in the onPause()/onResume() callbacks as there is the possibility that the user does not enter a value and hence you will unnecessarily be querying the database. In your custom listener interface implementation, first update the list with the new data from the DB and then notify the adapter.
Which leads to the error in assumption that onPause()/onResume() callbacks do not happen when your Activity is covered by a DialogFragment - this is incorrect. The moment the activity view is even partially covered, the onPause() callback is triggered.

Access other fragment data

I'm having some trouble, and I have done research on the problem but it did not help me.
I have a Main.java class, which is template made pager view of fragments.
I did not modify it in any way, except for getItem() method which now returns my own fragments.
My fragment A is collecting accelerometer data, saving last 120 records in an ArrayList.
It also has graph plots, with Series objects, which I would like to access from fragment B.
This is what I want to do:
In fragment B user presses a button "record data"
This results in fragment A boolean field "recordingOn" changing to true
Now in fragmentA onSensorChange method, after checking for "recordingOn", if it's true it will pass data to an ArrayList that is a field in fragment B
How do I access these fields?
from fragment call
Fragment frag = getActivity().getFragmentManager()..findFragmentByTag("fragment to find tag");
Greensy answer is a valid option (I upvoted him) but you can also refrain from doing so much DataPassing between fragments and let the Activity be a manager for all that.
For that you can create public methods and interfaces in the fragments and let/force the activity implement the interfaces.
Simple example:
public class Act extends Activity implements OnClickListener{
#Override
OnClick(View v){
if(v.getId()==R.id.btn_recordData){
fragA.startRecording();
}
}
}
then FragA you must create that method:
public class FragA extends Fragment{
private boolean isRecording
public void startRecording(){ isRecording = true; // also init the sensor stuff }
public void stopRecording() { isRecording = false; // also stop the sensor stuff }
}
then on FragB you can:
public class FragB extends Fragment{
onCreateView(...){
// initialise all the views and find the button, let's call it Button btn;
btn.setOnClickListener((OnClickListener)getActivity());
}
}
does that make sense?
A way to do that is to use your own Application class and store your ArrayList in there
You can then access it in any point of your application, if you got a Context :
ArrayList<AccelerometerData> myAccelerometerData = ((MyApplication) mContext.getApplicationContext()).getAccelerometerData();
Be carefull about this solution since your ArrayList will be alive during all the application run

Categories

Resources