First of all: There is no exception thrown when this problem occurs.
My app is currently running in Google Plays closed alpha program. When I test the app using an emulator provided by Android Studio or using my own Galaxy A5, everything works fine and as expected.
Now I'm getting reports of my alpha testers, that their app is closing after they close the VideoAd. After investigating a while, I realized all devices used by google while performing Pre-Launch-Tests, had the same problem (visible by the video provided by Google).
Since there is no exception thrown, I have absolutely no idea how to debug this behaviour.
Following is the code of the onRewarded method (the other methods of the listener don't contain any code):
#Override
public void onRewarded(RewardItem rewardItem) {
int amount = calculateAdReward(rewardItem.getAmount());
updateCoins(amount);
rewardedAmount = amount;
rewarded = true;
}
rewardedAmount and rewarded are private fields used to instantiate a fragment in the activitys onResume-method:
#Override
protected void onResume() {
super.onResume();
mAdVideo.resume(this);
if(rewarded){
loadFragment(RewardFragment.newInstance(rewardedAmount);
rewardedAmount = 0;
rewarded = false;
}
}
My goal is to display a fragment after the user has been rewarded which holds the rewarded amount. My first attempt was as followed:
#Override
public void onRewarded(RewardItem rewardItem) {
int amount = calculateAdReward(rewardItem.getAmount());
updateCoins(amount);
loadFragment(RewardFragment.newInstance(amount));
}
which failed, since I tried to instantiate a fragment after saveInstanceState was called.
So after a bit of research, I solved my problem.
What I learned:
Never perform transactions inside the activity's lifecycle methods (onResume,...) since there is a possibility that the activity hasn't fully resumed when you reach your transaction code.
Instead, perform transactions in the onPostResume method. When this method is called, it is guaranteed your activity and all it's fragments have been fully resumed and it is "save" to perform a transaction.
On a side note: Don't perform transactions in those methods if you don't absolutely have to.
Related
As the title says.
Specifically, I am writing an app that prints data to files over the course of runtime. I want to know when I can tell my PrintWriters to save the files. I understand that I can probably do autosave every X minutes, but I am wondering if Android Studio will let me save on close instead. I tried using onDestroy but the code block never executed. (To be precise, I started the app, did a few things, closed the app, clicked Recents, and swiped the app away. The debugger showed that the app never got to that code.)
My current solution attempts to catch the surrounding circumstances by checking for key presses but this only works for the back and volume buttons and not the home, recent, or power buttons.
#Override public boolean onKeyDown(int key, KeyEvent event) {
close();
return false;
}
There's a built in hook to the Activity lifecycle to save your state- onSaveInstanceState. There's even a bundle passed into you to save your state into for it to be restored (the matching function is onResumeInstanceState). And as a free bonus, if you call super.onSaveInstanceState and super.onRestoreInstanceState, it will automatically save the UI state of your app for all views with an id.
Please check the activity lifecycle:
https://developer.android.com/guide/components/activities/activity-lifecycle
Or if you're using a fragment:
https://developer.android.com/guide/fragments/lifecycle
Consider using one of these two:
#Override public void onStart() {
super.onStart();
close();
}
#Override public void onPause() {
super.onPause();
close();
}
I am working on stripe-terminal-android-app, to connect to BBPOS 2X Reader device,
wanted to click-item from list,(recyclerView).
I am trying to do:
when list of devices appears(readers), I am checking if readers.size()==1, then click first-device from list,else show recyclerView();
I have very less experience in Android(coming from JS, PY), :)
After going through debugger to understand flow of program-running, I used F8 key, or stepOver the functions one by one,
and where value is assigned to convert in displayble-format in adapter as here.
public ReaderAdapter(#NotNull DiscoveryViewModel viewModel) {
super();
this.viewModel = viewModel;
if (viewModel.readers.getValue() == null) {
readers = new ArrayList<>();
} else {
readers = viewModel.readers.getValue();
if(readers.size() == 1){
Log.e(TAG, "readers.size() is 1 "+ readers.size());
}
}
}
then in ReaderHolder-file, values are bind() as
void bind(#NotNull Reader reader) {
binding.setItem(reader);
binding.setHandler(clickListener);
binding.executePendingBindings();
}
}
I tried assigining button and manually clicking when only-one device appears, by clicing on reader[0], can't do that by findViewById inside Adapter file, to call onClick() method manually,
I tired another StackOverflow's answer but didn't understood, from here.
Main fragment is discovery-fragment,
how can I click first-device by checking readers.size()==1, then click onClick()?
my final-goal is to automate, whole stripe-terminal-payment process on android.
extra-info:
I am fetching data from python-odoo server, then using url, will open app through browser, (done this part), then device will be selected automatically as everytime-no any devices will be present except one,
so will automatically select that from recyclerView, then proceed.
I have asked for help in detailed way on GitHub-issues, and started learning Android's concepts for this app(by customizing stripe's demo app, which works great, but I wanted to avoid manually clicking/selection of devices).
I need to hide the content of my application when it goes to the background so sensitive information are not showing up on the android multitasking view.
It's been suggested to use the following line to hide the screen
getWindow().setFlags(LayoutParams.FLAG_SECURE, LayoutParams.FLAG_SECURE);
It works fine.
However, this prevents the user from taking screenshot as well which is not an expected behavior for me. I want to let the user take screenshot of the app if they need to. What I don't want is Android to display the latest screen on the multitasking view.
Would it be possible to set the FLAG_SECURE only when the app goes in the background?
We've ended up with this solution which worked the best for us:
#Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (!hasFocus) {
getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE);
} else {
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_SECURE);
}
}
You can use Activity Lifecycle Callbacks. Just call setVisiblity(View.INVISIBLE) on the views that you want to hide in the onPause() Callback and setVisiblity(View.VISIBLE) in onResume() Callback.
I'm trying to get an app to show all the users online... I'm using the following way to achieve it
#Override
public void onStart(){
super.onStart();
mDatabaseReference.child("Online").setValue(true);
}
#Override
public void onStop(){
super.onStop();
mDatabaseReference.child("Online").setValue(false);
}
I'm not using ondisconnect because it shows offline only if the app is completely closed(not running in the background). SO i used this method on each activity... But the problem is that whenever i open an activity it shows online and the next second turns offline... I'm guessing that its because the prev activity closes after opening the new activity so the presents activity's on start is executed before the next activity's on stop. So since the activity's onstop is executed last it shows offline. How do i solve this problem
Your guess is completely correct.
Starting a new Activity will cause the onPause() and onStop() methods to be called for the first Activity.
Based on your description, I'm assuming that you want the Online status to remain true for as long as the app remains in the foreground and you are putting it in every Activity because your app doesn't only open from a single main Activity.
Your current code will work without a problem if you switched to using a Single-Activity Architecture, which is simply to use a single Activity and have it display different Fragments instead of new Activities. This solution will work with your existing code because onStop() and onStart() will only be called when your app enters the background.
If you look at the Navigation section in the official Android Developers Blog, you'll see that Google wants to encourage developers to switch to using the Single-Activity Architecture.
However, if you still wish to use multiple Activities, then you might want to consider an alternative way to keep track of Online status to take into account of multiple Activities.
For example, rather than using a simple boolean value, you can use an int value.
#Override
public void onStart(){
super.onStart();
mDatabaseReference.child("Online").addValue();
}
#Override
public void onStop(){
super.onStop();
mDatabaseReference.child("Online").removeValue();
}
With the addValue() and removeValue() being:
private void addValue(){
activityCount++;
onlineStatus = true;
}
private void removeValue(){
activityCount--;
if(activityCount <= 0)
onlineStatus = false;
}
Please keep in mind that this is only an example and doesn't take into account of how your app is designed. Bottom line is, you'll have to think of a solution that takes into account of multiple Activities that are displayed.
I do heavily suggest the Single-Activity approach.
I have created a startup activity from where I am calling another activity which has a view pager and shows some introductory pages.
This app was taking time to load so I thought to display a progress dialog till the activity loads, but that progress dialog also appears few seconds later.
startup activity:
public class StartUpActivity extends AppCompatActivity {
boolean isUserFirstTime, login;
public static String PREF_USER_FIRST_TIME;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
isUserFirstTime = Boolean.valueOf(Utils.readSharedSetting(StartUpActivity.this, PREF_USER_FIRST_TIME, "true"));
Intent introIntent = new Intent(StartUpActivity.this, SlidingActivity.class);
introIntent.putExtra(PREF_USER_FIRST_TIME, isUserFirstTime);
ProgressDialog dialog = new ProgressDialog(StartUpActivity.this);
dialog.setMessage("Welcome to Mea Vita, please wait till the app loads.");
dialog.setCancelable(false);
dialog.setInverseBackgroundForced(false);
dialog.show();
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
//Here you can send the extras.
startActivity(new Intent(StartUpActivity.this,SlidingActivity.class));
// close this activity
finish();
}
}, 4000);
}
}
This doesn't happen every time,only sometimes. What can be the possible reason for this? how can I stop this?
Any solution? Thank you..
There is a strange issue with newly released Android Studio 2.0 (same issue in 2.1) first time of launching application take longer than usual (e.g. 2, 3 seconds or sometimes screen blinks or goes black) this issue happens only in debug mode and not effect your released APK.
A temporary solution to fix this is disabling instant run:
Settings → Build, Execution, Deployment → Instant Run and uncheck Enable Instant Run
First of all, make as rule to make all data loading in async tasks, you must check activity that you want to start where you load data.
The problem is in your second activity.
oncreate method should be used only to make findviews or start async tasks, don't load any in oncreate or in onstart or in onresume.
Probably you are loading high res images in sliding layout or you loading data in it.
There is another way, load all data in async task on first activity, then with ready data start second activity with already data loaded.
There are a few things that can load slowly.
Android need to read your code from storage and load the classes into ram.
I assume Utils.readSharedSetting(StartUpActivity.this, PREF_USER_FIRST_TIME, "true") reads from preferences. That's a file that you're reading from synchronously.
Actually launching the dialog takes a very small amount of time.
I'd suggest showing your loading inside the activity itself to minimize the work needed to render it.
Also, you can store PREF_USER_FIRST_TIME as a boolean instead of a String.