I am trying to put in app billing in my android app. I am currently stuck on how to call back to my MainActivity to perform a UI change from the helper billing class once it is found the user has previously bought something.
I have searched and searched but I cannot find what I'm looking for, I'm sure I need to implement a callback or a listener or both?
My code is the following:
MainActivity
public class MainActivity extends AppCompatActivity
implements NavigationView.OnNavigationItemSelectedListener {
MyBilling bill;
private Menu nav_Menu;
#Override
protected void onCreate(Bundle savedInstanceState) {
bill = new MyBilling(this);
bill.onCreate();
}
private void displaySelectedScreen(int itemId) {
///calls fragment and inflates
}
public void UpdateUI(){
//Make some changes to UI
nav_Menu.findItem(R.id.remove_ad_button).setVisible(false);
//Recall fragment
displaySelectedScreen(R.id.distance_check);
}
}
Billing helper class (Google In App Billing)
public class MyBilling {
Activity activity;
public MyBilling(Activity launcher) {
this.activity = launcher;
}
IabHelper.QueryInventoryFinishedListener mGotInventoryListener = new IabHelper.QueryInventoryFinishedListener() {
public void onQueryInventoryFinished(IabResult result,
Inventory inventory) {
Log.d(TAG, "Query inventory finished.");
// Have we been disposed of in the meantime? If so, quit.
if (mHelper == null)
return;
// Is it a failure?
if (result.isFailure()) {
// complain("Failed to query inventory: " + result);
return;
}
Log.d(TAG, "Query inventory was successful.");
/*
* Check for items we own. Notice that for each purchase, we check
* the developer payload to see if it's correct! See
* verifyDeveloperPayload().
*/
// Do we have the premium upgrade?
Purchase removeAdsPurchase = inventory.getPurchase(SKU_REMOVE_ADS);
AdCheck = (removeAdsPurchase != null && verifyDeveloperPayload(removeAdsPurchase));
//Yes there has been purchases!
if(AdCheck == true){
removeAds(); // sets global flag
//// Want to call UI change here....
MainActivity main = new MainActivity();
main.UpdateUI();
}
}
};
}
What I understand from debugging is IabHelper.QueryInventoryFinishedListener is called during oncreate of billing class, it is asynchronous, so my main activity continues to compile. When setup and reading of purchases are complete I need to go back to my MainActivity and make changes.
If anyone can point me in the right direction here please - I've tried to keep the code straight forward by just provided the needed snippets.
Use an Interface. Add the UpdateUI() method declaration in the Interface. Then create instance of the Interface in the MyBilling class and initialise using constructor. Call the UPdateUI() method throught the the instance of the Interface. Then implement the Interface in your MainActivity. If you are unclear about implementing, I'd be happy to post the code.
The code :
In your MyBilling class, add the following inside the class
public interface Update {
void UpdateUI();
}
Use this to call the UpdateUI() method from the MyBilling class.
myActivity.UpdateUI();
Use this as the constructor in MyBilling class
Update myActivity;
public MyBilling (Update activity) {
myActivity = activity;
}
Now change to the following in the MainActivity
public class MainActivity extends AppCompatActivity
implements NavigationView.OnNavigationItemSelectedListener, MyBilling.Update
If a red line appear beneath it, Alt+enter it to implement the Update interface in MainActivity. I'm guessing since you already has UpdateUI() in your MainActivity, there wont be a red line error. Hope it helps!
Related
PlaylistFragment starts an adapter:
playlistsAdapter = new PlaylistRecyclerAdapter(playlistsListArray, addToPlaylist, mSong, getActivity(), this);
PlaylistRecyclerAdapter binds data to the PlaylistViewHolder, something like this:
((PlaylistViewHolder) viewHolder).bind(this, dataSet.get(position), addToPlaylist, mSong);
User clicks on an item in PlaylistViewHolder:
context.startActivity(PublicPlaylistActivity.createStartIntent(context, playlist));
Now here is the question, how can PublicPlaylistActivity talk back to the initial PlaylistFragment?
I suggest you'd better use Interface from fragment to adapter. So when user clicks anything in adapter, call function realization in fragment. If you need your activity to proceed some operation - ((YourActivity) getActivity()).someMethod() should be called from fragment.
Second trick is using broadcastreceiver to send events. A bit more complicated. You have to launch broadcast in view you need to recive message and send these messages from adapter. This approach is more complexible to debug and support if system is wide spread, so you'd better use interfaces.
There are several ways of doing that. The simplest way should be starting the PublicPlaylistActivity with startActivityForResult. In that way, then the activity finishes, you can set send some data to the caller fragment (which is PlaylistFragment in your case). Here is a nice tutorial about the implementation.
Another way of doing that is by using lifecycle methods. You might have a public static variable which can keep track of some status that you might observe in your onResume function of your PlaylistFragment when you are returning back from your PublicPlaylistActivity. You might consider a sample implementation as follows.
Define a public static variable in your PlaylistFragment. Then in your onResume function check the value of that variable and take actions accordingly.
public static boolean someIndicator = false; // Initialize with a default value
#Override
protected void onResume() {
super.onResume();
if(someIndicator == true) doSomething();
else doSomethingElse();
}
Now you can set the indicator variable from anywhere in your application actually which will have the effect on your PlaylistFragment. For example, from your PublicPlaylistActivity, you might consider doing something like this.
public void someFunctionInYourPublicPlaylistActivity() {
// ...
// Some code and then the following
PlaylistFragment.someIndicator = true;
}
Another way of achieving the same thing is by using a BroadcastReceiver. Here is a tutorial on how you can implement one.
It really depends on how you are structuring your whole activity-fragments communication. Hope that helps!
I would do a common "context" class (ComContext) with an interface. When you create your fragment, you also create this class. And from the activity you can check if it exists or not.
I assume that you already have a helper(AppHelper) class with static variables.
public class AppHelper {
public static ComContext comContext = null;
}
public class MainFragment {
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
ConContext comContext = new ComContext();
comContext.listener = this;
AppHelper.comContext = comContext;
}
#Override
public void onDataChanged() {
}
#Override
public void onDestroyView() {
super.onDestroyView();
AppHelper.comContext = null;
}
}
public class MainActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (AppHelper.comContext != null) {
AppHelper.comContext.listener.onDataChanged();
}
}
}
public class ComContext {
public interface HelperListener {
void onDataChanged();
}
public HelperListener listener = null;
}
I have a database that provides an array of Strings, accessed from within a Fragment. I want these Strings to go back to the activity attached to the Fragment and set the titles of the tabs in a ViewPager. How can I do this?
This is how I want to do it:
Database String[] → Fragment → Attached activity's ViewPager → New
tabs
Edit: Here is my entire Activity and PagerAdapter code.
Here is my Fragment code
Suppose you have array of Strings and you want to send them to your activity from Fragment, make an interface like
public class MyFragment extends Fragment {
CustomStrings mCallback;
// Container Activity must implement this interface
public interface CustomStrings {
public void onStringRecieved(String[] stringss);
}
#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 = (CustomStrings) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement OnHeadlineSelectedListener");
}
}
And then simple use this when you need to send data
mCallback.onStringRecieved(yourStrings); //your data here
And then in your activity implement it
public class MainActivity extends Activity
implements MyFragment.CustomStrings{
...
public void onStringRecieved(String[] stringss) {
// Do something here to use these strings
Toast.makeText(getContext(), ""+strings, Toast.LENGTH_SHORT).show();
}
Hope this solves your problem, for more information refer this
I have a scenario where I'd like to open a dialogfragment from a button click in an already open dialog fragment. I'd like the original to either stay open and the new one open on top of it or hide the original and then reopen it when the second dialogfragment is dismissed. Just wondering if this is feasible before I go about trying to do it and possibly waste my time. Can anyone advise?
Following on from the comments above I have found that the following appears to work (Compiles and runs on a test handset although no logic is yet implemented). I replaced the onAttach method above with the following code.
#Override
public void onAttach(Context context) {
super.onAttach(context);
TextPropertiesDialogFragment prev = (TextPropertiesDialogFragment) getFragmentManager().findFragmentByTag("TextPropertiesDialogFragment");
if (prev != null) {
if (prev instanceof OnColourPickerFragmentInteractionListener) {
mListener = (OnColourPickerFragmentInteractionListener) prev;
} else {
throw new RuntimeException(prev.toString()
+ " must implement OnFragmentInteractionListener");
}
}
}
For reference this onAttach method is in the second dialog fragment called OnColourPickerDialogFragment. The TextPropertiesDialogFragment is the first dialogfragment that is called from the activity. For completeness I've included the definition of the listener and interface below.
public class TextPropertiesDialogFragment extends DialogFragment implements View.OnClickListener, ColourPickerDialogFragment.OnColourPickerFragmentInteractionListener{
public void colourPickerCallBackMethod(Bundle bundle){
//Do some work here
}
//........
}
public class ColourPickerDialogFragment extends DialogFragment implements View.OnClickListener {
private View topLevelFragmentView;
private OnColourPickerFragmentInteractionListener mListener;
private Bundle callBackBundle;
public interface OnColourPickerFragmentInteractionListener{
void colourPickerCallBackMethod(Bundle callBackBundle);
}
//......
}
I have a BaseActivity that gets extended by every other activity. The thing is, I have the music muted whenever the user leaves (onPause) the activity. I also stop listening for telephone calls. The problem is, onPause is getting called whenever the user switches between activities, meaning the app is unnecessarily muting and stopping telephonymanager, even though it should only be muting and stopping telephonymanager if the user were to leave the app.:
#Override
protected void onPause() {
Log.v(TAG, "IN onPause!");
// unregister phone listener to telephony manager
tManager.listen(phoneStateListener, PhoneStateListener.LISTEN_NONE);
mute();
super.onPause();
}
Now say I switch between public class myClass extends BaseActivity and switch to public class myOtherClass extends BaseActivity. This switch is unnecessarily executing onPause, even though I only want onPause to be called when the user leaves the app. What should I do?
Thanks for the expert advice,
Rich
From my understanding you are muting your music playing in onPause of BaseActivity, instead of that write it inside your Music play activity
Ex :
public class BaseActivity extends AppCompatActivity{
#Override
public void onPause(){
//do things that common for all activities
}
}
public void MusicPlayActivity extends AppCompatActivity{
#Override
public void onPause(){
music.mute()
}
}
This will work
UPDATE
There are few ways to detect whether your application is running in the background, but only one of them is completely reliable:
Track visibility of your application by yourself using Activity.onPause, Activity.onResume methods. Store "visibility" status in some other class.
Example
: Implement custom Application class (note the isActivityVisible() static method):
public class MyApplication extends Application {
public static boolean isActivityVisible() {
return activityVisible;
}
public static void activityResumed() {
activityVisible = true;
}
public static void activityPaused() {
activityVisible = false;
}
private static boolean activityVisible;
}
Register your application class in AndroidManifest.xml:
<application
android:name="your.app.package.MyApplication"
android:icon="#drawable/icon"
android:label="#string/app_name" >
Add onPause and onResume to every Activity in the project (you may create a common ancestor for your Activities if you'd like to, but if your activity is already extended from MapActivity/ListActivity etc. you still need to write the following by hand):
#Override
protected void onResume() {
super.onResume();
MyApplication.activityResumed();
}
#Override
protected void onPause() {
super.onPause();
MyApplication.activityPaused();
}
ActivityLifecycleCallbacks were added in API level 14 (Android 4.0). You can use them to track whether an activity of your application is currently visible to the user. Check Cornstalks' answer below for the details.
From your comments you only want to stop the music when the last Activity of your application is exiting. Overriding the finish() method of your BaseActivity like this should accomplish what you want:
#Override
public void finish() {
super.finish();
if (isTaskRoot()) {
// This is the last Activity in the stack so mute your music here...
}
}
Actually you probably want onDestroy() or onStop() as I'm not sure finish() executes unless you call it but the idea is the same:
#Override
protected void onDestroy() {
super.onDestroy();
if (isTaskRoot()) {
// This is the last Activity in the stack so mute your music here...
}
}
Here's info on isTaskRoot():
Return whether this activity is the root of a task. The root is the first activity in a task.
Returns
True if this is the root activity, else false.
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