Cannot cancel running AsyncTask in AsyncTaskLoader - android

I want to cancel running AsyncTask (in AsyncTaskLoader) when the user clicks the home button. Here is what I created so far:
package cz.davidliska.android.loaders;
import java.text.SimpleDateFormat;
import java.util.Date;
import android.content.Context;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.AsyncTaskLoader;
import android.support.v4.content.Loader;
import android.util.Log;
public class MainActivity extends FragmentActivity implements LoaderManager.LoaderCallbacks<Date> {
private static final String TAG = "loader";
private Date date;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
LoaderManager.enableDebugLogging(true);
getSupportLoaderManager().initLoader(0, savedInstanceState, this);
}
private static class DateLoader extends AsyncTaskLoader<Date> {
public static final String STATE_DATE_LOADER = "dateloader.state";
private Date mDate;
public DateLoader(Context context, Bundle savedInstanceState) {
super(context);
if (savedInstanceState != null) {
long timeStamp = savedInstanceState.getLong(STATE_DATE_LOADER);
if (timeStamp != 0L) mDate = new Date(timeStamp);
}
}
#Override
protected void onStartLoading() {
Log.d(TAG, "Loader.onStartLoading()");
if (mDate != null) {
deliverResult(mDate);
} else {
forceLoad();
}
}
#Override
public void deliverResult(Date data) {
super.deliverResult(data);
Log.d(TAG, "Loader.deliverResult()");
mDate = data;
}
#Override
protected void onStopLoading() {
super.onStopLoading();
cancelLoad(); // try to cancel AsyncTask
Log.d(TAG, "Loader.onStopLoading()");
}
#Override
protected void onForceLoad() { // overridden in AsyncTaskLoader
super.onForceLoad();
Log.d(TAG, "Loader.onForceLoad()");
}
#Override
protected void onReset() {
super.onReset();
mDate = null;
Log.d(TAG, "Loader.onForceLoad()");
}
#Override
public void onContentChanged() {
super.onContentChanged();
Log.d(TAG, "Loader.onContentChanged()");
}
#Override
protected void onAbandon() {
super.onAbandon();
Log.d(TAG, "Loader.onContentChanged()");
}
#Override
public Date loadInBackground() { // AsyncTaskLoader only
Log.d(TAG, "Loader.loadInBackground()");
try {
// there will be some HttpClient.execute()
while(true) {
Thread.sleep(100);
Log.d(TAG, "Loader.loadInBackground() still running");
}
} catch (InterruptedException e) {
Log.d(TAG, "Loader.loadInBackground() interupted");
}
Log.d(TAG, "Loader.loadInBackground() finished");
return new Date();
}
#Override
public void onCanceled(Date data) { // AsyncTaskLoader only
super.onCanceled(data);
Log.d(TAG, "Loader.onCanceled()");
}
#Override
protected Date onLoadInBackground() { // AsyncTaskLoader only
Log.d(TAG, "Loader.onContentChanged()");
return super.onLoadInBackground();
}
#Override
public void abandon() {
Log.d(TAG, "Loader.abandon()");
super.abandon();
}
#Override
public boolean cancelLoad() {
Log.d(TAG, "Loader.cancelLoad()");
return super.cancelLoad();
}
#Override
public void forceLoad() {
Log.d(TAG, "Loader.forceLoad()");
super.forceLoad();
}
#Override
public boolean isAbandoned() {
Log.d(TAG, "Loader.isAbandoned()");
return super.isAbandoned();
}
#Override
public boolean isReset() {
Log.d(TAG, "Loader.isReset()");
return super.isReset();
}
#Override
public boolean isStarted() {
Log.d(TAG, "Loader.isStarted()");
return super.isStarted();
}
#Override
public void reset() {
Log.d(TAG, "Loader.reset()");
super.reset();
}
#Override
public void stopLoading() {
Log.d(TAG, "Loader.stopLoading()");
super.stopLoading();
}
#Override
public boolean takeContentChanged() {
Log.d(TAG, "Loader.takeContentChanged()");
return super.takeContentChanged();
}
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
if (date != null)
outState.putLong(DateLoader.STATE_DATE_LOADER, date.getTime());
}
public Loader<Date> onCreateLoader(int id, Bundle args) {
Log.d(TAG, "LoaderCallback.onCreateLoader()");
if (args != null) Log.d(TAG, "bundle: " + args.getLong(DateLoader.STATE_DATE_LOADER));
return new DateLoader(this, args);
}
public void onLoadFinished(Loader<Date> loader, Date data) {
Log.d(TAG, "LoaderCallback.onLoadFinished(): " + new SimpleDateFormat("dd/MM/yyyy").format(data));
date = data;
}
public void onLoaderReset(Loader<Date> loader) {
Log.d(TAG, "LoaderCallback.onLoaderReset()");
}
}
So in onStopLoading() i am calling cancelLoad(), which i think should cancel current task, but AsyncTask in AsyncTaskLoader is still running (while loop in loadInBackground() is still in progress).
The problem is maybe in cancelLoad() method in "java.android.support.v4.content.AsyncTaskLoader.java", where mTask.cancel(boolean) is called with "false" in arguments:
public boolean cancelLoad() {
...
boolean cancelled = mTask.cancel(false);
Is there any chance to cancel running AsyncTask in AsyncTaskLoader?

If you mean "Is there any chance to cancel running AsyncTask in android.content.AsyncTaskLoader?" the answer is yes: you just need to add some "cancel points" in your loadInBackground method and check whether a cancellation request has been issued (isLoadInBackgroundCanceled() == true), then either return or throw an OperationCanceledException).
The support library version of AsyncTaskLoader you are using though doesn't seem to fully implement cancellation at this time (not in mid-flight at least, and a cursory comparison of the framework and of the support version of Loader seems to suggest that cancellation might not be supported at all...).
http://developer.android.com/reference/android/content/Loader.html
http://developer.android.com/reference/android/support/v4/content/Loader.html
Two ways to alleviate the problem come to my mind:
create two implementations of your Loader (one using the framework for API level 11 and above, and one without the cancel feature for older devices)
create an android.support.v4.content.Loader subclass and handle each AsyncTask and cancellation request yourself

public boolean cancelLoad() {
...
boolean cancelled = mTask.cancel(false);
}
#Override
public Date loadInBackground() { // AsyncTaskLoader only
Log.d(TAG, "Loader.loadInBackground()");
try {
// there will be some HttpClient.execute()
while(true) {
Thread.sleep(100);
Log.d(TAG, "Loader.loadInBackground() still running");
if(cancelled) <---------
return new Date(); <----------
}
} catch (InterruptedException e) {
Log.d(TAG, "Loader.loadInBackground() interupted");
}
Log.d(TAG, "Loader.loadInBackground() finished");
return new Date();
}

Related

Android ZoomSDK - Meeting Service Listener

I'm trying to catch onMeetingStatusChanged event. But for my case, the onMeetingStatusChanged is sometimes invoked, not all the time. Below is my implemented code:
#Override
protected void onCreate(Bundle savedInstanceState) {
registerListener();
InitAuthSDKHelper.getInstance().initSDK(this, new InitAuthSDKCallback() {
#Override
public void onZoomSDKInitializeResult(int i, int i1) {
}
#Override
public void onZoomAuthIdentityExpired() {
}
});
}
private void registerListener() {
ZoomSDK zoomSDK = ZoomSDK.getInstance();
MeetingService meetingService = zoomSDK.getMeetingService();
if (meetingService != null) {
meetingService.addListener(this);
}
}
#Override
public void onMeetingStatusChanged(MeetingStatus meetingStatus,
int errorCode,
int internalErrorCode) {
LogD.d(TAG, String.valueOf(meetingStatus));
if (meetingStatus == MeetingStatus.MEETING_STATUS_IDLE) {
layout_zoom_loading.setVisibility(View.VISIBLE);
} else {
layout_zoom_loading.setVisibility(View.GONE);
}
if(meetingStatus == MeetingStatus.MEETING_STATUS_FAILED
&& errorCode == MeetingError.MEETING_ERROR_CLIENT_INCOMPATIBLE) {
Toast.makeText(this, "Version of ZoomSDK is too low!", Toast.LENGTH_LONG).show();
}
}
public void joinMeeting(String meetingNo, String meetingPassword) {
ZoomSDK zoomSDK = ZoomSDK.getInstance();
if (!zoomSDK.isInitialized()) {
Toast.makeText(this, getString(R.string.msg_zoom_init_fail), Toast.LENGTH_LONG).show();
return;
}
JoinMeetingHelper.getInstance().joinMeetingWithNumber(this, meetingNo, meetingPassword);
}
I see the cause of this problem. We need to separate the initSDK method to BaseActivity class. So when user forward into the next Activity which runs Zoom meeting, onMeetingStatusChanged always be invoked.

Heyzap Button keep disappearing

I'm trying to make ads that give "100 coins" and the button just disappear after 0,2 - 1 second.
I've got no clue why this error could appear. Has someone got an idea how to fix that?
My error
06-03 21:42:16.017: V/PTAdHeyzapBridge(27950): PTAdHeyzapBridge -- Start Session: "MyHeyzapID"
06-03 21:42:16.023: E/Heyzap(27950): Heyzap encountered a runtime exception and is now disabled. Error: Attempt to invoke virtual method 'java.lang.String android.content.Context.getPackageName()' on a null object reference
06-03 21:42:16.023: V/PTAdHeyzapBridge(27950): PTAdHeyzapBridge -- Start Session FAILED : Attempt to invoke virtual method 'java.lang.String android.content.Context.getPackageName()' on a null object reference
06-03 21:42:16.023: V/PTAdHeyzapBridge(27950): Heyzap SDK Version : 8.4.1
My PTAdHeyzapBridge.java
package com.secrethq.ads;
import java.lang.ref.WeakReference;
import org.cocos2dx.lib.Cocos2dxActivity;
import com.google.android.gms.ads.AdView;
import com.heyzap.sdk.ads.HeyzapAds;
import com.heyzap.sdk.ads.InterstitialAd;
import com.heyzap.sdk.ads.VideoAd;
import com.heyzap.sdk.ads.IncentivizedAd;
import com.heyzap.sdk.ads.BannerAdView;
import com.heyzap.sdk.ads.HeyzapAds.BannerListener;
import com.heyzap.sdk.ads.HeyzapAds.BannerError;
import com.heyzap.sdk.ads.HeyzapAds.OnStatusListener;
import com.heyzap.sdk.ads.HeyzapAds.OnIncentiveResultListener;
import android.util.Log;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.RelativeLayout;
public class PTAdHeyzapBridge {
private static native String bannerId();
private static native String interstitialId();
private static native void interstitialDidFail();
private static native void bannerDidFail();
private static native void rewardVideoComplete();
private static final String TAG = "PTAdHeyzapBridge";
private static Cocos2dxActivity activity;
private static WeakReference<Cocos2dxActivity> s_activity;
private static BannerAdView bannerAdView;
public static void initBridge(Cocos2dxActivity activity){
Log.v(TAG, "PTAdHeyzapBridge -- INIT");
PTAdHeyzapBridge.s_activity = new WeakReference<Cocos2dxActivity>(activity);
PTAdHeyzapBridge.activity = activity;
PTAdHeyzapBridge.initBanner();
PTAdHeyzapBridge.initInterstitial();
PTAdHeyzapBridge.initVideo();
}
public static void initBanner(){
Log.v(TAG, "PTAdHeyzapBridge -- Init Banner");
PTAdHeyzapBridge.s_activity.get().runOnUiThread( new Runnable() {
public void run() {
PTAdHeyzapBridge.bannerAdView = new BannerAdView(PTAdHeyzapBridge.activity);
FrameLayout frameLayout = (FrameLayout)PTAdHeyzapBridge.activity.findViewById(android.R.id.content);
RelativeLayout layout = new RelativeLayout( PTAdHeyzapBridge.activity );
frameLayout.addView( layout );
RelativeLayout.LayoutParams adViewParams = new RelativeLayout.LayoutParams(
AdView.LayoutParams.WRAP_CONTENT,
AdView.LayoutParams.WRAP_CONTENT);
adViewParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
adViewParams.addRule(RelativeLayout.CENTER_IN_PARENT, RelativeLayout.TRUE);
layout.addView(PTAdHeyzapBridge.bannerAdView, adViewParams);
PTAdHeyzapBridge.bannerAdView.setVisibility( View.INVISIBLE );
// Add a listener.
PTAdHeyzapBridge.bannerAdView.setBannerListener(new BannerListener() {
#Override
public void onAdClicked(BannerAdView b) {
// The ad has been clicked by the user.
}
#Override
public void onAdLoaded(BannerAdView b) {
// The ad has been loaded.
}
#Override
public void onAdError(BannerAdView b, BannerError bannerError) {
// There was an error loading the ad.
Log.v(TAG, "PTAdHeyzapBridge -- Banner onAdError : " + bannerError.getErrorMessage());
bannerDidFail();
}
});
}
});
}
public static void initInterstitial(){
Log.v(TAG, "PTAdHeyzapBridge -- Init Interstitial");
InterstitialAd.setOnStatusListener(new OnStatusListener() {
#Override
public void onShow(String tag) {
// Ad is now showing
}
#Override
public void onClick(String tag) {
// Ad was clicked on. You can expect the user to leave your application temporarily.
}
#Override
public void onHide(String tag) {
// Ad was closed. The user has returned to your application.
}
#Override
public void onFailedToShow(String tag) {
// Display was called but there was no ad to show
}
#Override
public void onAvailable(String tag) {
// An ad has been successfully fetched
}
#Override
public void onFailedToFetch(String tag) {
// No ad was able to be fetched
Log.v(TAG, "PTAdHeyzapBridge -- Interstitial onFailedToFetch : " + tag);
interstitialDidFail();
}
#Override
public void onAudioFinished() {
// TODO Auto-generated method stub
}
#Override
public void onAudioStarted() {
// TODO Auto-generated method stub
}
});
}
public static void initVideo() {
IncentivizedAd.setOnIncentiveResultListener(new OnIncentiveResultListener() {
#Override
public void onComplete(String tag) {
Log.v(TAG, "PTAdHeyzapBridge -- IncentivizedAd Complete ");
// Give the player their reward
rewardVideoComplete();
}
#Override
public void onIncomplete(String tag) {
// Don't give the player their reward, and tell them why
Log.v(TAG, "PTAdHeyzapBridge -- IncentivizedAd InComplete ");
}
});
PTAdHeyzapBridge.s_activity.get().runOnUiThread( new Runnable() {
public void run() {
// As early as possible, and after showing a rewarded video, call fetch
IncentivizedAd.fetch();
}
});
}
public static void showRewardedVideo(){
Log.v(TAG, "PTAdHeyzapBridge -- showRewardedVideo");
PTAdHeyzapBridge.s_activity.get().runOnUiThread( new Runnable() {
public void run() {
if (IncentivizedAd.isAvailable()) {
IncentivizedAd.display(PTAdHeyzapBridge.activity);
}
}
});
}
public static void startSession( String sdkKey ){
if(sdkKey != null){
Log.v(TAG, "PTAdHeyzapBridge -- Start Session: " + sdkKey);
try {
HeyzapAds.start(sdkKey, PTAdHeyzapBridge.activity);
} catch (Exception e) {
// TODO: handle exception
Log.v(TAG, "PTAdHeyzapBridge -- Start Session FAILED : " + e.getMessage());
}
Log.v(TAG, "Heyzap SDK Version : " + HeyzapAds.getVersion());
}else{
Log.v(TAG, "Start Session : null ");
}
}
public static void showFullScreen(){
Log.v(TAG, "PTAdHeyzapBridge -- showFullScreen");
PTAdHeyzapBridge.s_activity.get().runOnUiThread( new Runnable() {
public void run() {
// InterstitialAds are automatically fetched from our server
InterstitialAd.display(PTAdHeyzapBridge.activity);
}
});
}
public static void showBannerAd(){
Log.v(TAG, "PTAdHeyzapBridge -- showBannerAd");
PTAdHeyzapBridge.s_activity.get().runOnUiThread( new Runnable() {
public void run() {
if(PTAdHeyzapBridge.bannerAdView != null){
PTAdHeyzapBridge.bannerAdView.setVisibility(View.VISIBLE);
// Load the banner ad.
PTAdHeyzapBridge.bannerAdView.load();
}
}
});
}
public static void hideBannerAd(){
Log.v(TAG, "PTAdHeyzapBridge -- hideBannerAd");
PTAdHeyzapBridge.s_activity.get().runOnUiThread( new Runnable() {
public void run() {
if(PTAdHeyzapBridge.bannerAdView != null){
PTAdHeyzapBridge.bannerAdView.setVisibility(View.INVISIBLE);
}
}
});
}
public static boolean isBannerVisible() {
return (PTAdHeyzapBridge.bannerAdView.getVisibility() == View.VISIBLE);
}
public static boolean isRewardedVideoAvialable(){
return IncentivizedAd.isAvailable();
}
}
My Main activity
package com.lopeostudios.runningpanda;
import org.cocos2dx.lib.Cocos2dxActivity;
import org.cocos2dx.lib.Cocos2dxGLSurfaceView;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.WindowManager;
import android.widget.Toast;
import com.secrethq.store.PTStoreBridge;
import com.google.android.gms.games.GamesActivityResultCodes;
import com.lopeostudios.runningpanda.R;
import com.secrethq.ads.*;
import com.secrethq.utils.*;
import com.onesignal.OneSignal;
public class PTPlayer extends Cocos2dxActivity {
private static native void loadModelController();
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
Log.v("----------","onActivityResult: request: " + requestCode + " result: "+ resultCode);
if(PTStoreBridge.iabHelper().handleActivityResult(requestCode, resultCode, data)){
Log.v("-----------", "handled by IABHelper");
}
else if(requestCode == PTServicesBridge.RC_SIGN_IN){
if(resultCode == RESULT_OK){
PTServicesBridge.instance().onActivityResult(requestCode, resultCode, data);
}
else if(resultCode == GamesActivityResultCodes.RESULT_SIGN_IN_FAILED){
int duration = Toast.LENGTH_SHORT;
Toast toast = Toast.makeText(this, "Google Play Services: Sign in error", duration);
toast.show();
}
else if(resultCode == GamesActivityResultCodes.RESULT_APP_MISCONFIGURED){
int duration = Toast.LENGTH_SHORT;
Toast toast = Toast.makeText(this, "Google Play Services: App misconfigured", duration);
toast.show();
}
}
}
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
OneSignal.startInit(this).init();
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
#Override
public void onNativeInit(){
initBridges();
}
private void initBridges(){
PTStoreBridge.initBridge( this );
PTServicesBridge.initBridge(this, getString( R.string.app_id ));
if (PTJniHelper.isAdNetworkActive("kChartboost")) {
PTAdChartboostBridge.initBridge(this);
}
if (PTJniHelper.isAdNetworkActive("kRevMob")) {
PTAdRevMobBridge.initBridge(this);
}
if (PTJniHelper.isAdNetworkActive("kAdMob") || PTJniHelper.isAdNetworkActive("kFacebook")) {
PTAdAdMobBridge.initBridge(this);
}
if (PTJniHelper.isAdNetworkActive("kAppLovin")) {
PTAdAppLovinBridge.initBridge(this);
}
if (PTJniHelper.isAdNetworkActive("kLeadBolt")) {
PTAdLeadBoltBridge.initBridge(this);
}
if (PTJniHelper.isAdNetworkActive("kVungle")) {
PTAdVungleBridge.initBridge(this);
}
if (PTJniHelper.isAdNetworkActive("kPlayhaven")) {
PTAdUpsightBridge.initBridge(this);
}
if (PTJniHelper.isAdNetworkActive("kMoPub")) {
PTAdMoPubBridge.initBridge(this);
}
if (PTJniHelper.isAdNetworkActive("kFacebook")) {
PTAdFacebookBridge.initBridge(this);
}
if (PTJniHelper.isAdNetworkActive("kHeyzap")) {
PTAdHeyzapBridge.initBridge(this);
}
}
#Override
public Cocos2dxGLSurfaceView onCreateView() {
Cocos2dxGLSurfaceView glSurfaceView = new Cocos2dxGLSurfaceView(this);
glSurfaceView.setEGLConfigChooser(8, 8, 8, 0, 0, 0);
return glSurfaceView;
}
static {
System.loadLibrary("player");
}
#Override
protected void onResume() {
super.onResume();
if (PTJniHelper.isAdNetworkActive("kChartboost")) {
PTAdChartboostBridge.onResume( this );
}
}
#Override
protected void onStart() {
super.onStart();
if (PTJniHelper.isAdNetworkActive("kChartboost")) {
PTAdChartboostBridge.onStart( this );
}
}
#Override
protected void onStop() {
super.onStop();
if (PTJniHelper.isAdNetworkActive("kChartboost")) {
PTAdChartboostBridge.onStop( this );
}
}
#Override
protected void onDestroy() {
super.onDestroy();
}
}
I'm an engineer at Heyzap. Our SDK will catch exceptions from third party SDKs, and shut down our SDK if we catch one (this is our last line of defense in preventing exceptions from crashing your game). In this case, we're catching this exception:
06-03 21:42:16.023: E/Heyzap(27950): Heyzap encountered a runtime exception and is now disabled. Error: Attempt to invoke virtual method 'java.lang.String android.content.Context.getPackageName()' on a null object reference
We've previously seen this exception caused by an outdated UnityAds SDK. Are you using that network, and if so, can you try UnityAds 1.5.6? If you're not, can you tell us which networks you're using, or the Android package of your game?
Also, I see in yours logs that you're using Heyzap 8.4.1, which was released in June of last year. Can you update to our latest version?

Amazon says PurchasingService.getPurchaseUpdates() not being called from libgdx project

I'm attempting to use the class PurchaseManagerAndroidAmazon to handle purchases for my libdx project. The following are within the interface to access the android methods from within the core project:
public void createPurchaseSystem();
public void getPurchaseUpdates();
public void getUserInformation();
public void purchaseItem(String id);
These are the actual methods within the AndroidApplication:
PurchaseManagerAndroidAmazon pm;
#Override
protected void onResume() {
Log.d(TAG, "onResume");
if(pm != null) {
getUserInformation();
getPurchaseUpdates();
}
super.onResume();
}
#Override
public void purchaseItem(String id) {
Log.d(TAG, "purchaseItem");
pm.purchase(id);
}
#Override
public void getUserInformation() {
Log.d(TAG, "getUserInformation");
if(pm == null)
createPurchaseSystem();
PurchasingService.getUserData();
}
#Override
public void getPurchaseUpdates() {
Log.d(TAG, "getPurchaseUpdates");
if(pm == null)
createPurchaseSystem();
PurchasingService.getPurchaseUpdates(true);
}
#Override
public void createPurchaseSystem() {
Log.d(TAG, "createPurchaseSystem");
if(pm == null)
pm = new PurchaseManagerAndroidAmazon(this, 0);
PurchaseManagerConfig config = new PurchaseManagerConfig();
config.addOffer(new Offer().setType(OfferType.CONSUMABLE).setIdentifier(getString(R.string.min_id)));
config.addOffer(new Offer().setType(OfferType.CONSUMABLE).setIdentifier(getString(R.string.med_id)));
config.addOffer(new Offer().setType(OfferType.CONSUMABLE).setIdentifier(getString(R.string.max_id)));
pm.install(new PurchaseObserver() {
#Override
public void handleInstall() {
Log.d(TAG, "PurchaseSystem installed");
PurchaseSystem.purchaseRestore();
}
#Override
public void handleInstallError(Throwable err) {
Log.e(TAG, "ERROR PurchaseObserver: handleInstallError!: " + err.getMessage());
throw new GdxRuntimeException(err);
}
#Override
public void handlePurchase(Transaction transaction) {
Log.d(TAG, "PurchaseSystem handlePurchase: " + transaction.toString());
pm.purchaseRestore();
}
#Override
public void handlePurchaseCanceled() {
Log.d(TAG, "PurchaseSystem handlePurchaseCanceled");
}
#Override
public void handlePurchaseError(Throwable err) {
Log.d(TAG, "ERROR PurchaseObserver: handlePurchaseError!: " + err.getMessage());
throw new GdxRuntimeException(err);
}
#Override
public void handleRestore(Transaction[] transactions) {
Log.d(TAG, "PurchaseSystem handleRestore: " + transactions.toString());
}
#Override
public void handleRestoreError(Throwable err) {
Log.d(TAG, "ERROR PurchaseObserver: handleRestoreError!: " + err.getMessage());
throw new GdxRuntimeException(err);
}
}, config, true);
}
And this is within the core project:
HighPoint highPoint; // this class extends Game of libgdx
public void createDonationScreen() {
if(!purchaseSytemCreated)
createPurchaseSystem();
TextButton minDonButton = new TextButton(....);
medDonButton.addListener(new ClickListener() {
#Override
public void clicked(InputEvent event, float x, float y) {
highPoint.hpaInterface.getPurchaseUpdates();
highPoint.hpaInterface.purchaseItem(MIN_ID);
}
});
Using the Amazon App Tester gives me the error
failed to call PurchasingService.getPurchaseUpdates()
but as you can tell its being called mulitple times. I feel I've put in too many times actually. The Amazon dialog pops up asking me to confirm the purchase when I click the button so it seems like it should work either way.
Any ideas would be greatly appreciated.
Adding call to PurchasingService.getPurchaseUpdates(false) in activity onResume callback solved the notification issue in my case.

getLoaderManager().initLoader(); always returns a new loader when using support.v4.fragment

I'm using android.support.v4.content.AsyncTaskLoader to load data into a support.v4.fragmentbut when the configuration changes i.e : rotate the screen getLoaderManager().initLoader(); always returns a new loader thus loadInBackground() is called again . When I tried to use a normal fragment not the support.v4 version and changed to the normal AsyncTaskLoader every thing worked as expected ,so i'm not sure if this is a bug in the support library or what?
TestAsync.class:
import android.support.v4.content.AsyncTaskLoader;
public class TestAsync extends AsyncTaskLoader<List<Movie>> {
public TestAsync(Context context) {
super(context);
}
#Override
public void deliverResult(List<Movie> data) {
if (isReset()) {
// An async query came in while the loader is stopped. We
// don't need the result.
if (data != null) {
onReleaseResources(data);
}
}
List<Movie> oldData = mData;
mData = data;
if (isStarted()) {
// If the Loader is currently started, we can immediately
// deliver its results.
super.deliverResult(data);
}
// At this point we can release the resources associated with
// 'oldApps' if needed; now that the new result is delivered we
// know that it is no longer in use.
if (oldData != null) {
onReleaseResources(oldData);
}
}
#Override
protected void onStartLoading() {
super.onStartLoading();
if (mData != null || oneShot){
deliverResult(mData);
}else {
forceLoad();
}
}
#Override
protected void onStopLoading() {
cancelLoad();
}
#Override public void onCanceled(List<Movie> data) {
super.onCanceled(data);
// At this point we can release the resources associated with 'apps'
// if needed.
onReleaseResources(data);
}
/**
* Handles a request to completely reset the Loader.
*/
#Override protected void onReset() {
super.onReset();
// Ensure the loader is stopped
onStopLoading();
// At this point we can release the resources associated with 'apps'
// if needed.
if (mData != null) {
onReleaseResources(mData);
mData = null;
}
}
protected void onReleaseResources(List<Movie> apps) {
// For a simple List<> there is nothing to do. For something
// like a Cursor, we would close it here.
}
}
BrowseMoviesActivityFragment:
public class BrowseMoviesActivityFragment extends Fragment implements LoaderManager.LoaderCallbacks<List<Movie>> {
#Override
public Loader<List<Movie>> onCreateLoader(int id, Bundle args) {
return new TestAsync(mContext);
}
#Override
public void onLoadFinished(Loader<List<Movie>> loader, List<Movie> data) {
if (data != null) {
if (adapter.isEmpty()){
adapter.add(data);
gridView.setAdapter(adapter);
}else {
adapter.add(data);
adapter.notifyDataSetChanged();
}
}
}
#Override
public void onLoaderReset(Loader<List<Movie>> loader) {
adapter = new BrowseMoviesAdapter(getActivity(),new ArrayList<Movie>());
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
mContext = activity;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
Bundle args = new Bundle();
getLoaderManager().initLoader(id, args, this);
}
}
BrowseMoviesActivity:
import android.support.v7.app.AppCompatActivity;
public class BrowseMoviesActivity extends AppCompatActivity{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_browse);
android.support.v4.app.FragmentManager fm = getSupportFragmentManager();
BrowseMoviesActivityFragment browseFragment = (BrowseMoviesActivityFragment) fm.findFragmentByTag(TAG_BROWSE_FRAGMENT);
if (savedInstanceState == null){
if (browseFragment==null){
browseFragment = new BrowseMoviesActivityFragment();
fm.beginTransaction().replace(R.id.browse_container, browseFragment).commit();
}
}

Asynctaskloader restart loading when the activity restart

Hi I'm implementing a custom asynctaskloader to load data in the background. The problem is when the user goes back to the activity after he minimizes the app(or pick photo from gallary), all the asynctaskloaders associated with the activity and asynctaskloaders associated with the fragments in the activity start all over again.
How can I prevent the loader to restart the loading process when the activity restarts?
My baseAsynctaskLoader class:
import android.content.Context;
import android.support.v4.content.AsyncTaskLoader;
import android.util.Log;
public abstract class BaseAsyncTaskLoader extends AsyncTaskLoader{
private static final String TAG = "BaseAsyncTaskLoader";
protected Context context;
protected Object mData;
public BaseAsyncTaskLoader( Context context ) {
super(context);
Log.d(TAG, "BaseLoader");
this.context = context.getApplicationContext();
}
#Override
public abstract Object loadInBackground();
#Override
public void deliverResult(Object data){
Log.d( TAG, "deliverResult" );
if (isReset()) {
return;
}
mData = data;
if (isStarted()) {
super.deliverResult(data);
}
}
#Override
protected void onStartLoading(){
Log.d( TAG, "onStartLoading" );
if (mData != null) {
deliverResult(mData);
}
if (takeContentChanged() || mData == null) {
forceLoad();
}
}
#Override
protected void onStopLoading(){
Log.d( TAG, "onStopLoading" );
cancelLoad();
}
#Override
protected void onReset(){
Log.d( TAG, "onReset" );
super.onReset();
onStopLoading();
if(mData !=null){
mData=null;
}
}
#Override
public void onCanceled(Object data){
Log.d( TAG, "onCanceled" );
super.onCanceled(data);
}
}
Loader class sample:
public class AddDetailService extends BaseAsyncTaskLoader{
Activity activity;
Bundle bundle;
String outputstringrespone="";
public AddCarService(Activity activity, Bundle bundle){
super(activity);
this.activity = activity;
this.bundle = bundle;
}
#Override
public Object loadInBackground(){
try{
int userId = bundle.getInt(USER_ID);
int modelId = bundle.getInt(MODEL_ID);
outputstringrespone = addDetails(userId, modelId);
}catch(Exception e){
Log.d(TAG, e.toString());
}
return null;
}
#Override
public void deliverResult(Object data){
super.deliverResult(data);
Log.d(TAG,"output--"+outputstringrespone);
if(outputstringrespone.equalsIgnoreCase("Success")){
Toast.makeText(activity, "Details Added Successfully", Toast.LENGTH_SHORT).show();
}else {
Toast.makeText(activity, "Details not added",Toast.LENGTH_SHORT).show();
}
}
}
LoaderCallback in activity:
getLoaderManager().initLoader(LoaderId.ADD_DETAIL, bundle, addDetailsCallbacks);
LoaderManager.LoaderCallbacks addDetailsCallbacks = new LoaderManager.LoaderCallbacks(){
#Override
public Loader onCreateLoader(int id, Bundle args){
return new AddDetailService(getActivity(), args);
}
#Override
public void onLoadFinished(Loader loader, Object data){
getLoaderManager().destroyLoader(LoaderId.ADD_DETAIL);
}
#Override
public void onLoaderReset(Loader loader){
}
};
This is the desired behavior of LoaderManager framework - it takes care of reloading the data with the initiated Loaders in case the enclosing Activity or Fragment get re-created.
In fact, some implementations of Loaders do not reload the data, but simply provide access to the latest data that has been cached internally.
Bottom line: you observe correct behavior of LoaderManager framework.
It is not clear what it is you're trying to accomplish with your Loader, but it looks like you chose an incorrect tool. If your goal is to perform the action just once, then you should use AsyncTask instead of Loaders.

Categories

Resources