I'm facing this problem with TextView. It is not erasing the previous instances of data.
When I'm running my application in emulator it displays output data in TextView. That's fine. But when I'm clicking back button in my emulator and re opening the application it does not clear the previous data. Instead it appends the data to already existing data.
Any help is appreciated.
My code is as below:
public class MainActivity extends ActionBarActivity
{
private TextView mTextView;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTextView = (TextView) findViewById(R.id.text_test);
new Thread(new TestLocalHost()).start();
}
private class TestLocalHost implements Runnable
{
#Override
public void run()
{
final String s = JSONParser.doGet("http://192.168.0.107:15071/GetResult.ashx?op=getInfo",null);
runOnUiThread(new Runnable()
{
#Override
public void run()
{
mTextView.setText(s);
}
});
}
}
}
It's happening because your app still lives in the emulator memory, you need to force kill it if you want your app to run again from scratch.
You should click on the "running processes" button and swipe left/right the app process.
In the scenario that you described the activity wasn't destroyed yet, and when you reopen it only its onResume() method is being called.
Related
I was developing an exam score calculator app.
When I want to call AD methods,advertisements don't show up.
Calculation process happens in OnCreate method:
public class resultActivity extends AppCompatActivity {
public String responseId;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_result);
/*Calculation...*/}
and other voids like:
public void requestAd() {
/*AD RQUESTING PROCESS...*/
}
and
public void showAd() {
/*AD SHOWING PROCESS...*/
}
AD team gave me this code to call the method and it works well:
requestButton.setOnClickListener(v -> requestAd());
showButton.setOnClickListener(v -> showAd());
But the Problem is I don't have buttons to call them so I tried this:
public class resultActivity extends AppCompatActivity {
public String responseId;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_result);
requestAd();
showAd();
/*Calculation...*/}
But when the activity starts ads don't show up!
The whole question is I want this methods to be called while this activity starts.
thank you.
Try building up the release version APK and test on it. Maybe your Ad-provider have some restrictions in debug version?
I made another class and moved request Ad and showAd there. Then, I made an object and called the method through object.
I have to mention that I changed a minor thing in requestAd but the main job was done by the object.
Thank You All.
Problem: I need to run some code at every start before my app is ready to be used.
At first, I tried doing it in a dedicated activity.
AndroidManifest.xml
<activity android:name=".MainActivity" />
<activity android:name=".StarterActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
AppLoader.java
public class AppLoader {
private static Object someInstance;
public static void load(Runnable onCompleteCallback) {
try {
someInstance = new Object();
//potentially long operation to initialize the app
Thread.sleep(5000);
onCompleteCallback.run();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
public static void checkInitialized() {
if (someInstance == null) {
throw new RuntimeException("Not initialized");
}
}
}
StarterActivity.java
public class StarterActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
AppLoader.load(() -> {
MainActivity.start(this);
finish();
});
}
}
MainActivity.java
public class MainActivity extends AppCompatActivity {
public static void start(Context context) {
Intent starter = new Intent(context, MainActivity.class);
context.startActivity(starter);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
AppLoader.checkInitialized();
}
}
This works fine if the app is cold started via the launcher icon but crashes in all other cases. Simple way to reproduce the issue:
Go to developer settings on your device and set "Background process limit" to "No background process"
Open the app
Open some other app
Open the app again. Result: it crashes.
Here's an article describing a similar problem: Android process death — and the (big) implications for your app
Possible solutions:
Lazy loading/reactive approach. I try to use it as much as possible but there is always some code I need to run in a blocking way before user can interact with the app so this is not enough.
Putting all of that code in App.onCreate(). This would probably work for small apps but I've seen large apps that take 5-10 seconds to initialize, and I doubt they use onCreate() for that. Possible downsides: ANR and/or excessive startup time in Android Vitals?
Checking if the app is initialized in a BaseActivity, but that would require either blocking onCreate or managing lifecycle callbacks manually which doesn't sound like a good idea.
So, what's the proper way to run some code every time the app is launched?
Note: Normally StarterActivity would be a splash screen, AppLoader would be injected, etc, but I left that out for simplicity.
AndroidManifest.xml
<application
android:name=".AppLoader"
AppLoader.java
public class AppLoader extends Application {
private static Object someInstance;
#Override
public void onCreate() {
super.onCreate();
// DO YOUR STUFF
}
}
Update
- Use Handler with splash screen.
public class StarterActivity extends AppCompatActivity {
private Handler handler;
private Runnable myStuffRunnable;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
handler = new Handler();
myStuffRunnable = new Runnable(){
public void run(){
// DO MY STUFF
MainActivity.start(this);
}
};
}
#Override
protected void onPause() {
handler.removeCallbacks(myStuffRunnable);
super.onPause();
}
#Override
protected void onResume() {
super.onResume();
handler.post(myStuffRunnable);
}
#Override
protected void onDestroy() {
handler.removeCallbacks(myStuffRunnable);
super.onDestroy();
}
}
Your app is throwing the RuntimeException you set in AppLoader.checkInitialized() method, because your someInstance object is losing it's state when the app goes to background and gets killed by the system ('cause you have set your device to hold zero background threads). So, when you try to reopen the app, the system launches MainActivity directly (and not StarterActivity) because it is trying to restore it's previous state. But variables are not restored, not even static variables.
So, if you need the Object someInstance on your MainActivity, you should integrate it's instantiation into MainActivitie's lifecycle, overriding methods like onSavedInstanceState, onRestoreInstanceState, etc, to properly handle and reaload this object if your app gets killed by the system.
Take a look on this https://developer.android.com/guide/components/activities/activity-lifecycle
If anyone's interested, I ended up just redirecting the user to StarterActivity if needed to make sure the necessary code is executed at every start.
public abstract class BaseActivity extends AppCompatActivity {
private boolean isCreated;
#Override
protected final void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (!appLoader.isLoaded()) {
StarterActivity.start(this);
finish();
return;
}
onCreateActivity(savedInstanceState);
isCreated = true;
}
protected void onCreateActivity(#Nullable Bundle savedInstanceState) {
}
#Override
protected final void onDestroy() {
super.onDestroy();
if (isCreated) {
onDestroyActivity();
}
}
protected void onDestroyActivity() {
}
}
All activities extend BaseActivity (except StarterActivity) and override onCreateActivity/onDestroyActivity instead of onCreate/onDestroy.
I have a Parent activity that sets a view on Resume based on some check like this :
public class AppLockActivity extends AppCompatActivity {
#BindView(R.id.btnSubmit)
Button submitButton;
private static final String TAG = "AppLockActivity";
private static TimeElapsed timeElapsedInstance;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
timeElapsedInstance = TimeElapsed.getInstance();
timeElapsedInstance.resetTime();
timeElapsedInstance.setStartTime();
}
#Override
protected void onResume() {
super.onResume();
//check if app has passed a time threshold
if(timeElapsedInstance.getStartTime() != 0){
timeElapsedInstance.setEndTime(Calendar.getInstance().getTimeInMillis());
long threshold = timeElapsedInstance.getEndTime()-timeElapsedInstance.getStartTime();
Log.d(TAG,"Threshold : "+threshold);
//Current timeout threshold set to 30s
if(threshold>30000){
setContentView(R.layout.activity_app_lock);
ButterKnife.bind(this);
}else{
}
}
}
#OnClick(R.id.btnSubmit) void onSubmit() {
//destroy current(Parent) view and show the previous
}
}
This activity is extended by other activities like MainAcitivty ,etc...
public class MainActivity extends AppLockActivity{
#Override
protected void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.activity_main);
}
}
When the app goes in background and is resumed the onResume function is called and based on the check the new View is set - R.layout.activity_app_lock. What I want to do is onClick of the submit button in this view I want to destroy the current view i.e (R.layout.activity_app_lock) and show the previous view that was in the child activity like MainActivity (R.layout.activiyt_main)...
Anybody have any idea how can I do this?
Thanks
You can actually call setContentView again with a different view. All your bindings need to be reset and your On_____Listeners need to be cleared or else you'll get a memory leak. Other than that, it'll be up and ready for you to go.
Though I suggest an alternative approach to changing the layout. Instead, create a new Activity that you start in replacement of the layout your currently submitting. Then, rather than worrying about leaks, you just call finish() on the lock Activity when the user submits. The effect would be the same and it would be more versatile (In my opinion).
I have been searching for a while a solution to my problem : I have two activities. The first one disappears to let the second one appears after 4 seconds.The problem is every 4 seconds the second activity is relaunched and so my application on my Smart phone is not stable at all (every 4 seconds the second activities appears, then disappears again and again !)
My aim is : after 4 seconds my first activity let place to the second one and the second must stay stable until an action of the user. How can I stop this "periodicity" ?
Here is the code of the two Java file : The first class =
public class MainActivityWelcome extends AppCompatActivity {
private static int TIME_OUT = 4000;
#Override
protected void onCreate(Bundle savedInstanceState) {
//this.requestWindowFeature(Window.FEATURE_NO_TITLE);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_activity_welcome);
TextView texteView = (TextView) findViewById(R.id.notick);
Typeface font = Typeface.createFromAsset(getAssets(),"fonts/USAAF_Stencil.ttf");
texteView.setTypeface(font);
texteView.setText(Html.fromHtml(getString(R.string.notick)));
final View myLayout = findViewById(R.id.notick);
new Handler().postDelayed(new Runnable() {
#Override
public void run(){
Intent i = new Intent(MainActivityWelcome.this,FirstConnexion.class);
startActivity(i);
finish();
}
}, TIME_OUT);
}
}
And the second class :
public class FirstConnexion extends MainActivityWelcome{
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.first_connexion);
TextView texteView1 = (TextView) findViewById(R.id.titlenotick);
Typeface font = Typeface.createFromAsset(getAssets(),"fonts/USAAF_Stencil.ttf");
texteView1.setTypeface(font);
texteView1.setText(Html.fromHtml(getString(R.string.notick)));
}
}
Do you know where I must play to stop this phenomenon ?
Thank you very much !
you are extending MainActivityWelcome to your FirstConnexion that is why super.onCreate(savedInstanceState); again calling MainActivityWelcome's onCreate method and it is again calling your FirstConnexion after 4 seconds . Result Infinite Call
so you have to extend your FirstConnexion with AppCompatActivity
public class FirstConnexion extends AppCompatActivity
public class FirstConnexion extends AppCompatActivity{
}
I know that this topic has been already beaten enough, but I still don't understand completely if Android System has fine behavior in following case:
I created small app consists of two classes, here is the code:
Main.java
public class Main extends Activity {
private Button bv;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
bv = (Button) findViewById(R.id.hello_txt);
bv.setOnClickListener(
new OnClickListener() {
#Override
public void onClick(View v) {
Intent i = new Intent(Main.this, Main2.class);
startActivity(i);
}
}
);
}
}
Main2.java
public class Main2 extends Activity {
private TextView countOfActivities;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
countOfActivities = new TextView(this);
setContentView(countOfActivities);
countOfActivities.setText("Count of Activities: " + getInstanceCount());
}
}
When I clicked on the button from first activity several times, I get that even after pressing BACK button that should call second Activity's onDestroy() it's instance remains in the memmory.
Only after creating about 35 instances next click let me know, that GC cleared the memmory.
I just want to completely be sure that it is normal system's behavior.
Following pictures from Emulator and LogCat
Button clicked 10 times
LogCat output after clicked
Yes, the system works fine.
When you press the back button, your activity is removed from the activity stack.
onDestroy() may have been called, this doesn't mean that the instance was actually unallocated from the memory.