Share a fragment with several classes? - java

I wonder how I can best create a progress bar fragment. It must be usable by every other class of course.
At the moment I have just a ProgressBarFragment, which has public setVisible method. Getting the Fragment through FragmentManager I can set it visible or not. But is this the right way to do these sort of actions?
public class MyActivity exetends FragmentActivity {
void setVisibility(int visible) {
ProgressBarFragment fragment = (ProgressBarFragment) getSupportFragmentManager().findFragmentById(R.id.fragment_progress_bar);
fragment.setProgressBar(visible);
}
}
And of course I have several other Fragments which uses this code too, to trigger the progress bar.
public class ProgressBarFragment extends Fragment {
public void setProgressBar(int visible) {
progressBar = (ProgressBar) getActivity().findViewById(R.id.progress_bar);
progressBar.setVisibility(visible);
}
}

You can refactor this code into a static method of your ProgressBarFragment
class ProgressBarFragment {
//...
static void setVisibility(Activity parent, int visible) {
ProgressBarFragment progressBar =
(ProgressBarFragment)parent.getSupportFragmentManager()
.findFragmentById(R.id.fragment_progress_bar);
progressBar.setProgressBar(visible);
//...
}
So then you will be using ProgressBarFragment.setVisibility(yourActivity, 1) everywhere.

Related

Android how to call Activity data type from another class in Main Activity?

I have this code separate class which makes a Snackbar to be displayed within my application, But with my current implementation I am getting a 'java.lang.NullPointerException'. How do I implement it in my main class properly?
here is my snack bar class:
public class SnackBarUtils
{
private static SnackBarUtils mInstance = null;
private Snackbar mSnackBar;
private SnackBarUtils()
{
}
public static SnackBarUtils getInstance()
{
if (mInstance == null)
{
mInstance = new SnackBarUtils();
}
return mInstance;
}
public void hideSnackBar()
{
if (mSnackBar != null)
{
mSnackBar.dismiss();
}
}
public void showProblemSnackBar(final Activity activity, final String message)
{
mSnackBar = Snackbar.make(activity.findViewById(android.R.id.content), message,
Snackbar.LENGTH_INDEFINITE);
// Changing action button text color
View sbView = mSnackBar.getView();
TextView textView = sbView.findViewById(com.google.android.material.R.id.snackbar_text);
mSnackBar.setAction("x", new View.OnClickListener()
{
#Override
public void onClick(View v)
{
//Call your action method here
mSnackBar.dismiss();
}
});
textView.setTextColor(Color.WHITE);
sbView.setBackgroundColor(Color.RED);
textView.setMaxLines(3);
mSnackBar.show();
}
}
This is my current implementation within main activity, I have already Initialized the snackbar class like this:
SnackBarUtils snackBarUtils;
and then called it like this:
snackBarUtils.showProblemSnackBar(MainActivity.this, mPlainTextResponse);
what am I doing wrong? Or what is the correct way to do this?
First of all, you would share the stacktrace of the NPE for more context.
For the snackbar utility:
If you are using callbacks, then you can use the utility for displaying a snackbar with that callback as parameter:
interface onProblemSnackbarClickedListener {
void onActionClicked(View view);
}
...
/* inside SnackBarUtils.java */
...
public static void showProblemSnackbar(View view, #StringRes int message, onProblemSnackbarClickedListener listener){
Snackbar mSnackBar = Snackbar.make(view,message,Snackbar.LENGTH_INDEFINITE)
.setAction("x", new View.OnClickListener() {
#Override
public void onClick(View v) {
listener.onActionClicked(v);
mSnackBar.dismiss();
}
})
mSnackbar.show();
}
The callback could work for the need to listen to it in the activity/fragment.
For the styling of the Snackbar, you can see this related question:
Style SnackBar in theme app.
Keep in mind the migration from "Support design" to MDC (Material design components), that facilitates the global styling of the snackbar with theme attributes.

Modify elements of a layout from another class

I am a student and a beginner in java and android.
I am modifying an android application which allows to configure bluetooth beacons. With the original application we can only configure the beacons one by one, therefore I want to modify the application to be able to configure a good number automatically.
I have a problem when I want to modify an element in the layout of a class from another class.
From the Main class I can interact well with the elements of the Main layout. But since the Main class, I can't interact with other layouts (PasswordDialog in my case). I've been struggling for several days, I tried responses to similar posts but without success because the configuration of my classes is quite special and I don't want to modify them too much so as not to alter the functioning of the application. If anyone has any leads, I would be very grateful;)
The main class:
public class MainActivity extends BaseActivity implements RadioGroup.OnCheckedChangeListener, MokoScanDeviceCallback, AdapterView.OnItemClickListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// ...
}
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
// ...
final PasswordDialog dialog = new PasswordDialog(this); // Another function which already calls the PasswordDialog class which interests me
dialog.setSavedPassword(mSavedPassword);
dialog.setOnPasswordClicked(new PasswordDialog.PasswordClickListener() {
// ...
}
}
#OnClick({R.id.iv_about, R.id.iv_refresh, R.id.bt_auto})
public void onClick(View view) {
switch (view.getId()) {
// ...
case R.id.bt_auto: // When I click on the bt_auto button, the code below is executed
final PasswordDialog dialog = new PasswordDialog(this);
dialog.AutoSetPassword("Moko4321"); // the method I'm trying to launch
// ...
}
}
// ...
}
Now here is the PasswordDialog class which is in another package. I want to modify an element of the passworddialog layout from my Main class :
public class PasswordDialog extends BaseDialog {
#Bind(R.id.et_password)
EditText etPassword; // The element that I want to modify
public PasswordDialog(Context context) {
super(context);
}
// ...
public void AutoSetPassword(String pass) { // My method to modify the EditText
etPassword.setText(pass); // This does not work
// and
((EditText) findViewById(R.id.et_password)).setText(pass); // If I try this instead, it's the same
}
}
Thank you so much for your help :)

How to set the title of Android toolbar from another class?

I would like to do something like this:
if (total != 0) {
percentage = String.valueOf((count * 100) / total);
Log.e("Percentage", percentage);
myActivity.getSupportActionBar().setTitle("Progress: " + percentage + "%.");
}
However, I can't call getSupportActionBar() because it says Non-static method 'getSupportActionBar()' cannot be referenced from a static context. How can I solve this?
Update
This is the method inside my public class where I'd like to call the above code;
#Override
public void onBindViewHolder(final ViewHolder holder, int position) {
holder.checkbox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
}
});
}
Casting your activity can resolve your problem. Suppose your Activity Name is YourCustomActivity. Now cast the Activity like below. Hope it will work.
YourCustomActivity activity=(YourCustomActivity)myActivity;
activity.getSupportActionBar().setTitle("");
Please Let me know if it works or not.
You can pass activity parameter to another class and use activities funcitons like below;
public class CityModel {
Activity activity;
public CityModel(Activity activity) {
this.activity = activity;
}
private void doIt() {
((YourActivity) activity).changeTitle("New Title");
}
}
And define this class instance like below;
public class YourActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
CityModel model = new CityModel(this); // this-> Your activity.
}
public void changeTitle(String newTitle){
getSupportActionBar().setTitle(newTitle);
}
}
Hope it helps.
Thanks to other answers, but none of them fit what I wanted.
I solved it by moving the code to the activity in question and setting the title from there. However, the main change was to post the percentage value from a listener method, in my case: onItemCheckBoxChecked. This meant that every time a user checked a box (could be other listeners in case of a textview or something else) the percentage was calculated in real time. I also made the percentage variable public.
Because getSupportActionBar() is not static method. If you are using this method in static class or static method then you will get below error.
Non-static method getSupportActionBar() cannot be referenced from a static context
If you want to common method for it you can make one think create public method in your activity and call in your fragments.
public void setToolBar(String title) {
getSupportActionBar().setTitle(title);
}
If you have Activity, simply you can call below code.
getSupportActionBar().setTitle(title);
Edit My Code :
public static void setToolbar(final AppCompatActivity activity,String title){
activity.getSupportActionBar().setTitle(title);
}
Edit Code :
My RecyclerViewAdapter class :
public class ExploreGalleryAdapter extends RecyclerView.Adapter<ExploreGalleryAdapter.ViewHolder> {
private AppCompatActivity activity;
private ArrayList<ExploreGalleryModel> exploreGalleryModelArrayList;
// private String status;
public ExploreGalleryAdapter(AppCompatActivity activity, final ArrayList<ExploreGalleryModel> exploreGalleryModelArrayList, final String status) {
this.activity = activity;
this.exploreGalleryModelArrayList = exploreGalleryModelArrayList;
// this.status = status;
}
public void onBindViewHolder(final ViewHolder holder, int position) {
holder.checkbox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
activity.getSupportActionBar().setTitle(title);
}
});
}

method call from adapter class to activity

Adapter:
check_list_item.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
JPrequirements.prepareSelection(v, getAdapterPosition());
}
});
JPrequirements is the activity. and prepareSelection is non-static method inside activity. I cannot access it from adapter.
ERROR:
non static method cannot be referenced from a static context
Which is right. that's why I tried with:
JPrequirements().prepareSelection(v, getAdapterPosition()); // Creating an instance...
But, the problem is I lost all activity component here. eg. layout components and other supporting variables. I don't want that. What is the best way to deal with this? How can I get updated value from adapter to activity? So, I can display it real-time.
Thanks.
You can achieve this via interface. Firstly, define an interface class as:
public interface ActivityAdapterInterface {
public void prepareSelection(View v, int position);
}
Now, implement the interface in your Activity as:
public class JPrequirements extends AppCompatActivity implements ActivityAdapterInterface {
...
public void prepareSelection(View v, int position) {
// cool stuff here
}
...
}
Make sure you pass this interface reference to your Adapter via its constructor. Then finally call it on click as:
check_list_item.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mActivityAdapterInterface.prepareSelection(v, getAdapterPosition());
}
});
[EDIT]
To provide the interface to your Adapter provide it the constructor.
public class YourAdapter ... {
private ActivityAdapterInterface mActivityAdapterInterface;
public YourAdapter(..., ActivityAdapterInterface activityAdapterInterface) {
activityAdapterInterface = mActivityAdapterInterface;
}
}

Communicate from Activity to Fragment using Interface

I have searched SO for this problem but was not able to find anything which would solve my problem. My problem is, I have a activity which contains FrameLayout which is constantly updated with different fragments. The top view and bottom view are going to remain same hence they are in the layout of the
activity.
As you can see bottom view has a button on click of that i want to make changes in the fragments which will be present in the FrameLayout.
I have created a interface
public interface ShowFormula {
void showFormula(boolean show);
}
which i will use to implement in the fragment.
Now the main problem in my MainActivity class i am trying to initialize the interface but not able to as i am getting class cast exception
showFormula = (ShowFormula) this;//yes i know this is wrong
How should i initialize this in order to communicate with the fragment.
Main goal is to toggle the view in fragments on click of the button in activity.
Thanks in advance.
You don't need to use an interface to make calls from an Activity to a Fragment. Just keep a reference to the current Fragment, and call into a public method in the Fragment from the Activity.
If you have multiple Fragments and you don't want to keep a reference for each one, you can create a Fragment base class, declare the common method in the base class, and then implement that method override in all of your Fragments that inherit from the base Fragment. Then, keep one reference of the base Fragment type, and always have it set to the Fragment that is shown currently.
Activity ---> Fragment
Communication from Activity to Fragment is pretty straightforward. You
really don't need a listener.
Let's say you have a method inside Fragment share()
public class MyFragment extends Fragment{
public static MyFragment getInstance()
{
return new MyFragment();
}
........
public void share()
{
// do something
}
}
How to call share() method from an Activity?
Get the reference of the Fragment and call the method. Simple!
MyFragment myFragment = MyFragment.getInstance();
myFragment.share();
You can see the full working code for Fragment to Fragment Communication
Just to add to Daniel Nugent's brilliant answer, here are snippets from my working code for delegating calls from Activity to Fragment.
I have a MVP architecture and I have defined the error handling method showError on the BaseView class and the code below demonstrates how to handle the UI on a TargetFragment class. I, specifically needed to hide my progress spinner on the fragment upon any error scenario. Here's the code snippets for the base classes:
public interface BaseView {
void showError(ErrorResponse errorResponse);
}
public abstract class BaseActivity implements BaseView {
#Override
public void showError(ErrorResponse errorResponse) {
// Check error condition or whatever
// ...
MaterialDialog dialog = new MaterialDialog.Builder(this)
.title(R.string.dialog_error_title)
.content(R.string.error_no_internet)
.positiveText(R.string.dialog_action_ok)
.build();
dialog.show();
}
}
public abstract class BaseFragment implements BaseView {
#Override
public void showError(ErrorResponse errorResponse) {
((BaseView) getActivity()).showError(errorResponse);
}
}
And, this is how I handle UI inside my TargetFragment class:
public final class TargetFragment extends BaseFragment implements TargetView {
#Override
public void showError(ErrorResponse errorResponse) {
super.showError(errorResponse);
hideSpinner();
// Do other UI stuff
// ...
}
private void hideSpinner() {
spinner.setVisibility(View.INVISIBLE);
}
}
a clean solution:
public interface ShowFormula {
public void showFormula(boolean show);
}
public class MyActivity implements ShowFormula {
...
#Override
public void showFormula(boolean show) {
/** Your Code **/
}
...
}
public class MyFragment {
private ShowFormula listener;
...
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
listener = (ShowFormula) activity;
// listener.showFormula(show?);
} catch (ClassCastException castException) {
/** The activity does not implement the listener. **/
}
}
...
}
simple thing make public method in fragments then call it on from your activity.
e.g
MyFragment fragment = new MyFragment();
fragment.doSomeThing();
doSomeThing() is a public method in MyFragment.
Activity to Fragment Communication via Interface:
public class MyActivity {
private ShowFormula showFormulaListener;
public interface ShowFormula {
public void showFormula(boolean show);
}
public void setListener(MyFragment myFragment) {
try {
showFormulaListener = myFragment;
} catch(ClassCastException e) {
}
}
}
public class MyFragment implements ShowFormula{
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
((MyActivity) activity).setListener(this);
} catch (ClassCastException e) {
Log.e(TAG, e.toString());
}
}
#Override
public void showFormula(boolean show) {
/** Your Code **/
}
}
Once you are done setting this, you can call 'showFormulaListener.showFormula(boolVal)'

Categories