I'm trying to implement Admob App Open Ads and did exactly what it says on Admob page. But ad doesn't open on app launch but it opens on if app minimized to background and bring back to foreground. I think this is the default Google implementation of app open ads. But I want to make app appear on app launch. Can you help me?
There is 2 classes that makes app open ads work. MyApplication and AppOpenManager classes.
public class MyApplication extends Application {
private static AppOpenManager appOpenManager;
#Override
public void onCreate() {
super.onCreate();
MobileAds.initialize(
this,
initializationStatus -> {});
appOpenManager = new AppOpenManager(this);
}
}
and
/**
* Prefetches App Open Ads.
*/
public class AppOpenManager implements LifecycleObserver,Application.ActivityLifecycleCallbacks {
private static final String LOG_TAG = "AppOpenManager";
private static final String AD_UNIT_ID = "ca-app-pub-7500195269906423/9767523313";
private AppOpenAd appOpenAd = null;
private Activity currentActivity;
private AppOpenAd.AppOpenAdLoadCallback loadCallback;
private final MyApplication myApplication;
private static boolean isShowingAd = false;
/**
* Constructor
*/
public AppOpenManager(MyApplication myApplication) {
this.myApplication = myApplication;
this.myApplication.registerActivityLifecycleCallbacks(this);
ProcessLifecycleOwner.get().getLifecycle().addObserver(this);
}
/** LifecycleObserver methods */
#OnLifecycleEvent(ON_START)
public void onStart() {
showAdIfAvailable();
Log.d(LOG_TAG, "onStart");
}
/** Shows the ad if one isn't already showing. */
public void showAdIfAvailable() {
// Only show ad if there is not already an app open ad currently showing
// and an ad is available.
if (!isShowingAd && isAdAvailable()) {
Log.d(LOG_TAG, "Will show ad.");
FullScreenContentCallback fullScreenContentCallback =
new FullScreenContentCallback() {
#Override
public void onAdDismissedFullScreenContent() {
// Set the reference to null so isAdAvailable() returns false.
AppOpenManager.this.appOpenAd = null;
isShowingAd = false;
fetchAd();
}
#Override
public void onAdFailedToShowFullScreenContent(AdError adError) {}
#Override
public void onAdShowedFullScreenContent() {
isShowingAd = true;
}
};
appOpenAd.setFullScreenContentCallback(fullScreenContentCallback);
appOpenAd.show(currentActivity);
} else {
Log.d(LOG_TAG, "Can not show ad.");
fetchAd();
}
}
/**
* Request an ad
*/
public void fetchAd() {
// Have unused ad, no need to fetch another.
if (isAdAvailable()) {
return;
}
loadCallback =
new AppOpenAd.AppOpenAdLoadCallback() {
/**
* Called when an app open ad has loaded.
*
* #param ad the loaded app open ad.
*/
#Override
public void onAdLoaded(AppOpenAd ad) {
AppOpenManager.this.appOpenAd = ad;
}
/**
* Called when an app open ad has failed to load.
*
* #param loadAdError the error.
*/
#Override
public void onAdFailedToLoad(LoadAdError loadAdError) {
// Handle the error.
}
};
AdRequest request = getAdRequest();
AppOpenAd.load(
myApplication, AD_UNIT_ID, request,
AppOpenAd.APP_OPEN_AD_ORIENTATION_PORTRAIT, loadCallback);
}
/**
* Creates and returns ad request.
*/
private AdRequest getAdRequest() {
return new AdRequest.Builder().build();
}
/**
* Utility method that checks if ad exists and can be shown.
*/
public boolean isAdAvailable() {
return appOpenAd != null;
}
/** ActivityLifecycleCallback methods */
#Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
currentActivity = activity;
}
#Override
public void onActivityStarted(Activity activity) {
currentActivity = activity;
}
#Override
public void onActivityResumed(Activity activity) {
currentActivity = activity;
}
#Override
public void onActivityStopped(Activity activity) {}
#Override
public void onActivityPaused(Activity activity) {}
#Override
public void onActivitySaveInstanceState(Activity activity, Bundle bundle) {}
#Override
public void onActivityDestroyed(Activity activity) {
currentActivity = null;
}
}
Add this code to your AppOpenManager
import android.app.Activity
import androidx.lifecycle.Lifecycle.Event.ON_START
import android.app.Application
import android.os.Bundle
import android.content.Context
import android.util.Log
import androidx.lifecycle.LifecycleObserver
import androidx.lifecycle.OnLifecycleEvent
import androidx.lifecycle.ProcessLifecycleOwner
import com.google.android.gms.ads.AdError
import com.google.android.gms.ads.AdRequest
import com.google.android.gms.ads.FullScreenContentCallback
import com.google.android.gms.ads.LoadAdError
import com.google.android.gms.ads.appopen.AppOpenAd
import java.util.*
class AppOpenManager (private var myApplication: MyApplication) : LifecycleObserver,Application.ActivityLifecycleCallbacks {
companion object {
private const val LOG_TAG = "AppOpenManager"
private const val AD_UNIT_ID = "ca-app-pub-3940256099942544/3419835294"
}
private var appOpenAd: AppOpenAd? = null
private lateinit var loadCallback: AppOpenAd.AppOpenAdLoadCallback
private var currentActivity : Activity? = null
private var isShowingAd : Boolean = false
private var loadTime:Long = 0
private var temp = 0
init{
this.myApplication.registerActivityLifecycleCallbacks(this)
ProcessLifecycleOwner.get().lifecycle.addObserver(this)
}
#OnLifecycleEvent(ON_START)
fun onStart() {
showAdIfAvailable()
Log.d(LOG_TAG, "onStart")
}
fun showAdIfAvailable() {
// Only show ad if there is not already an app open ad currently showing
// and an ad is available.
if (!isShowingAd && isAdAvailable())
{
Log.d(LOG_TAG, "Will show ad.")
val fullScreenContentCallback = object: FullScreenContentCallback() {
override fun onAdDismissedFullScreenContent() {
// Set the reference to null so isAdAvailable() returns false.
this#AppOpenManager.appOpenAd = null
isShowingAd = false
fetchAd()
}
override fun onAdFailedToShowFullScreenContent(adError: AdError) {}
override fun onAdShowedFullScreenContent() {
isShowingAd = true
}
}
appOpenAd?.show(currentActivity, fullScreenContentCallback)
}
else
{
Log.d(LOG_TAG, "Can not show ad.")
fetchAd()
}
}
/** Request an ad */
fun fetchAd() {
// We will implement this below.
if (isAdAvailable()) {
return
}
loadCallback = object:AppOpenAd.AppOpenAdLoadCallback() {
/**
* Called when an app open ad has loaded.
*
* #param ad the loaded app open ad.
*/
override fun onAppOpenAdLoaded(ad:AppOpenAd) {
this#AppOpenManager.appOpenAd = ad
this#AppOpenManager.loadTime = (Date()).getTime()
val fullScreenContentCallback = object: FullScreenContentCallback() {
override fun onAdDismissedFullScreenContent() {
// Set the reference to null so isAdAvailable() returns false.
this#AppOpenManager.appOpenAd = null
isShowingAd = false
fetchAd()
}
override fun onAdFailedToShowFullScreenContent(adError: AdError) {}
override fun onAdShowedFullScreenContent() {
isShowingAd = true
}
}
if(temp==0)
{
appOpenAd?.show(currentActivity, fullScreenContentCallback)
temp=1
}
}
/**
* Called when an app open ad has failed to load.
*
* #param loadAdError the error.
*/
override fun onAppOpenAdFailedToLoad(loadAdError: LoadAdError) {
// Handle the error.
}
}
val request : AdRequest = getAdRequest()
AppOpenAd.load(
myApplication, AD_UNIT_ID, request,
AppOpenAd.APP_OPEN_AD_ORIENTATION_PORTRAIT, loadCallback)
}
/** Creates and returns ad request. */
private fun getAdRequest():AdRequest {
return AdRequest.Builder().build()
}
/** Utility method that checks if ad exists and can be shown. */
fun isAdAvailable():Boolean {
return appOpenAd != null && wasLoadTimeLessThanNHoursAgo(4)
}
/** Utility method to check if ad was loaded more than n hours ago. */
private fun wasLoadTimeLessThanNHoursAgo(numHours:Long):Boolean {
val dateDifference = (Date()).time - this.loadTime
val numMilliSecondsPerHour:Long = 3600000
return (dateDifference < (numMilliSecondsPerHour * numHours))
}
override fun onActivityPaused(activity: Activity) {
}
override fun onActivityStarted(activity: Activity) {
currentActivity = activity
}
override fun onActivityDestroyed(activity: Activity) {
currentActivity = null
}
override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {
}
override fun onActivityStopped(activity: Activity) {
}
override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
}
override fun onActivityResumed(activity: Activity) {
currentActivity = activity
}
}
Related
I want to call method on App Start on Enter Foreground (when Activity created). But
appOpenAdManager.showAdAndWaitUntilLoaded(currentActivity);
doesnt execute method. Why?
Expected Logs:
LogAdMaster: AdMaster_autoInit: true
LogAdMaster: AdMaster_autoAppOpenAd: true
LogAdMaster: AdMaster_isAppOpenShowed: false
LogAdMaster: ACTIVITY: NOT NULL
LogAdMaster: appOpenAdManager: NOT NULL
LogAdMaster: INSIDE METHOD
LogAdMaster: Show App Open Ad attempt:
...
But I get only:
LogAdMaster: AdMaster_autoInit: true
LogAdMaster: AdMaster_autoAppOpenAd: true
LogAdMaster: AdMaster_isAppOpenShowed: false
LogAdMaster: ACTIVITY: NOT NULL
LogAdMaster: appOpenAdManager: NOT NULL
...
package com.epicgames.ue4;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.Map;
import java.util.Properties;
import android.app.Activity;
import android.app.Application;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.os.Build;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleObserver;
import androidx.lifecycle.OnLifecycleEvent;
import androidx.lifecycle.ProcessLifecycleOwner;
import com.YourCompany.AdMobPlugin.R;
import com.google.android.gms.ads.AdError;
import com.google.android.gms.ads.AdRequest;
import com.google.android.gms.ads.FullScreenContentCallback;
import com.google.android.gms.ads.LoadAdError;
import com.google.android.gms.ads.MobileAds;
import com.google.android.gms.ads.appopen.AppOpenAd;
import com.google.android.gms.ads.initialization.AdapterStatus;
import com.epicgames.ue4.network.NetworkChangedManager;
public class GameApplication extends Application implements LifecycleObserver, Application.ActivityLifecycleCallbacks {
private static final Logger Log = new Logger("UE4", "GameApp");
private static final String LOG_TAG = "LogAdMaster";
private static boolean isForeground = false;
private AppOpenAdManager appOpenAdManager;
private Activity currentActivity;
private boolean AdMaster_autoInit = true;
private boolean AdMaster_autoAppOpenAd = false;
private String AdMaster_appOpenAdId = "ca-app-pub-3940256099942544/3419835294";
private boolean AdMaster_isAppOpenShowed = false;
public Context getContext() { return (Context)this; }
public void AndroidThunk_AdMaster_initialize() {
MobileAds.initialize(this, initializationStatus -> {
Map<String, AdapterStatus> statusMap = initializationStatus.getAdapterStatusMap();
for (String adapterClass : statusMap.keySet()) {
AdapterStatus status = statusMap.get(adapterClass);
android.util.Log.d(LOG_TAG, String.format(
"Adapter name: %s, Description: %s, Latency: %d",
adapterClass, status.getDescription(), status.getLatency()));
}
});
}
/** Show the ad if one isn't already showing. */
public void AndroidThunk_AdMaster_showAppOpenAdIfAvailable() {
// We wrap the showAdIfAvailable to enforce that other classes only interact with MyApplication
// class.
appOpenAdManager.showAdIfAvailable(currentActivity);
}
private void loadProperties() {
android.util.Log.d(LOG_TAG, "LOADING");
Resources resources = getContext().getResources();
try {
InputStream rawResource = resources.openRawResource(R.raw.config);
Properties properties = new Properties();
properties.load(rawResource);
String autoInit = properties.getProperty("admaster.auto_init");
String autoAppOpenAd = properties.getProperty("admaster.auto_app_open_ad");
String appOpenAdId = properties.getProperty("admaster.app_open_ad_id");
if (autoInit != null) {
AdMaster_autoInit = Boolean.parseBoolean(autoInit);
}
if (autoAppOpenAd != null) {
AdMaster_autoAppOpenAd = Boolean.parseBoolean(autoAppOpenAd);
}
if (appOpenAdId != null) {
AdMaster_appOpenAdId = appOpenAdId;
}
} catch (Resources.NotFoundException e) {
android.util.Log.e(LOG_TAG, "Unable to find the config file: " + e.getMessage());
} catch (IOException e) {
android.util.Log.e(LOG_TAG, "Failed to open config file.");
}
}
#Override
public void onCreate() {
super.onCreate();
loadProperties();
this.registerActivityLifecycleCallbacks(this);
if (AdMaster_autoInit) {
AndroidThunk_AdMaster_initialize();
}
ProcessLifecycleOwner.get().getLifecycle().addObserver(this);
appOpenAdManager = new AppOpenAdManager(AdMaster_appOpenAdId);
NetworkChangedManager.getInstance().initNetworkCallback(this);
}
#Override
public void attachBaseContext(Context base) {
super.attachBaseContext(base);
}
#Override
public void onLowMemory() {
super.onLowMemory();
}
#Override
public void onTrimMemory(int level) {
super.onTrimMemory(level);
}
#Override
public void onConfigurationChanged (Configuration newConfig) {
super.onConfigurationChanged(newConfig);
}
#OnLifecycleEvent(Lifecycle.Event.ON_START)
void onEnterForeground() {
Log.verbose("App in foreground");
isForeground = true;
android.util.Log.d(LOG_TAG, "AdMaster_autoInit: " + AdMaster_autoInit + "\r\nAdMaster_autoAppOpenAd: " + AdMaster_autoAppOpenAd + "\r\nAdMaster_isAppOpenShowed: " + AdMaster_isAppOpenShowed);
if (AdMaster_autoInit && AdMaster_autoAppOpenAd && !AdMaster_isAppOpenShowed) {
android.util.Log.d(LOG_TAG, "ACTIVITY: " + (currentActivity != null ? "NOT NULL" : "NULL"));
android.util.Log.d(LOG_TAG, "appOpenAdManager: " + (currentActivity != null ? "NOT NULL" : "NULL"));
// Show the ad (if available) when the app moves to foreground.
appOpenAdManager.showAdAndWaitUntilLoaded(currentActivity);
}
}
#OnLifecycleEvent(Lifecycle.Event.ON_STOP)
void onEnterBackground() {
Log.verbose("App in background");
isForeground = false;
}
#SuppressWarnings("unused")
public static boolean isAppInForeground() {
return isForeground;
}
public static boolean isAppInBackground() {
return !isForeground;
}
/** ActivityLifecycleCallback methods. */
#Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {}
#Override
public void onActivityStarted(Activity activity) {
// Updating the currentActivity only when an ad is not showing.
if (!appOpenAdManager.isShowingAd) {
currentActivity = activity;
}
}
#Override
public void onActivityResumed(Activity activity) {}
#Override
public void onActivityStopped(Activity activity) {}
#Override
public void onActivityPaused(Activity activity) {}
#Override
public void onActivitySaveInstanceState(Activity activity, Bundle bundle) {}
#Override
public void onActivityDestroyed(Activity activity) {}
/** Interface definition for a callback to be invoked when an app open ad is complete. */
public interface OnShowAdCompleteListener {
void onShowAdComplete();
}
private class AppOpenAdManager {
private static final String LOG_TAG = "AppOpenAdManager";
private String AD_UNIT_ID = "ca-app-pub-3940256099942544/3419835294";
private AppOpenAd appOpenAd = null;
private boolean isLoadingAd = false;
private boolean isShowingAd = false;
/** Keep track of the time an app open ad is loaded to ensure you don't show an expired ad. */
private long loadTime = 0;
/** Constructor. */
public AppOpenAdManager(String adUnitAd) { AD_UNIT_ID = adUnitAd; }
/** Request an ad. */
private void loadAd(Context context) {
// Do not load ad if there is an unused ad or one is already loading.
if (isLoadingAd || isAdAvailable()) {
return;
}
isLoadingAd = true;
AdRequest request = new AdRequest.Builder().build();
AppOpenAd.load(
context, AD_UNIT_ID, request,
AppOpenAd.APP_OPEN_AD_ORIENTATION_PORTRAIT,
new AppOpenAd.AppOpenAdLoadCallback() {
#Override
public void onAdLoaded(AppOpenAd ad) {
// Called when an app open ad has loaded.
android.util.Log.d(LOG_TAG, "Open App Ad was loaded.");
appOpenAd = ad;
isLoadingAd = false;
loadTime = (new Date()).getTime();
}
#Override
public void onAdFailedToLoad(LoadAdError loadAdError) {
// Called when an app open ad has failed to load.
android.util.Log.d(LOG_TAG, loadAdError.getMessage());
isLoadingAd = false;
}
});
}
/** Utility method to check if ad was loaded more than n hours ago. */
private boolean wasLoadTimeLessThanNHoursAgo(long numHours) {
long dateDifference = (new Date()).getTime() - this.loadTime;
long numMilliSecondsPerHour = 3600000;
return (dateDifference < (numMilliSecondsPerHour * numHours));
}
/** Check if ad exists and can be shown. */
private boolean isAdAvailable() {
return appOpenAd != null && wasLoadTimeLessThanNHoursAgo(4);
}
public void showAdAndWaitUntilLoaded(#NonNull final Activity activity) {
android.util.Log.d(LOG_TAG, "INSIDE METHOD");
int attempts = 5;
while (!isShowingAd && attempts != 0) {
android.util.Log.d(LOG_TAG, "Show App Open Ad attempt: " + attempts);
showAdIfAvailable(activity);
attempts--;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
AdMaster_isAppOpenShowed = true;
}
/** Shows the ad if one isn't already showing. */
private void showAdIfAvailable(#NonNull final Activity activity) {
showAdIfAvailable(
activity,
() -> {
// Empty because the user will go back to the activity that shows the ad.
});
}
public void showAdIfAvailable(
#NonNull final Activity activity,
#NonNull OnShowAdCompleteListener onShowAdCompleteListener) {
// If the app open ad is already showing, do not show the ad again.
if (isShowingAd) {
android.util.Log.d(LOG_TAG, "The app open ad is already showing.");
return;
}
// If the app open ad is not available yet, invoke the callback then load the ad.
if (!isAdAvailable()) {
android.util.Log.d(LOG_TAG, "The app open ad is not ready yet.");
onShowAdCompleteListener.onShowAdComplete();
loadAd(activity);
return;
}
appOpenAd.setFullScreenContentCallback(
new FullScreenContentCallback() {
#Override
public void onAdDismissedFullScreenContent() {
// Called when fullscreen content is dismissed.
// Set the reference to null so isAdAvailable() returns false.
android.util.Log.d(LOG_TAG, "Ad dismissed fullscreen content.");
appOpenAd = null;
isShowingAd = false;
onShowAdCompleteListener.onShowAdComplete();
loadAd(activity);
}
#Override
public void onAdFailedToShowFullScreenContent(AdError adError) {
// Called when fullscreen content failed to show.
// Set the reference to null so isAdAvailable() returns false.
android.util.Log.d(LOG_TAG, adError.getMessage());
appOpenAd = null;
isShowingAd = false;
onShowAdCompleteListener.onShowAdComplete();
loadAd(activity);
}
#Override
public void onAdShowedFullScreenContent() {
// Called when fullscreen content is shown.
android.util.Log.d(LOG_TAG, "Ad showed fullscreen content.");
}
});
isShowingAd = true;
appOpenAd.show(activity);
}
}
}
I am using Obtaining Consent with the User Messaging Platform in my application: https://developers.google.com/admob/ump/android/quick-start
The consent form is not shown on the screen at the start of the activity.
The logs show the triggering of the method after onResume, but the form does not appear on the eran. What's wrong with my code?
In run, I found the lines:
UserMessagingPlatform: No available form can be built.
D / UserMessagingPlatform: Stored info not exists: IDFA_freqCapNumViews
Stored info not exists: IABTCF_TCString
Stored info not exists: IABTCF_AddtlConsent
I / System.out: (HTTPLog) -Static: isSBSettingEnabled false
(HTTPLog) -Static: isSBSettingEnabled false
D / UserMessagingPlatform: Action [clear]: {"keys": ["IABTCF_CmpSdkID", "IABTCF_CmpSdkVersion", "IABTCF_PolicyVersion", "IABTCF_gdprApplies", "IABTCF_PublisherCC", "IABTCFreat_Streats" , "IABTCF_VendorLegitimateInterests", "IABTCF_PurposeConsents", "IABTCF_PurposeLegitimateInterests", "IABTCF_SpecialFeaturesOptIns", "IABTCF_PublisherConsent", "IABTCF_PublisherLegitimateInterests", "IABTCF_PublisherCustomPurposesConsents", "IABTCF_PublisherCustomPurposesLegitimateInterests", "IABTCF_AddtlConsent", "IABTCF_UserConsentRecordId", "IABTCF_idfaFlowControl"]}
D / UserMessagingPlatform: Action [write]: {"IABTCF_idfaFlowControl": 2}
What's wrong with my code?
public abstract class BaseActivity extends AppCompatActivity {
private final String TAG = "ART_APP";
private SharedPreferences sp;
private ConsentInformation consentInformation;
private ConsentForm consentForm;
final String LOG_TAG = "myLogs";
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.sp = getSharedPreferences(Sp.SP_KEY, Context.MODE_PRIVATE);
ConsentDebugSettings debugSettings = new ConsentDebugSettings.Builder(this)
.setDebugGeography(ConsentDebugSettings
.DebugGeography
.DEBUG_GEOGRAPHY_EEA)
.addTestDeviceHashedId("C258BF9BE13D842B973A20309A39C080")
.build();
ConsentRequestParameters params = new ConsentRequestParameters
.Builder()
.setConsentDebugSettings(debugSettings)
.build();
consentInformation = UserMessagingPlatform.getConsentInformation(this);
consentInformation.requestConsentInfoUpdate(
this,
params,
new ConsentInformation.OnConsentInfoUpdateSuccessListener() {
#Override
public void onConsentInfoUpdateSuccess() {
// The consent information state was updated.
// You are now ready to check if a form is available.
if (consentInformation.isConsentFormAvailable()) {
loadForm();
}
}
},
new ConsentInformation.OnConsentInfoUpdateFailureListener() {
#Override
public void onConsentInfoUpdateFailure(FormError formError) {
// Handle the error.
}
});
}
public SharedPreferences getSp() {
return sp;
}
public void loadForm(){
Log.d(LOG_TAG, "showconsent");
UserMessagingPlatform.loadConsentForm(
this,
new UserMessagingPlatform.OnConsentFormLoadSuccessListener() {
#Override
public void onConsentFormLoadSuccess(ConsentForm consentForm) {
BaseActivity.this.consentForm = consentForm;
if(consentInformation.getConsentStatus() == ConsentInformation.ConsentStatus.UNKNOWN) {
consentForm.show(
BaseActivity.this,
new ConsentForm.OnConsentFormDismissedListener() {
#Override
public void onConsentFormDismissed(#Nullable FormError formError) {
// Handle dismissal by reloading form.
loadForm();
}
});
}
}
},
new UserMessagingPlatform.OnConsentFormLoadFailureListener() {
#Override
public void onConsentFormLoadFailure(FormError formError) {
/// Handle Error.
}
}
);
}
/**
* Достать строку из переменных
*
* #param stringId
* #return
*/
public String getSpString(String stringId) {
return getResources().getString(sp.getInt(stringId, 0));
}
/**
* #param stringId
* #return
*/
public String getSpStringSt(String stringId) {
return sp.getString(stringId, "");
}
public void log(String msg) {
Log.d(TAG, msg);
}
/**
* Открываем ссылку в баузере
*
* #param url
*/
public void showLink(String url) {
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url)));
}
/**
* Есть ли подписка ?
*
* #return
*/
}
public class CategoryActivity extends BaseActivity implements RVAdapter.ItemClickListener,
View.OnClickListener, BarMenu.OnItemClick {
private static final String TAG = CategoryActivity.class.getSimpleName();
private RecyclerView rv;
private List<Item> items;
private List<Modal> modals;
private BarMenu barMenu;
private HashMap<Integer, MoreApp> moreApps;
private AdView adView;
private FrameLayout adContainerView;
private ConsentInformation consentInformation;
private ConsentForm consentForm;
final String LOG_TAG = "myLogs";
private SliderView sliderView;
private SliderPromoAdapter adapter;
private ArrayList<SliderItem> sliderViewArrayList = new ArrayList<>();
private View banner;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_category);
Log.d(LOG_TAG, "CategoryCreate");
initRateMe();
showRateMe();
MobileAds.initialize(this, new OnInitializationCompleteListener() {
#Override
public void onInitializationComplete(InitializationStatus initializationStatus) { }
});
//StartAppSDK.init(this, "202286925", true);
//------------
this.barMenu = new BarMenu(this, R.menu.top_bar_menu);
barMenu.setOnItemClick(this);
//------------
adapter = new SliderPromoAdapter(this);
SliderItem sliderItem = new SliderItem();
sliderItem.setSource(R.drawable.banner_premium);
sliderItem.setType(GlobalData.TYPE_PREMIUM);
sliderViewArrayList.add(sliderItem);
sliderView = findViewById(R.id.slider_view);
sliderView.setIndicatorAnimation(IndicatorAnimations.WORM); //set indicator animation by using SliderLayout.IndicatorAnimations. :WORM or THIN_WORM or COLOR or DROP or FILL or NONE or SCALE or SCALE_DOWN or SLIDE and SWAP!!
sliderView.setSliderTransformAnimation(SliderAnimations.SIMPLETRANSFORMATION);
sliderView.setAutoCycleDirection(SliderView.AUTO_CYCLE_DIRECTION_BACK_AND_FORTH);
sliderView.setIndicatorSelectedColor(Color.WHITE);
sliderView.setIndicatorUnselectedColor(Color.GRAY);
sliderView.setScrollTimeInSec(4); //set scroll delay in seconds :
sliderView.startAutoCycle();
sliderView.setSliderAdapter(adapter);
adapter.renewItems(sliderViewArrayList);
///get the reference to your FrameLayout
adContainerView = findViewById(R.id.adView_container);
//Create an AdView and put it into your FrameLayout
adView = new AdView(this);
adContainerView.addView(adView);
String adUnitId = getResources().getString(getSp().getInt(Sp.SP_ADS_BANNER_ID, 0));
adView.setAdUnitId(adUnitId);
//start requesting banner ads
loadBanner();
//------------
((TextView) findViewById(R.id.top_bar_title)).setText(
getSp().getInt(Sp.SP_APP_NAME, 0)
);
this.items = new ArrayList<>();
this.moreApps = new HashMap<>();
/*
if (!getSp().getBoolean(Sp.SP_MORE_APP_UP, false)) {
readJson();
}*/
//TODO Есть ли вообще другие приложения ?)
try {
if (!getSpStringSt(Sp.SP_MORE_APPS).equals("")) {
Gson gson = new Gson();
Type type = new TypeToken<List<MoreApp>>() {
}.getType();
List<MoreApp> ma = gson.fromJson(getSpStringSt(Sp.SP_MORE_APPS), type);
for (MoreApp m : ma) {
moreApps.put(m.getPosition(), m);
}
}
} catch (Exception e) {
e.printStackTrace();
}
// Баннер
this.banner = findViewById(R.id.custom_banner);
banner.setOnClickListener(this);
if (getSp().getBoolean(Sp.SP_IS_FREE5DAY, false)) {
banner.setVisibility(View.VISIBLE);
}
//if (getSp().getBoolean(Sp.SP_MORE_APP_UP, false)) {
readJson();
//}
this.rv = findViewById(R.id.category_recycler);
LinearLayoutManager llm = new GridLayoutManager(getApplicationContext(), 2);
rv.setLayoutManager(llm);
rv.setHasFixedSize(true);
RVAdapter adapter = new RVAdapter(items, this, true);
rv.setAdapter(adapter);
adapter.setmClickListener(this);
findViewById(R.id.top_bar_check).setVisibility(View.GONE);
findViewById(R.id.top_bar_menu).setOnClickListener(this);
findViewById(R.id.top_bar_back).setOnClickListener(this);
}
#Override
protected void onResume() {
super.onResume();
Log.d(LOG_TAG, "onResume");
loadForm();
if (getSp().getBoolean(Sp.SP_IS_FAQ, true)) {
// startActivity(new Intent(this, FaqActivity.class));
getSp().edit().putBoolean(Sp.SP_IS_FAQ, false).commit();
}
if (getSp().getBoolean(Sp.SP_IS_FREE5DAY, false)) {
}
hideSystemUI();
}
}
The problem might be that you call
super.onCreate(savedInstanceState);
before
setContentView(R.layout.activity_category);
I moved all Consent-Related code to a separate method initializeConsent() in the base class, and I called initializeConsent() as last method in my subclass's onCreate() method.
Additionally, I call
MobileAds.initialize
only in method onConsentFormLoadSuccess, it then looks like this:
#Override
public void onConsentFormLoadSuccess(ConsentForm consentForm) {
DisplayNumberActivity.this.consentForm = consentForm;
if(consentInformation.getConsentStatus() == ConsentInformation.ConsentStatus.REQUIRED) {
consentForm.show(
DisplayNumberActivity.this,
new ConsentForm.OnConsentFormDismissedListener() {
#Override
public void onConsentFormDismissed(#Nullable FormError formError) {
//reset all DSGVO information for next trial
// Handle dismissal by reloading form.
loadForm(); //neuerlicher Aufruf, sollte nun ConsentStatus == ConsentInformation.ConsentStatus.OBTAINED haben. Dort wird dann initializeMobileAds() aufgerufen
}
});
} else if (consentInformation.getConsentStatus() == ConsentInformation.ConsentStatus.OBTAINED
|| consentInformation.getConsentStatus() == ConsentInformation.ConsentStatus.NOT_REQUIRED) {
//Form muss nicht mehr angezeigt werden, Ads können geladen werden
if (consentInformation.getConsentStatus() == ConsentInformation.ConsentStatus.OBTAINED) {
logInfo("DSGVO Consent obtained");
} else {
logInfo("DSGVO Consent not required");
}
//ads können jedenfalls geladen werden, Admob checkt ob es personalisierte werbung sein darf
initializeMobileAds();
} else {
Toast.makeText(DisplayNumberActivity.this, "DSGVO Consent status: " + consentInformation.getConsentStatus(), Toast.LENGTH_LONG).show();
logInfo("unexpected DSGVO Consent: " + consentInformation.getConsentStatus());
initializeMobileAds();
}
}
I've got a main activity with a listener put on a MutableLiveData set in the onCreate hook :
userService.getPfcRepository().getUserLogged().observe(this, user -> {
if (user != null) {
setUserPets(user);
setUserDataInNavBar(user);
}
});
After that the login activity is launched, the value is changed. Another listener put in this activity on the MutableLiveData is working as expected, but when the login activity finishes and the main activity is back to the foreground, I notice that the listener hasn't been triggered (verified with the logs).
What could be at the origin of this problem ?
Main activity
public class MainActivity extends AppCompatActivity implements
PetFragment.OnListFragmentInteractionListener,
AccountManagementFormFragment.OnSaveButtonClickListener{
private static final int LOGIN_REQUEST = 1;
private static final int ADD_PET_REQUEST = 2;
/** LOGGING */
private static final String TAG = "MainActivity";
#Inject
UserService userService;
#Inject
PhotoService photoService;
...
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
((PetFoodingControl) getApplicationContext()).getServicesComponent().inject(this);
setContentView(R.layout.activity_main);
toolbar = findViewById(R.id.main_toolbar);
setSupportActionBar(toolbar);
setupAddButton();
DrawerLayout drawer = findViewById(R.id.drawer_layout);
NavigationView navigationView = findViewById(R.id.nav_view);
// Passing each menu ID as a set of Ids because each
// menu should be considered as top level destinations.
mAppBarConfiguration = new AppBarConfiguration.Builder(
R.id.nav_pets, R.id.nav_account_settings)
.setDrawerLayout(drawer)
.build();
NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
NavigationUI.setupActionBarWithNavController(this, navController, mAppBarConfiguration);
NavigationUI.setupWithNavController(navigationView, navController);
headerView = navigationView.getHeaderView(0);
getUserDataView();
setupLogoutListener();
setupUserLoggedListener();
if (userService.getPfcRepository().getUserLogged().getValue() == null) {
launchLoginActivity();
}
}
/**
* Setup userLoggedListener
*/
private void setupUserLoggedListener() {
userService.getPfcRepository().getUserLogged().observe(this, user -> {
if (user != null) {
setUserPets(user);
setUserDataInNavBar(user);
}
});
}
...
/**
* Launch login activity trough explicit intent.
*/
public void launchLoginActivity() {
Intent loginActivityIntent = new Intent(this, LoginActivity.class);
startActivityForResult(loginActivityIntent, LOGIN_REQUEST);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == LOGIN_REQUEST && resultCode != RESULT_OK) {
finishAndRemoveTask();
}
}
...
#Override
protected void onDestroy() {
userService.clearDisposables(this);
photoService.clearDisposables(this);
userService.leave();
super.onDestroy();
}
Login activity
#Inject
UserService userService;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
((PetFoodingControl) getApplicationContext()).getServicesComponent().inject(this);
setContentView(R.layout.activity_login);
if (savedInstanceState == null) {
setupUserLoggedListener();
}
userService.initLogin(this);
}
...
/**
* Action invoked when login button is clicked
* #param email entered
* #param password entered
*/
public void onLoginButtonClick(String email, String password) {
if (email.isEmpty() || password.isEmpty()) {
showToast(R.string.toast_input_empty);
} else {
tryToLog(email, password,
((CheckBox) findViewById(R.id.chk_keep_logged_in)).isChecked());
}
}
...
/**
* Try to log with the data provided (email, password and keep logged).
* #param email the email entered
* #param password the password entered
* #param isKeepLogged true if "keep logged" checked, false otherwise
*/
private void tryToLog(String email, String password, boolean isKeepLogged) {
userService.tryToLog(this, email, password, isKeepLogged).observe(this,
result -> {
if (result == 1) {
showToast(R.string.toast_failed_login);
} else if (result == 0) {
showToast(R.string.toast_success_login);
}
});
}
/**
* Setup a listener to load the login fields if no user is logged or the welcome fragment
* in the contrary.
*/
private void setupUserLoggedListener() {
userService.getPfcRepository().getUserLogged().observe(this, user -> {
if (user == null) {
loadFragment(LoginFieldsFragment.newInstance());
} else {
loadFragment(LoginWelcomeFragment.newInstance());
}
});
}
/**
* Return to the Main activity, and finishes the Login activity.
*/
public void finishLoginActivity(int resultCode) {
Intent retIntent = new Intent();
setResult(resultCode, retIntent);
finish();
}
#Override
protected void onDestroy() {
userService.clearDisposables(this);
super.onDestroy();
}
UserServiceImpl
public class UserServiceImpl extends PetFoodingControlService implements UserService {
/** LOGGING */
private static final String TAG = "UserService";
/** PREFERENCES AUTO LOGIN KEY */
private static final String AUTO_LOGIN_TOKEN = "autoLoginToken";
/** Disposable management */
private Map<Context, CompositeDisposable> compositeDisposableMap = new HashMap<>();
private PetFoodingControlRepository pfcRepository;
private SharedPreferences sharedPreferences;
#Inject
public UserServiceImpl(PetFoodingControlRepository pfcRepository,
SharedPreferences sharedPreferences) {
this.pfcRepository = pfcRepository;
this.sharedPreferences = sharedPreferences;
}
/**
* Init the login process.
* #param context the Context of the caller
*/
#Override
public void initLogin(Context context) {
String autoLogin = sharedPreferences.getString(AUTO_LOGIN_TOKEN,"");
if (!autoLogin.isEmpty()) {
Log.i(TAG, "Auto login value stored in preferences : " + autoLogin);
tryToAutologin(context, autoLogin);
} else {
pfcRepository.setUserLogged(null);
}
}
/**
* Try to log with auto login with the local token given as a parameter.
* #param autoLoginLocalToken the local auto login token
*/
private void tryToAutologin(Context context, String autoLoginLocalToken) {
Disposable disposable = pfcRepository.getUserByAutoLogin(autoLoginLocalToken).subscribe(
user -> {
Log.i(TAG, "User from AutoLogin successfully retrieved");
pfcRepository.setUserLogged(user);
}, throwable -> {
Log.e(TAG, "AutoLogin failed", throwable);
pfcRepository.setUserLogged(null);
});
addToCompositeDisposable(context, disposable);
}
/**
* Try to log in with the data provided, initiate the auto login feature saving and storing
* in preferences if necessary.
* Return a SingleLiveEvent<Integer> taking the value 0 in case of success and 1 in case
* of failure.
* #param context the Context of the caller
* #return logInResult SingleLiveEvent<Integer> result of the try
*/
#Override
public SingleLiveEvent<Integer> tryToLog(Context context, String email, String password,
boolean isKeepLogged) {
SingleLiveEvent<Integer> logInResult = new SingleLiveEvent<>();
Disposable disposable = pfcRepository.getUserByEmail(email).subscribe(
user -> CryptographyUtils.checkPassword(password, user.getPassword()).subscribe(
() -> {
pfcRepository.setUserLogged(user);
if (isKeepLogged) {
setAutoLogin(context);
}
logInResult.setValue(0);
Log.i(TAG, "Log in success.");
}, throwable -> {
logInResult.setValue(1);
Log.i(TAG, "Log in failure, wrong password.");
}),
throwable -> {
logInResult.setValue(1);
Log.e(TAG, "Log in failure ", throwable);
});
addToCompositeDisposable(context, disposable);
return logInResult;
}
...
PetFoodingControlService
public abstract class PetFoodingControlService {
/** Disposable management */
protected final Map<Context, CompositeDisposable> compositeDisposableMap = new HashMap<>();
/**
* Add the Disposable to the CompositeDisposable corresponding to the context.
* #param context the context of the CompositeDisposable
* #param disposable the Disposable to add
*/
protected final void addToCompositeDisposable(Context context, Disposable disposable) {
if (!compositeDisposableMap.containsKey(context)) {
compositeDisposableMap.put(context, new CompositeDisposable());
}
compositeDisposableMap.get(context).add(disposable);
}
/**
* Clear the CompositeDisposable corresponding to the context given in parameter,
* if it exists in the storage map.
* #param context the context of th CompositeDisposable
*/
protected final void compositeDisposableClear(Context context) {
if (compositeDisposableMap.containsKey(context)) {
compositeDisposableMap.get(context).clear();
}
}
PetFoodingControlRepositoryImpl
#RepositoryScope
public class PetFoodingControlRepositoryImpl implements PetFoodingControlRepository {
private static final String DB_NAME = "pfc_db";
private final PetFoodingControlDatabase petFoodingControlDatabase;
private final MutableLiveData<User> userLogged = new MutableLiveData<>();
private final MutableLiveData<Pet> userPets = new MutableLiveData<>();
#Inject
public PetFoodingControlRepositoryImpl(Application application) {
petFoodingControlDatabase = Room.databaseBuilder(application, PetFoodingControlDatabase.class, DB_NAME).build();
}
#Override
public Single<User> getUserByEmail(String email) {
return petFoodingControlDatabase.getUserDao().getUserByEmail(email)
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread());
}
#Override
public Single<User> getUserById(Long userId) {
return petFoodingControlDatabase.getUserDao().getUserById(userId)
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread());
}
#Override
public Single<Photo> getUserPhoto(User user) {
return petFoodingControlDatabase.getPhotoDao().getPhotoById(user.getPhotoId())
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread());
}
#Override
public void setUserLogged(User user) {
userLogged.setValue(user);
}
#Override
public MutableLiveData<User> getUserLogged() {
return userLogged;
}
...
Your problem is this line:
userService.getPfcRepository().getUserLogged().observe(this, user -> {
Your this is the activity it is placed on - or rather its lifecycle.
Once the activity goes to pause, the listener is removed by default.
To overcome this you have 2 options:
register this line in onResume, and receive the value, because there
is a value
register this line with a LifeCycleOwner who is NOT your activity's lifecycle.
I found the problem. It resides in the Dagger part of the application, and more prcisely in the fact that my services provides were not singleton annotated.
I searched but didn't find any good solution for my situation which is:
I need to filter existing List<Article> which is generated thru the paging lib, but can't figure it out how to retrieve actual articleList from api request in FeedDataSource class at FeedActivity. I need to filter actual list before adapter.submitList(pagedList);
FeedDataSurce class
public class FeedDataSource extends PageKeyedDataSource<Long, Article>{
private static final String QUERY = "movies";
private static final String API_KEY = "079dac74a5f94ebdb990ecf61c8854b7";
private static final String TAG = FeedDataSource.class.getSimpleName();
private RestApi restApi;
private MutableLiveData networkState;
public FeedDataSource() {
restApi = RestApiFactory.feedRequest();
networkState = new MutableLiveData();
}
public MutableLiveData getNetworkState() {
return networkState;
}
#Override
public void loadInitial(#NonNull LoadInitialParams<Long> params,
#NonNull LoadInitialCallback<Long, Article> callback) {
networkState.postValue(NetworkState.LOADING);
restApi.fetchFeed(QUERY, API_KEY, 1, params.requestedLoadSize)
.enqueue(new Callback<FeedResponse>() {
#Override
public void onResponse(Call<FeedResponse> call, Response<FeedResponse> response) {
if(response.isSuccessful()) {
callback.onResult(response.body().getArticles(), null, 2l);
networkState.postValue(NetworkState.LOADED);
} else {
networkState.postValue(new NetworkState(NetworkState.Status.FAILED, response.message()));
}
}
#Override
public void onFailure(Call<FeedResponse> call, Throwable t) {
String errorMessage = t == null ? "unknown error" : t.getMessage();
networkState.postValue(new NetworkState(NetworkState.Status.FAILED, errorMessage));
}
});
}
#Override
public void loadBefore(#NonNull LoadParams<Long> params,
#NonNull LoadCallback<Long, Article> callback) {
}
#Override
public void loadAfter(#NonNull LoadParams<Long> params, #NonNull LoadCallback<Long, Article> callback) {
Log.d(TAG, "Loading Rang " + params.key + " Count " + params.requestedLoadSize);
networkState.postValue(NetworkState.LOADING);
restApi.fetchFeed(QUERY, API_KEY, params.key, params.requestedLoadSize).enqueue(new Callback<FeedResponse>() {
#Override
public void onResponse(Call<FeedResponse> call, Response<FeedResponse> response) {
if(response.isSuccessful()) {
callback.onResult(response.body().getArticles(), params.key + 1);
networkState.postValue(NetworkState.LOADED);
} else
networkState.postValue(new NetworkState(NetworkState.Status.FAILED, response.message()));
}
#Override
public void onFailure(Call<FeedResponse> call, Throwable t) {
String errorMessage = t == null ? "unknown error" : t.getMessage();
networkState.postValue(new NetworkState(NetworkState.Status.FAILED, errorMessage));
}
});
}
DataFactory class
public class FeedDataFactory extends DataSource.Factory {
private MutableLiveData<FeedDataSource> mutableLiveData;
public FeedDataFactory() {
this.mutableLiveData = new MutableLiveData<>();
}
#Override
public DataSource create() {
FeedDataSource feedDataSource = new FeedDataSource();
mutableLiveData.postValue(feedDataSource);
return feedDataSource;
}
public MutableLiveData<FeedDataSource> getMutableLiveData() {
return mutableLiveData;
}
ViewModel
public class FeedViewModel extends ViewModel {
private Executor executor;
private LiveData<NetworkState> networkState;
private LiveData<PagedList<Article>> articleLiveData;
public FeedViewModel() {
init();
}
private void init() {
executor = Executors.newFixedThreadPool(5);
FeedDataFactory feedDataFactory = new FeedDataFactory();
networkState = Transformations.switchMap(feedDataFactory.getMutableLiveData(),
dataSource -> dataSource.getNetworkState());
PagedList.Config pagedListConfig = new PagedList.Config.Builder()
.setEnablePlaceholders(true)
.setInitialLoadSizeHint(20)
.setPageSize(20)
.build();
articleLiveData = new LivePagedListBuilder(feedDataFactory, pagedListConfig)
.setFetchExecutor(executor)
.build();
}
public LiveData<NetworkState> getNetworkState() {
return networkState;
}
public LiveData<PagedList<Article>> getArticleLiveData() {
return articleLiveData;
}
Activity
public class FeedActivity extends AppCompatActivity {
private FeedListAdapter adapter;
private FeedViewModel feedViewModel;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
/*
* Step 2: Initialize the ViewModel
*
* */
feedViewModel = new FeedViewModel();
/*
* Step 2: Setup the adapter class for the RecyclerView
*
* */
RecyclerView recyclerView = findViewById(R.id.list_feed);
recyclerView.setLayoutManager(new LinearLayoutManager(getApplicationContext()));
adapter = new FeedListAdapter(getApplicationContext());
/*
* Step 4: When a new page is available, we call submitList() method
* of the PagedListAdapter class
*
* */
feedViewModel.getArticleLiveData().observe(this, pagedList -> {
Log.d("TAG", "onCreate: ");
adapter.submitList(pagedList);
});
/*
* Step 5: When a new page is available, we call submitList() method
* of the PagedListAdapter class
*
* */
feedViewModel.getNetworkState().observe(this, networkState -> {
adapter.setNetworkState(networkState);
});
recyclerView.setAdapter(adapter);
}
I am using Sync Adapter along with Dagger 2 for dependency injection. I am stuck since I cannot seem to figure out where should I use XYZ.inject since SyncAdapter class does not provide OnCreate or an Activity to stick to. Can someone suggest how to deal with Dependency injection in case of Sync Adapter alike classes which do not belong to activity/fragment?
PS: I have looked at several similar questions but failed to find a solution to my problem.
SyncAdapter.java
public class SyncAdapter extends AbstractThreadedSyncAdapter {
ContentResolver mContentResolver;
//Injects here
#Inject
SyncCenterPresenter mSyncCenterPresenter;
private final AccountManager mAccountManager;
Context context;
public SyncAdapter(Context context, boolean autoInitialize) {
super(context, autoInitialize);
mContentResolver = context.getContentResolver();
mAccountManager = AccountManager.get(context);
this.context=context;
}
Account mainAccount;
public static final int SYNC_INTERVAL = 60 * 1;
public static final int SYNC_FLEXTIME = SYNC_INTERVAL/3;
#Override
public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult) {
Log.v("Sync class me","sync adapter on perform sync");
if (mSyncCenterPresenter == null){
Log.v("messsage","null");
} else {
Log.v("messsage","not null");
mSyncCenterPresenter.loadDatabaseCenterPayload();
mSyncCenterPresenter.syncPayload();
}
}
/**
* Helper method to schedule the sync adapter periodic execution
*/
public static void configurePeriodicSync(Context context, int syncInterval, int flexTime) {
Account account = myAccount;
String authority = "com.mifos.provider";
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
// we can enable inexact timers in our periodic sync
SyncRequest request = new SyncRequest.Builder().
syncPeriodic(syncInterval, flexTime).
setSyncAdapter(account, authority).
setExtras(new Bundle()).build();
ContentResolver.requestSync(request);
} else {
ContentResolver.addPeriodicSync(account,
authority, new Bundle(), syncInterval);
}
}
static Account myAccount;
public static void onAccountCreated(Account newAccount, Context context) {
/*
* Since we've created an account
*/
myAccount = newAccount;
SyncAdapter.configurePeriodicSync(context, SYNC_INTERVAL, SYNC_FLEXTIME);
/*
* Without calling setSyncAutomatically, our periodic sync will not be enabled.
*/
ContentResolver.setSyncAutomatically(newAccount, "com.mifos.provider", true);
/*
* Finally, let's do a sync to get things started
*/
syncImmediately(context);
}
public static Account getSyncAccount(Context context) {
// Create the account type and default account
Account newAccount = new Account(
context.getString(R.string.app_name), "com.mifos");
return newAccount;
}
/**
* Helper method to have the sync adapter sync immediately
* #param context The context used to access the account service
*/
public static void syncImmediately(Context context) {
Bundle bundle = new Bundle();
bundle.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true);
bundle.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
ContentResolver.requestSync(getSyncAccount(context),
"com.mifos.provider", bundle);
}
}
SyncCenterPresenter.java
public class SyncCenterPresenter {
private final DataManagerCenter mDataManagerCenter;
private CompositeSubscription mSubscriptions;
List<CenterPayload> centerPayloads;
int mCenterSyncIndex = 0;
#Inject
public SyncCenterPresenter(DataManagerCenter dataManagerCenter) {
Log.v("messsage","const me");
mDataManagerCenter = dataManagerCenter;
mSubscriptions = new CompositeSubscription();
centerPayloads = new ArrayList<>();
}
public void loadDatabaseCenterPayload() {
Log.v("messsage","load me");
mSubscriptions.add(mDataManagerCenter.getAllDatabaseCenterPayload()
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.subscribe(new Subscriber<List<CenterPayload>>() {
#Override
public void onCompleted() {
}
#Override
public void onError(Throwable e) {
}
#Override
public void onNext(List<CenterPayload> centerPayloads) {
showCenters(centerPayloads);
}
}));
}
public void syncCenterPayload(CenterPayload centerPayload) {
mSubscriptions.add(mDataManagerCenter.createCenter(centerPayload)
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.subscribe(new Observer<SaveResponse>() {
#Override
public void onCompleted() {
}
#Override
public void onError(Throwable e) {
}
#Override
public void onNext(SaveResponse center) {
showCenterSyncResponse();
}
}));
}
public void deleteAndUpdateCenterPayload(int id) {
mSubscriptions.add(mDataManagerCenter.deleteAndUpdateCenterPayloads(id)
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.subscribe(new Observer<List<CenterPayload>>() {
#Override
public void onCompleted() {
}
#Override
public void onError(Throwable e) {
}
#Override
public void onNext(List<CenterPayload> centerPayloads) {
showPayloadDeletedAndUpdatePayloads(centerPayloads);
}
}));
}
public void showCenters(List<CenterPayload> centerPayload) {
centerPayloads = centerPayload;
}
public void showCenterSyncResponse() {
deleteAndUpdateCenterPayload(centerPayloads
.get(mCenterSyncIndex).getId());
}
public void showPayloadDeletedAndUpdatePayloads(List<CenterPayload> centers) {
mCenterSyncIndex = 0;
this.centerPayloads = centers;
}
public void syncPayload() {
for (int i = 0; i < centerPayloads.size(); ++i) {
if (centerPayloads.get(i).getErrorMessage() == null) {
syncCenterPayload(centerPayloads.get(i));
mCenterSyncIndex = i;
break;
} else {
Log.v("messsage","else block");
}
}
}
}
ActivityComponent
#PerActivity
#Component(dependencies = ApplicationComponent.class, modules =
ActivityModule.class)
public interface ActivityComponent {
void inject(LoginActivity loginActivity);
void inject(PassCodeActivity passCodeActivity);
//other methods
void inject(SyncAdapter syncAdapter);
}
ActivityModule
#Module
public class ActivityModule {
private Activity mActivity;
public ActivityModule(Activity activity) {
mActivity = activity;
}
#Provides
Activity provideActivity() {
return mActivity;
}
#Provides
#ActivityContext
Context providesContext() {
return mActivity;
}
}
EDIT
SyncService.java
public class SyncService extends Service {
private static final Object sSyncAdapterLock = new Object();
private static SyncAdapter sSyncAdapter = null;
#Override
public void onCreate() {
synchronized (sSyncAdapterLock) {
if (sSyncAdapter == null) {
sSyncAdapter = new SyncAdapter(getApplicationContext(), true);
}
}
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return sSyncAdapter.getSyncAdapterBinder();
}
}
Can someone please help me to get this working? since I can't figure out where to use the inject and how to do it without an Activity Component? A different and a better approach would be appreciated as well.
Thanks
You can implement the constructor, so please use constructor injection to initialize your adapter.
public class SyncAdapter extends AbstractThreadedSyncAdapter {
// ...
#Inject
public SyncAdapter(Context context, boolean autoInitialize) { /*...*/ }
}
Then you simply inject the service that returns the SyncAdapter like you would anything else...
public class SyncService extends Service {
#Inject SyncAdapter syncAdapter;
#Override
public void onCreate() {
AndroidInjection.inject(this);
// or
DaggerSyncServiceComponent.create().inject(this);
}
#Override
public IBinder onBind(Intent intent) {
return syncAdapter;
}
}
And that's it.