Bound service with Activity with Fragment - android

I have question about binding service. I am having parent activity and several fragments, i am binding and unbinding service with activity,now can i get access to that service in fragment? I need to use ServiceConnection in Fragments.

Yes, you could access services of parent activity inside your fragments by something like this :
getActivity().getMyService()

===========in you activity=================
callbackFragmentServiceConnection callbackfragment;
public interface callbackFragmentServiceConnection{
public void servicefun(MusicPlayService musicPlayService);
}
public void registerClientFragment(Fragment fragment){
this.callbackfragment = (callbackFragmentServiceConnection)fragment;
}
/** Defines callbacks for service binding, passed to bindService() */
private ServiceConnection mConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName className,
IBinder service) {
mBound = true;
callbackfragment.servicefun(musicPlayService);
}
#Override
public void onServiceDisconnected(ComponentName arg0) {
mBound = false;
}
};
=================in your fragment=============
public class FragmentLibraryTrack extends Fragment implements
MainActivity.callbackFragmentServiceConnection {
MainActivity mainActivity;
#Override
public void onAttach(Context context) {
super.onAttach(context);
mainActivity= (MainActivity) context;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
mainActivity.registerClientFragment(this);
}
#Override
public void servicefun(MusicPlayService musicPlayService) {
Log.e("reached sucessfully","yes");
}
}

Related

Object reference changes when called from onPropertyChanged(DataBinding Android)

public class FilterFragmentExp extends BaseFragmentFilter implements ListingMVPview{
#Inject PresenterListing presenterExp;
private FilterUtilsModel filterModel;
private ListingModel listingModel,listingModel_tmp;
public static FilterFragmentExp newInstance(FilterUtilsModel filterModel,ListingModel listingModel) {
FilterFragmentExp fragment = new FilterFragmentExp();
Bundle bundle = new Bundle();
bundle.putSerializable("filter",filterModel);
bundle.putSerializable("listing",listingModel);
fragment.setArguments(bundle);
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getComponent().inject(this);
presenterExp.attachView(this);
receiveArguments();
filterModel.addOnPropertyChangedCallback(new Observable.OnPropertyChangedCallback() {
#Override
public void onPropertyChanged(Observable observable, int i) {
presenterExp.initialize(filterModel.getExpMap(),TYPE_EXP);
}
});
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return super.onCreateView(inflater, container, savedInstanceState);
}
#Override
public void onDestroy() {
super.onDestroy();
presenterExp.detachView();
}
#Override
protected int getLayout() {
return R.layout.fragment_filter_exp;
}
#Override
protected FilterUtilsModel getFilter() {
}
private void receiveArguments(){
filterModel = (FilterUtilsModel) getArguments().getSerializable("filter");
listingModel = (ListingModel) getArguments().getSerializable("listing");
listingModel_tmp = listingModel;
}
#Override
public void showLoading() {
}
#Override
public void hideLoading() {
}
#Override
public void showRetry() {
}
#Override
public void hideRetry() {
}
#Override
public void showError(String message) {
}
}
When I moved to this fragment for the first time everything works well, but from next time(pressed back and come back again) I am getting a nullpointer exception from this line -
presenterExp.initialize(filterModel.getExpMap(),TYPE_EXP);
I am supposed to get this error only if I wont set any view(MVP view, here its ListingMVPview) to the presenter object(presenterExp), but I already set it on this line
presenterExp.attachView(this);
Here is my Presenter -
public class PresenterListing extends BasePresenter<ListingMVPview> {
private final Context context;
#Inject
public PresenterListing(#ActivityContext Context context) {
this.context = context;
}
#Override
public void attachView(ListingMVPview mvpView) {
super.attachView(mvpView);
}
#Override
public void detachView() {
super.detachView();
}
public void initialize(Map options, String type) {
getMVPView().showLoading();
this.getListing(options,type);
}
....
}
Here in the above code getMVPView() returning null, though I have set MVP view.
I have used Dagger2 for dependency injection and using constructor injection for creating PresenterListing objects and using MVP architecture.
Any clues would be helpful as this problem is happening on when called from onPropertyChanged, if I move the code to some other place(say on some view's onclicklistener) everything works fine
you can add a null judgement
if (null) {...
advise start to use google mvp, good lucky

Opening android application from background

Whenever my android application goes into the background i always wants to open my password activity every time application comes from background, How can i implement this functionality in my code?
Please follow these steps:
Add New Class Global
public class Global extends Application
{
private static Global mInstance;
#Override
public void onCreate() {
super.onCreate();
mInstance = this;
ApplicationLifeCycleHandler handler = new ApplicationLifeCycleHandler();
registerActivityLifecycleCallbacks(handler);
registerComponentCallbacks(handler);
}
public static Global getInstance(){
return mInstance;
}
}
Add this line in your manifest in application tag like
<application
android:name=".Global"
</application>
Add this class and open your password intent when app come background to foreground like
public class ApplicationLifeCycleHandler implements Application.ActivityLifecycleCallbacks, ComponentCallbacks2 {
public static Activity activity;
private static final String TAG = ApplicationLifeCycleHandler.class.getSimpleName();
public static boolean isInBackground = true;
#Override
public void onActivityCreated(Activity activity, Bundle bundle) {
}
#Override
public void onActivityStarted(Activity activity) {
this.activity = activity;
}
#Override
public void onActivityResumed(Activity activity) {
this.activity = activity;
if (isInBackground) {
Intent intent = new Intent(activity, PasswordActivity.class);//set your password activity
activity.startActivity(intent);
Log.d(TAG, "app went to foreground");
isInBackground = false;
}
}
#Override
public void onActivityPaused(Activity activity) {
}
#Override
public void onActivityStopped(Activity activity) {
}
#Override
public void onActivitySaveInstanceState(Activity activity, Bundle bundle) {
}
#Override
public void onActivityDestroyed(Activity activity) {
}
#Override
public void onConfigurationChanged(Configuration configuration) {
}
#Override
public void onLowMemory() {
}
#Override
public void onTrimMemory(int i) {
if (i == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {
Log.d(TAG, "app went to background");
isInBackground = true;
}
}
}
Hope it will help you and please let me know if you are facing any issue. Thanks

Android unit testing fragment with roboletric in MPV application

I am reinventing my app using a classic MVP approach. In order to to this I read many many articles and tutorials, and what I came out with is that the best way is to :
create an interface for the presenter and one for the view
make fragments and activities implements view interfaces
create an implementation of the presenter interface, which takes in the constructor an instance of the the view it manages, and hold a reference to the presenter inside the view's implementation.
So I have created this classes
VIEW INTERFACE
public interface SignupEmailView extends BaseView {
void fillEmail(String email);
void onEmailInvalid(String error);
void onDataValidated();
}
PRESENTER INTERFACE
public interface SignupEmailPresenter {
void initData(Bundle bundle);
void validateData(String email);
}
VIEW IMPLEMENTATION
public class FrSignup_email extends BaseSignupFragmentMVP implements IBackHandler, SignupEmailView {
public static String PARAM_EMAIL = "param_email";
#Bind(R.id.signup_step2_new_scrollview)
ScrollView mScrollview;
#Bind(R.id.signup_step2_new_lblTitle)
SuperLabel mLblTitle;
#Bind(R.id.signup_step2_new_lblSubtitle)
TextView mLblSubtitle;
#Bind(R.id.signup_step2_new_txtEmail)
EditText mTxtEmail;
#Bind(R.id.signup_step2_new_btnNext)
Button mBtnNext;
protected SignupActivityView mActivity;
SignupEmailPresenter mPresenter;
public FrSignup_email() {
// Required empty public constructor
}
public static FrSignup_email newInstance(String email) {
FrSignup_email fragment = new FrSignup_email();
Bundle b = new Bundle();
b.putString(PARAM_EMAIL, email);
fragment.setArguments(b);
return fragment;
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mActivity = (SignupActivityView) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement IResetPasswordBridge");
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = loadView(inflater, container, savedInstanceState, R.layout.fragment_signup_email);
mPresenter = new SignupEmailPresenterImpl(this);
ButterKnife.bind(this, view);
return view;
}
#Override
public final void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
applyCircularReveal();
mPresenter.initData(this.getArguments());
mTxtEmail.setImeOptions(EditorInfo.IME_ACTION_NEXT);
mTxtEmail.setOnEditorActionListener(new TextView.OnEditorActionListener() {
#Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
if (actionId == EditorInfo.IME_ACTION_NEXT) {
mPresenter.validateData(mTxtEmail.getText().toString());
return true;
}
return false;
}
});
mTxtEmail.setOnTouchListener(new OnTouchCompoundDrawableListener_NEW(mTxtEmail, new OnTouchCompoundDrawableListener_NEW.OnTouchCompoundDrawable() {
#Override
public void onTouch() {
mTxtEmail.setText("");
}
}));
mBtnNext.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mPresenter.validateData(mTxtEmail.getText().toString());
}
});
}
#Override
public void fillEmail(String email) {
mTxtEmail.setText(email);
}
#Override
public void onEmailInvalid(String error) {
displayError(error);
}
#Override
public void onDataValidated() {
changeFieldToValid(mTxtEmail);
setEmail(mTxtEmail.getText().toString());
// the activity shows the next fragment
mActivity.onEmailValidated();
}
#Override
public boolean doBack() {
if (!isLoading()) {
mActivity.onEmailBack();
}
return true;
}
#Override
public void displayError(String error) {
changeFieldToInvalid(mTxtEmail);
mLblSubtitle.setText(error);
mLblSubtitle.setTextColor(ContextCompat.getColor(getActivity(), R.color.field_error));
}
}
PRESENTER IMPLEMENTATION
public class SignupEmailPresenterImpl implements SignupEmailPresenter {
private SignupEmailView mView;
public SignupEmailPresenterImpl(SignupEmailView view) {
mView = view;
}
#Override
public void initData(Bundle bundle) {
if (bundle != null) {
mView.fillEmail(bundle.getString(FrSignup_email.PARAM_EMAIL));
}
}
#Override
public void validateData(String password) {
ValidationUtils_NEW.EmailStatus status = ValidationUtils_NEW.validateEmail(password);
if (status != ValidationUtils_NEW.EmailStatus.VALID) {
mView.onEmailInvalid(ValidationUtils_NEW.getEmailErrorMessage(status));
} else {
mView.onDataValidated();
}
}
}
Now the fragment is held by an activity which implements this view interface and has its own presenter
public interface SignupActivityView extends BaseView {
void onEmailValidated();
void onPhoneNumberValidated();
void onPasswordValidated();
void onUnlockCodeValidated();
void onResendCodeClick();
void onEmailBack();
void onPhoneNumberBack();
void onPasswordBack();
void onConfirmCodeBack();
void onSignupRequestSuccess(boolean resendingCode);
void onSignupRequestFailed(String errorMessage);
void onTokenCreationFailed();
void onUnlockSuccess();
void onUnlockError(String errorMessage);
void showTermsAndConditions();
void hideTermsAndConditions();
}
My idea is to have a unit test for each project unit, so for each view and presenter implementation I want a unit test, so I want to unit test my fragment with roboletric, and for example I want to test that if I click the "NEXT" button and the email is correct, the hosting Activity's onEmailValidated()method is called. This is my test class
public class SignupEmailViewTest {
private SignupActivity_NEW mActivity;
private SignupActivity_NEW mSpyActivity;
private FrSignup_email mFragment;
private FrSignup_email mSpyFragment;
private Context mContext;
#Before
public void setUp() {
final Context context = RuntimeEnvironment.application.getApplicationContext();
this.mContext = context;
mActivity = Robolectric.buildActivity(SignupActivity_NEW.class).create().visible().get();
mSpyActivity = spy(mActivity);
mFragment = FrSignup_email.newInstance("");
mSpyFragment =spy(mFragment);
mSpyActivity.getFragmentManager()
.beginTransaction()
.replace(R.id.signupNew_fragmentHolder, mSpyFragment)
.commit();
mSpyActivity.getFragmentManager().executePendingTransactions();
}
#Test
public void testEmailValidation() {
assertTrue(mSpyActivity.findViewById(R.id.signup_step2_new_lblTitle).isShown());
assertTrue(mSpyActivity.findViewById(R.id.signup_step2_new_lblSubtitle).isShown());
mSpyActivity.findViewById(R.id.signup_step2_new_btnNext).performClick();
assertTrue(((SuperLabel) mSpyActivity.findViewById(R.id.signup_step2_new_lblSubtitle)).getText().equals(mContext.getString(R.string.email_empty)));
((EditText) mSpyActivity.findViewById(R.id.signup_step2_new_txtEmail)).setText("aaa#bbb.ccc");
mSpyActivity.findViewById(R.id.signup_step2_new_btnNext).performClick();
verify(mSpyFragment).onDataValidated();
verify(mSpyActivity).onEmailValidated();
}
}
everything works well, is just the last verify which doesn't work. Note that the previous verify works, so onEmailValidated is called for sure.
Aside from this specific case, I have some point to discuss:
If with roboeletric I am forced to use an activity to instantiate a fragment, how can I test the fragment in complete isolation (which would be the unit tests goal)? I mean, if I use Robolectric.setupActivity(MyActivity.class) and the activity instantiates somewhere a fragment, it will load the activity and the fragment, which is good, but what if the activity manages a flow of fragments? How can I test the second or third fragment without manually navigating to it? Someone can say to use a dummy activity and use FragmentTestUtil.startFragment, but what in the fragment's onAttach() method is implemented the bridging with the parent activity? Is it me going on the wrong way or are this problems still unsolved?
thanks
Actually you don't even require Roboelectric to do any of those tests.
If each fragment/activity implements a different view interface you could implement fake views and instantiate those instead of the activity/fragment. In this way you could have isolated tests.
If you don't want to implement all the methods of the view interface you could use Mockito and stub only the ones that your unit test requires.
Let me know if you need sample code.

BroadcastReceiver in order to pass data from another Activity to Fragment

Let's say I have MainActivity where are few Fragments in ViewPager. I want to pass data from another Activity to one of these fragments. I'm doing this by BroadcastReceiver.
public class MyFragment extends Fragment {
private MyFragmentReceiver mReceiver;
public MyFragment() {
super();
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mReceiver = new MyFragmentReceiver();
getActivity().registerReceiver(mReceiver, new IntentFilter("fragmentUpdater"));
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_my, container, false);
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
// My code here
}
public class MyFragmentReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
//My methods
}
}
#Override
public void onDestroy() {
super.onDestroy();
if (mReceiver != null)
getActivity().unregisterReceiver(mReceiver);
}
}
So in my AnotherActivity I'm doing something like this:
Intent data = new Intent("fragmentUpdater");
MyApplication.getInstance().getMainActivity().sendBroadcast(data);
Where MyApplication is singleton which contains MainActivity.
I noticed that BroadcastReceiver is putting something into logs, and I am wondering is that the best way to do it.
Are there better ways to pass data from another activity to specific Fragment or call methods in that Fragment?
Do I have to include something in AndroidManifest.xml related to BroadcastReceiver?
One alternative is using an interface for communicating between your activity and fragments. Example:
Interface
public interface MyInterface {
void setSomeValue(int someValue);
int getSomeValue();
}
Activity
public class MyActivity extends Activity implements MyInterface {
private int someValue;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// do the usual stuff
}
// implement from MyInterface
#Override
public void setSomeValue(int someValue) {
this.someValue = someValue;
}
// implement from MyInterface
#Override
public int getSomeValue() {
return someValue;
}
}
Fragment
public class MyFragment extends Fragment {
private MyInterface mi;
#Override
public void onAttach(Context context) {
super.onAttach(context);
mi = (MyInterface) context;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
mi.setSomeValue(20);
int someValue = mi.getSomeValue();
}
}
You can use the interface to communicate between one or more activities, multiple fragments, views, tasks, services, etc etc etc. If you were to go this route, I would create a base activity which implements MyInterface and its methods, and have all other activities extend the base activity. I would even create a base fragment which calls onAttach(), and have all my other fragments extend this base fragment (so that I don't need to call onAttach() in every fragment).
UPDATE...
A base fragment would simply look like this:
public class BaseFragment extends Fragment {
public MyInterface mi;
#Override
public void onAttach(Context context) {
super.onAttach(context);
mi = (MyInterface) context;
}
}
Now, MyFragment would just extend BaseFragment...
public class MyFragment extends BaseFragment {
...
}
There's no need now to attach or even declare MyInterface in any fragment extending BaseFragment, the base fragment already has a public instance of it. You just set/get/etc via your interface without any additional fuss:
mi.setSomeValue(20);
I would use LocalBroadcastManager instead, it gives you the following advantages :
You know that the data you are broadcasting won't leave your app, so
don't need to worry about leaking private data.
It is not possible for other applications to send these broadcasts
to your app, so you don't need to worry about having security holes
they can exploit.
It is more efficient than sending a global broadcast through the system.
This is directly from the official docs
You may pass the data using Extras.
Intent data = new Intent("fragmentUpdater");
data.putExtra("STRING_YOU_NEED", strName);
and you can get the data inside onReceive function by :
String data_needed_here= extras.getString("STRING_YOU_NEED");

is there a way to create condition listener

is there a way to create a listener that activates an event under a certain condition(boolean)?
i tried reading about creating custom listeners using interfaces but i dont think it's the answer for my question.
right now in my app i write an if statement everywhere so if i could just create a listener for it, it would be much easier.
set_A==B_Listener(????? {//listener takes place if a==b
#Override
public boolean event(View v, MotionEvent e)
{
//do something
}
});
Create a class variable for your statement, than you can attach an OnChangeListener to your statement in the onCreate method of your Activity
public class DummyActivity extends Activity {
interface OnStateChangeListener{
public void onAttach(Activity activity);
public void onStateChange(boolean state);
}
private boolean state;
private OnStateChangeListener listener;
private YourClass stateChangedCallback;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
listener = new OnStateChangeListener() {
private Activity currentActivity;
#Override
public void onAttach(Activity activity) {
currentActivity = activity;
}
#Override
public void onStateChange(boolean state) {
if (((DummyActivity) this.currentActivity).state != state) {
stateChangedCallback.doSomething();
((DummyActivity) this.currentActivity).state = state;
}
}
};
}
private void yourFunction() {
boolean state = true;
listener.onStateChange(state);
}
}

Categories

Resources