I want to override a method present in an Activity through a Fragment which is added in the activity.
I have following setup:
BaseActivity
public class BaseActivity extends AppCompatActivity {
// gets triggered whenever I set a toolbar title
// from an Activity or Fragment
public boolean shouldLimitToolbarCharacters () {
return true;
}
}
BaseFragmentActivity
public class BaseFragmentActivity extends BaseActivity implements ToolbarBehaviour {
// override from BaseActivity and from ToolbarBehaviour
#Override
public boolean shouldLimitToolbarCharacters () {
// instead send it to fragment somehow
return true;
}
}
ToolbarBehaviour
// implemented by BaseFragmentActivity above
interface ToolbarBehaviour {
boolean shouldLimitToolbarCharacters();
}
BaseFragment
public class BaseFragment extends Fragment {
#Override
public void onAttach (Context context) {
if (context instanceof ToolbarBehaviour) {
ToolbarBehaviour toolbarBehaviour = (ToolbarBehaviour) context;
// ?? now what
}
}
}
How do I override BaseFragmentActivity's shouldLimitToolbarCharacters() from BaseFragment or its sub-fragments?
Whenever I trigger shouldLimitToolbarCharacters() from a sub-fragment of BaseFragment, it should use sub-fragment's provided overridden method for shouldLimitToolbarCharacters().
Thanks.
Call a method of fragment inside Activity as in
BaseFragmentActivity
public class BaseFragmentActivity extends BaseActivity implements ToolbarBehaviour {
BaseFragment fragment; // init in oncreate or something;
// override from BaseActivity and from ToolbarBehaviour
#Override
public boolean shouldLimitToolbarCharacters () {
if(fragment == null)
return false;
return fragment.shouldLimitToolbarCharacters();
}
}
BaseFragment
public class BaseFragment extends Fragment {
public boolean shouldLimitToolbarCharacters(){
return true; // do what ever you want to do
}
}
you can directly access the activity method through ((BaseFragmentActivity )getActivity()).shouldLimitToolbarCharacters();
and use like this
#Override
public void onAttach (Context context) {
if (context instanceof BaseFragmentActivity) {
((BaseFragmentActivity)getActivity()).shouldLimitToolbarCharacters();
}
}
Related
I have ViewModel
class MyViewModel extends BaseViewModel{
public void foo(){
// some code or return some boolean
}
}
View Class
class MyView extends View{
private MyViewModel myviewmodel;
public void bindTo(MyViewModel viewModel) {
this.viewModel = viewModel;
context = viewModel.getContext();
validateView();
requestLayout();
}
private validateView(){
//some code
}
}
this bind view method bind with adapter
I want to get call back in Myview class when ever i will validateView will call please suggest me how get call back from Viewmodel method to View in android.
it is best practice to use live data for communicating from viewmodel to your view.
class MyViewModel {
private MutableLiveData<Boolean> state = new MutableLiveData<Boolean>;
public LiveData<Boolean> getState() {
return state;
}
public void foo() {
//bool = value returned of your work
state.setValue(bool);
} }
class Myview extends View {
public void onCreate() {
viewmodel.getState().observe(this, observer); // 'this' is life cycle owner
}
final Observer<Boolean> observer = new Observer<Boolean>() {
#Override
public void onChanged(#Nullable final Boolean state) {
// do your work with returned value
}
}; }
for more details refer to this
Correct Me if i wrong
first you need to make interface class
public interface ViewModelCallback {
void returnCallBack(Boolean mBoolean);
}
then your View class implements that interface class & Override that method
class MyView extends View implements ViewModelCallback
#Override
public void returnCallBack(Boolean mBoolean) {
//here you will retrieve callback
// Do Something
}
Next you just pass a value from your view model
class MyViewModel {
private ViewModelCallback myViewCallBack;
public void foo() {
Boolean yourReturnValue = false;
myViewCallBack.returnCallBack(yourReturnValue);
}
}
I have the MainActivity that a want to communicate with a class using an interface.
public interface MyInterface(){
public void doAction();
}
In my MainActivity I will have this piece of code:
public class MainActivity extends AppCompatActivity implements MyInterface(){
//....some more code here
#Override
public void doAction() {
//any code action here
}
//....some more code here
}
So now, If I have another class (NOT ACTIVITY), how should I correctly make the link between class---interface---mainActivity??
public class ClassB {
private MyInterface myinterface;
//........
//...... how to initialize the interface
}
I am confused about how to initialize and use the interface in ClassB
In the constructor of other class: ClassB, accept interface as argument and pass reference of Activity, hold that object in your Activity.
like so:
public class MainActivity extends AppCompatActivity implements MyInterface()
{
private ClassB ref; // Hold reference of ClassB directly in your activity or use another interface(would be a bit of an overkill)
#Override
public void onCreate (Bundle savedInstanceState) {
// call to super and other stuff....
ref = new ClassB(this); // pass in your activity reference to the ClassB constructor!
}
#Override
public void doAction () {
// any code action here
}
}
public class ClassB
{
private MyInterface myinterface;
public ClassB(MyInterface interface)
{
myinterface = interface ;
}
// Ideally, your interface should be declared inside ClassB.
public interface MyInterface
{
// interface methods
}
}
FYI, this is also how View and Presenter classes interact in MVP design pattern.
public class MainActivity extends AppCompatActivity implements
MyInterface
{
OnCreate()
{
ClassB classB= new ClassB(this);
}
}
public class ClassB
{
private MyInterface myinterface;
public ClassB(MyInterface myinterface)
{
this.myinterface=myinterface;
}
void anyEvent() // like user click
{
myinterface.doAction();
}
}
public class MainActivity extends AppCompatActivity implements MyInterface(){
private ClassB ref;
#Override
public void onCreate (Bundle savedInstanceState) {
ref = new ClassB();
ref.setMyinterface(this);
}
#Override
public void doAction () {
// any code action here
}
}
public class ClassB{
private MyInterface myinterface;
public setMyInterface(MyInterface interface){
myinterfece = interface;
}
public interface MyInterface{
// interface methods
}
}
//-------------------------------------
//Two way communication using Interface
//-------------------------------------
//A. Interfaces
//Communicator Interface ( Activity to Fragment )
public interface CommunicateToFragment {
public void CallBack(String name);
}
// Communicator Interface ( Fragment to Main )
public interface CommunicateToMain {
public void respond(String data);
}
//B. Main Class implements CommunicateToMain Interface
//Use CommunicateToFragment interface to send data in FragmentA
public class MainActivity extends AppCompatActivity implements CommunicateToMain {
private CommunicateToFragment communicateToFragment;
public void setCommunicateToFragment(CommunicateToFragment communicateToFragment) {
this.communicateToFragment = communicateToFragment;
}
#Override
protected void onCreate (Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Override
public void respond (String data) {
communicateToFragment.CallBack("Callbacked when onCreate method Created" + data);
Log.d("test","get result from fragment: " + data);
FragmentManager manager = getFragmentManager();
FragmentB f2 = (FragmentB) manager.findFragmentById(R.id.id_fragment2);
f2.changeText(data);
}
}
//C. FragmentA implements CommunicateToFragment
//Use CommunicateToMain interface to send data in MainActivity
public class FragmentA extends Fragment implements View.OnClickListener, CommunicateToFragment{
Button button;
int counter=0;
CommunicateToMain commToMain;
#Nullable
#Override
public View onCreateView (LayoutInflater inflater, #Nullable ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_a,container,false);
}
#Override
public void onActivityCreated (#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
commToMain = (CommunicateToMain) getActivity();
button = getActivity().findViewById(R.id.button);
button.setOnClickListener(this);
if(getActivity() instanceof MainActivity){
((MainActivity) getActivity()).setCommunicateToFragment(this);
}
}
#Override
public void onClick (View view) {
counter++;
commToMain.respond("The button was clicked" + counter + " Times");
}
#Override
public void CallBack(String name) {
Log.d("test","get result from main activity: " + name);
}
}
I've been questioning myself a long time how to solve this issue but didn't find a proper solution. I have the following subclasses of Fragment:
BaseListFragment extends ListFragment
BaseDialogFragment extends DialogFragment
BaseFragment extends Fragment
Each of these BaseFragments override the same methods and implement the same functionality. For example:
public abstract class BaseFragment extends Fragment
{
private BaseActivity baseActivity;
#Override
public void onAttach(Context context)
{
super.onAttach(context);
baseActivity = (BaseActivity) context;
}
#Override
public void onDetach()
{
baseActivity = null;
super.onDetach();
}
// other overridden methods.
}
public abstract class BaseDialogFragment extends DialogFragment
{
private BaseActivity baseActivity;
#Override
public void onAttach(Context context)
{
super.onAttach(context);
baseActivity = (BaseActivity) context;
}
#Override
public void onDetach()
{
baseActivity = null;
super.onDetach();
}
// other overridden methods.
}
public abstract class BaseListFragment extends ListFragment
{
private BaseActivity baseActivity;
#Override
public void onAttach(Context context)
{
super.onAttach(context);
baseActivity = (BaseActivity) context;
}
#Override
public void onDetach()
{
baseActivity = null;
super.onDetach();
}
// other overridden methods.
}
All other fragments in my app then extend any of these Fragments. However, the problem is that I don't want to code everything three times.
Want can I do to solve this problem?
I'm making a conversion from 2 clases that extends ListActivity to extend ListFragment due to code proposals.
As I know, the Fragment is related to the Activity, so at first using getActivity()... should do the work to adapt most methods. Other times, I've defined Activity activity_context; and I use this.
Anyway, I have some functions that I'm not able to adapt, and I would need some help.
The first is: RecentCallsListActivity extends Fragment
public class RecentCallsListActivity extends ListFragment
...
private static final class QueryHandler extends AsyncQueryHandler {
private final WeakReference<RecentCallsListActivity> mActivity;
...
public QueryHandler(Context context) {
super(context.getContentResolver());
mActivity = new WeakReference<RecentCallsListActivity>(
(RecentCallsListActivity) context); //GETTING THE ERROR HERE
}
ERROR: Cannot cast from context to RecenCallsListActivity
public void onActivityCreated(Bundle state) {
super.onActivityCreated(state);
mQueryHandler = new QueryHandler(activity_context);
The second is: CallDetailActivity extends Fragment
public class CallDetailActivity extends ListFragment
...
public boolean onKeyDown(int keyCode, KeyEvent event) {
switch (keyCode) {
case KeyEvent.KEYCODE_CALL: {
// Make sure phone isn't already busy before starting direct call
TelephonyManager tm = (TelephonyManager)
getActivity().getSystemService(Context.TELEPHONY_SERVICE);
if (tm.getCallState() == TelephonyManager.CALL_STATE_IDLE) {
Intent callIntent = new Intent(Intent.ACTION_CALL,
Uri.fromParts("tel", mNumber, null));
startActivity(callIntent);
return true;
}
}
}
return super.onKeyDown(keyCode, event); //GETTING IT HERE
}
ERROR: The method onkeyDown(int, keyevent) is undefined for the type ListFragment
QueryHandler
At runtime you're providing a class that is not a RecentCallsListActivity or extend from it. The way of handling this is to define an interface that exposes an API that should be implemented by parent activity. If you have multiple activities that need to implement this interface and have the same implementation, you can make a super Activity that implements your interface and each of your activity will extend from this super class. But if you have a single class don't need to do this.
onKeyDown handling - as you can see from API, the fragment doesn't expose any onKeyDown. I have some ideas why this was not implemented, but you can delegate this action from activity to fragment, so that if the fragment is not present and it doesn't wish to consume the event, then you can call activity's super.onKeyDown.
Maybe some code will provide some light and will be helpful.
Sample fragment class:
public class QueryFragment extends Fragment {
public static interface RecentCallsLister {
public void someAction();
}
private RecentCallsLister recentCallsListener;
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
if (activity instanceof RecentCallsLister) {
this.recentCallsListener = (RecentCallsLister) activity;
} else {
throw new ClassCastException("Parent class does not implement RecentCallsLister");
}
}
#Override
public void onDetach() {
this.recentCallsListener = null;
super.onDetach();
}
public boolean manageOnKeyDown(int keyCode, KeyEvent event) {
if(keyCode == KeyEvent.KEYCODE_CALL) {
// your specific code
return true;
}
return false;
}
}
Sample parent activity class:
public class QueryParentActivity extends FragmentActivity implements RecentCallsLister {
private static final String QUERY_FRAGMENT_TAG = "QUERY_FRAGMENT_TAG";
protected void addQueryFragment() {
QueryFragment fragment = new QueryFragment();
getSupportFragmentManager().beginTransaction()
.add(R.id.where_do_want_to_have_me, fragment, QUERY_FRAGMENT_TAG).commit();
}
#Override
public void someAction() {
}
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (queryFragmentConsumedKeyDown(keyCode, event)) {
return true;
}
return super.onKeyDown(keyCode, event);
}
private boolean queryFragmentConsumedKeyDown(int keyCode, KeyEvent event) {
FragmentManager fm = getSupportFragmentManager();
Fragment fragment = fm.findFragmentByTag(QUERY_FRAGMENT_TAG);
if (fragment != null) {
return ((QueryFragment) fragment).manageOnKeyDown(keyCode, event);
}
return false;
}
}
EDIT for your first issue:
replace the QueryHandler constructor from:
public QueryHandler(Context context) {
super(context.getContentResolver());
mActivity = new WeakReference<RecentCallsListActivity>((RecentCallsListActivity) context);
}
to:
public QueryHandler(Context context, RecentCallsListActivity fragmentInstance) {
super(context.getContentResolver());
mActivity = new WeakReference<RecentCallsListActivity>(fragmentInstance);
}
Instantiate it as: mQueryHandler = new QueryHandler(activity_context, this);
MAIN ACTIVITY
public class MyActivity() extends Activity
{
onCreate()
{
MyClass myobj=new MyClass();
}
public void Mymethod()
{}
}
//HELPER CLASS IN A SEPARATE FILE
public class MyClass()
{
MyClass(Context context)
{
}
}
I tried to call Mymethod() from an instance of MyClass.
I would really appreciate any help. Thanks.
Why not just pass the activity to the constructor like
public class MyActivity extends Activity {
onCreate(){
MyClass myobj=new MyClass(MyActivity.this);
}
public void myMethod(){
}
}
//HELPER CLASS IN A SEPARATE FILE
public class MyClass{
public MyClass(MyActivity act) {
act.myMethod();
}
}
Make that method as static so you can call without creating the class object
public static void Mymethod()
{}
and call like this way
MainActivity.Mymethod();
This is probably the best way to do it. This is how I'm doing it. It's called a Singleton Design Pattern:
public class MyActivity extends Activity {
private static MainActivity instance;
public static MainActivity getInstance() {
if(instance==null){
setInstance(this);
}
return instance;
}
public static void setInstance(MainActivity instance) {
MainActivity.instance = instance;
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setInstance(this);
}
}
If I'm understanding you correctly I believe you can solve your problems using an interface as a callback.
////ACTIVITY/////////////////////////////////
public class MyActivity() extends Activity {
onCreate()
{
MyClass myObj=new MyClass();
//Set the listener on the object. Created as anonymous
myObj.setListener(new MyClass.Listener() {
myMethod();
});
}
}
public void myMethod(){
}
//////Custom Class//////////////////
public class MyClass {
Listener mListener;
public interface Listener {
public void onInterestingEvent();
}
public void setListener(Listener listener) {
mListener = listener;
}
public void someUsefulThingTheClassDoes() {
//Do your code here and when you're ready to call the activity's method do this
mListener.onInterestingEvent();
}
}
I had an inner class that I wanted to pull out into a more general library "Helper" class. I had the same issue you do. I got around it by making the helper class abstract, with a single abstract method. Then in my project package I extended the helper class with a constructor call in the specific class.
public class MyActivity extends Activity {
onCreate() {
MyHelperClass = new MyHelperClass(this, "foobar");
}
public void myMethod() {
// Code...
}
}
// In a different file
public class MyHelperClass extends HelperClass {
private MyActivity mInstance;
public MyHelperClass(MyActivity act, String data) {
super();
this.mInstance = act;
this.mActivity = act; // Useful for calling generic Activity methods in the HelperClass
this.mData = data;
}
protected void callMyActivityMethod() {
mInstance.myMethod();
}
}
// In a different file
public abstract class HelperClass {
protected Activity mActivity;
protected String mData;
public HelperClass() {
// Subclass will set variables
}
protected abstract void callMyActivityMethod();
// More code for all the other stuff the class does
}
In this way, I have a helper class that contains the vast majority of the "work", and all I have to do is make a subclass with the constructor and one method in order to get access to the calling activity's method of interest.
You have to pass instance of MainActivity into another class, then you can call everything public (in MainActivity) from everywhere.
MainActivity.java
public class MainActivity extends AppCompatActivity {
// Instance of AnotherClass for future use
private AnotherClass anotherClass;
#Override
protected void onCreate(Bundle savedInstanceState) {
// Create new instance of AnotherClass and
// pass instance of MainActivity by "this"
anotherClass = new AnotherClass(this);
}
// Method you want to call from another class
public void myMethod(){
...
}
}
AnotherClass.java
public class AnotherClass {
// Main class instance
private MainActivity mainActivity;
// Constructor
public AnotherClass(MainActivity activity) {
// Save instance of main class for future use
mainActivity = activity;
// Call method in MainActivity
mainActivity.myMethod();
}
}
In MainActivity.class file
You have to pass MainActivity context from MainActivity Class. Then in MyClass you have to Get MainActivity context. Remember Context and MyActivity are two different reference.
public class MyActivity extends Activity
{
onCreate(){
MyClass myobj=new MyClass(MyActivity context);
}
public void Mymethod(){}
}
//HELPER CLASS IN A SEPARATE FILE
public class MyClass()
{
MyActivity context;
MyClass(MyActivity context)
{
this.context = context;
this.context.Mymethod();
//Or you can directly use activity context
context.Mymethod();
}
}
I decided to write the HelperClass MyClass as an inner class of MyActivity class. This allows it full access to parent class but the bad thing is now MyClass is restricted to MyActivity class only.
public class MyActivity() extends Activity
{
onCreate()
{
MyClass myobj=new MyClass();
}
public void myMethod()
{
}
}
//INNER CLASS
public class MyClass
{
public MyClass()
{
}
//I can directly access the MyMethod
myMethod();
}