为什么我的Android应用程序在目前一切正常的情况下运行两个实例?

为什么我的Android应用程序在目前一切正常的情况下运行两个实例?,android,debugging,android-activity,Android,Debugging,Android Activity,我有一个包含三个活动的应用程序 从SharedReferences加载数据的splashscreenActivity(启动器活动)。然后在第二次之后继续MainActivity并退出(finish())本身 负责UI并对变量和AlarmManager进行必要更改的主要活动 仅由AlarmManager使用的广播接收器。BroadCastReceiver根据Splash的静态值发送通知 一切都很顺利,直到我将材料设计添加到依赖项中,并更新了我的所有布局和所有这些东西。我不确定这是否是导致这个错误的

我有一个包含三个活动的应用程序

  • 从SharedReferences加载数据的splashscreenActivity(启动器活动)。然后在第二次之后继续MainActivity并退出(finish())本身
  • 负责UI并对变量和AlarmManager进行必要更改的主要活动
  • 仅由AlarmManager使用的广播接收器。BroadCastReceiver根据Splash的静态值发送通知
  • 一切都很顺利,直到我将材料设计添加到依赖项中,并更新了我的所有布局和所有这些东西。我不确定这是否是导致这个错误的原因。但现在,我的应用程序启动了两个启动屏幕实例。 它并不那么明显,因为它消失了。但在我完成MainActivity并按下back按钮后,MainActivity将返回到另一个MainActivity。 怎么会这样

    代码如下:

    SplashScreen.java>

    package com.example.breathe;
    
    import androidx.appcompat.app.AppCompatActivity;
    import androidx.appcompat.app.AppCompatDelegate;
    
    import android.content.Intent;
    import android.content.SharedPreferences;
    import android.os.Bundle;
    import android.os.Handler;
    import android.util.Log;
    
    public class SplashScreen extends AppCompatActivity {
    
        public static boolean breatheToggled = false, persistence = true;
        public static int interval = 0;
        public static boolean TESTING = false;
        public static String BreathePreferencesKey="THE_KEY_TO_THE_VALLEY_OF_ETERNAL_PREFERENCES",
                breatheToggleString = "Isthetoggleswitchonoroff",
                breatheIntervalString = "IntervalForBreatheReminder",
                breathePersistenceString = "StringForPersistenceSwitchKey";
        public static void log(String x){ Log.d("jitin", x); }
        public static void trace(String x){ Log.d("trace", x); }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            trace("Splash Destroyed");
        }
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_splash);
    //        AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
    
            //LOAD DATA FROM PREFERENCES
            SharedPreferences preferences = getSharedPreferences(BreathePreferencesKey, 0);
            breatheToggled = preferences.getBoolean(breatheToggleString, breatheToggled);
            interval = preferences.getInt(breatheIntervalString, interval);
            persistence = preferences.getBoolean(breathePersistenceString, persistence);
            log("Read Preferences :"+
                    "\nMainSwitch : "+String.valueOf(breatheToggled) +
                    "\nInterval   : "+String.valueOf(interval) +
                    "\nPersistance: "+String.valueOf(persistence) +
                    "\nAutoCancel : "+String.valueOf(!persistence)
            );
    
            trace("Splash created, going to Main in 1 sec");
            //GO TO MAIN ACTIVITY AFTER DELAY
            new Handler().postDelayed(new Runnable() {
                @Override
                public void run() {
                    goToMain();
                }
            }, 1000);
        }
    
        //    public void goToMain(View view){ goToMain();}
        private void goToMain() {
            startActivity((new Intent(SplashScreen.this, MainActivity.class))
                    //ALL LOADED DATA TO BE PASSED TO MAIN CLASS AS INTENT
                    .putExtra(breatheToggleString, breatheToggled)
                    .putExtra(breatheIntervalString, interval)
                    .putExtra(breathePersistenceString, persistence)
            );
            finish();
        }
    }
    
    MainActivity.java>

    package com.example.breathe;
    
    import androidx.appcompat.app.AppCompatActivity;
    import androidx.appcompat.app.AppCompatDelegate;
    
    import android.annotation.SuppressLint;
    import android.app.AlarmManager;
    import android.app.PendingIntent;
    import android.content.Intent;
    import android.content.SharedPreferences;
    import android.media.AudioManager;
    import android.os.Build;
    import android.os.Bundle;
    import android.os.VibrationEffect;
    import android.os.Vibrator;
    import android.view.View;
    import android.widget.CompoundButton;
    import android.widget.SeekBar;
    import android.widget.Switch;
    import android.widget.TextView;
    import android.widget.ToggleButton;
    
    import static com.example.breathe.SplashScreen.TESTING;
    import static com.example.breathe.SplashScreen.log;
    import static com.example.breathe.SplashScreen.trace;
    
    public class MainActivity extends AppCompatActivity {
    
        public static boolean toggleState, persistence;
        private int interval;
        private SeekBar intervalBar;
        private ToggleButton toggleButton;
        private TextView intervalText;
        private Switch persistenceSwitch;
        //Intent to BroadCast liSTENER
        PendingIntent calltoBroadcastListener;
        //ALARM MANAGER
        AlarmManager AM;
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            trace("Main destroyed");
        }
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
            toggleButton = findViewById(R.id.toggleButton);
            intervalText = findViewById(R.id.intervalValue);
            intervalBar = findViewById(R.id.intervalBar);
            persistenceSwitch = findViewById(R.id.persistenceSwitch);
    
            trace("Main created");
            //OBTAINING DATA FROM INTENT, WHICH COMES FROM SHAREDPREFERENCES LOADED IN THE SPLASH ACTIVITY
            Intent intentData = getIntent();
            toggleState = intentData.getBooleanExtra(SplashScreen.breatheToggleString, SplashScreen.breatheToggled);
            toggleBreatheSwitch(toggleState);
            interval = intentData.getIntExtra(SplashScreen.breatheIntervalString, SplashScreen.interval);
            setInterval();
            intervalBar.setOnSeekBarChangeListener(seekBarChangeListener);
            persistence = intentData.getBooleanExtra(SplashScreen.breathePersistenceString, SplashScreen.persistence);
            persistenceSwitch.setChecked(!persistence);
            persistenceSwitch.setOnCheckedChangeListener(switchChangeListener);
    
            calltoBroadcastListener = PendingIntent.getBroadcast(
                    this,
                    1,
                    new Intent(this, BreathBroadcastReceiver.class),
                    PendingIntent.FLAG_UPDATE_CURRENT
            );
            AM = (AlarmManager) getSystemService(ALARM_SERVICE);
        }
    
        Switch.OnCheckedChangeListener switchChangeListener = new Switch.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
                if (compoundButton.getId() == R.id.persistenceSwitch) {
                    persistence = !b;
    
                    //set state to Shared Preferences
                    SharedPreferences.Editor preferences = getSharedPreferences(SplashScreen.BreathePreferencesKey, 0).edit();
                    preferences.putBoolean(SplashScreen.breathePersistenceString, persistence);
                    preferences.apply();
    
                    log("Saved preference persistence : " + persistence + ", AutoCancel : " + !persistence);
                }
            }
        };
    
        SeekBar.OnSeekBarChangeListener seekBarChangeListener = new SeekBar.OnSeekBarChangeListener() {
            @SuppressLint("SetTextI18n")
            @Override
            public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
                switch (seekBar.getId()){
                    case R.id.intervalBar:
                        setInterval(i);
                        vibrate(30);
                    default:
                }
            }
    
            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {}
    
            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {
                toggleBreatheSwitch(false);
                log("Saved Prefereces : interval : "+interval);
                SharedPreferences.Editor preferences = getSharedPreferences(SplashScreen.BreathePreferencesKey, 0).edit();
                preferences.putInt(SplashScreen.breatheIntervalString, (seekBar.getProgress()+1)*15);
                preferences.apply();
            }
        };
    
        @SuppressLint("ShortAlarm")
        private void setAlarm(){
            if (AM != null) {
                if (!TESTING)AM.setInexactRepeating(
                        AlarmManager.ELAPSED_REALTIME_WAKEUP,
                        0,
                        1000*60*interval,
                        calltoBroadcastListener
                );
                else AM.setRepeating(
                        AlarmManager.ELAPSED_REALTIME_WAKEUP, 0, 1000*60*1, calltoBroadcastListener);
                log("Alarm Set");
            } else log("Alarm is NULL");
        }
    
        private void toggleBreatheSwitch(boolean thetoggleState){
            toggleState = thetoggleState;
    
            //set toggle state to shared preferences;
            toggleButton.setChecked(toggleState);
            SharedPreferences.Editor preferences = getSharedPreferences(SplashScreen.BreathePreferencesKey, 0).edit();
            preferences.putBoolean(SplashScreen.breatheToggleString, toggleState);
            preferences.apply();
            log("Saved preferences : MainSwitch : "+ toggleState);
    
            //set changes to UI
            if (toggleState){ //REMINDER ON
                toggleButton.setTextColor(getResources().getColor(R.color.colorAccent));
                setAlarm();
            } else { //REMINDER OFF
                toggleButton.setTextColor(getResources().getColor(R.color.colorWhite));
                if (AM != null) AM.cancel(calltoBroadcastListener);
                log("Alarms Revoked");
            }
            vibrate(50);
        }
    
        public void toggleBreatheSwitch(View view) {
            //dummy function to handle calls from UI
            toggleBreatheSwitch(((ToggleButton)view).isChecked());
        }
        private void vibrate(int mSecs){
            try{ //To avoid vibrating when device is in total silence
                if (((AudioManager)getSystemService(AUDIO_SERVICE)).getRingerMode() == AudioManager.RINGER_MODE_SILENT) return;
            } catch (Exception ignore){}
    
            Vibrator vibe = (Vibrator) getSystemService(VIBRATOR_SERVICE);
            if ((vibe != null) && (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O))
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
                    vibe.vibrate(VibrationEffect.createOneShot(mSecs, VibrationEffect.EFFECT_TICK));
                else
                    vibe.vibrate(mSecs);
        }
    
        private void setInterval(){
            //Function to update UI - set intervalText and intervalBar values
            setInterval(interval/15 - 1);
            intervalBar.setProgress(interval/15 - 1);
        }
        @SuppressLint("SetTextI18n")
        private void setInterval(int seekbarValue){
            //Function to update UI - set the intervalText
            int hours, minutes;
            interval = (seekbarValue+1)*15;
            hours = interval/60;
            minutes = interval%60;
            if (hours != 0 ) intervalText.setText(hours + "Hr ");
            if (minutes != 0)
                if (hours != 0)
                    intervalText.setText(intervalText.getText().toString() + minutes +"min");
                else intervalText.setText(minutes +"min");
        }
    }
    
    BreathBroadcastReceiver.java>

    package com.example.breathe;
    
    import android.app.NotificationChannel;
    import android.app.NotificationManager;
    import android.content.BroadcastReceiver;
    import android.content.Context;
    import android.content.Intent;
    import android.media.AudioAttributes;
    import android.net.Uri;
    import android.os.Build;
    
    import androidx.core.app.NotificationCompat;
    
    import static com.example.breathe.SplashScreen.log;
    import static com.example.breathe.SplashScreen.trace;
    
    public class BreathBroadcastReceiver extends BroadcastReceiver {
    
    
        @Override
        public void onReceive(Context context, Intent intent) {
            trace("Broadcast Receiver received, sending notification");
            sendBreatheNotification(context);
        }
    
        public void sendBreatheNotification(Context context) {
            String NotificationChannelID = "Channel001";
            NotificationManager notifier = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
    
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && notifier != null) {
                NotificationChannel chan = new NotificationChannel (
                        NotificationChannelID,
                        "Primary Breathe Reminders",
                        NotificationManager.IMPORTANCE_DEFAULT);
                chan.setSound(
                        Uri.parse("android.resource://" + context.getPackageName() + "/" + R.raw.m),
                        new AudioAttributes.Builder()
                                .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
                                .setUsage(AudioAttributes.USAGE_ALARM)
                                .build()
                );
                notifier.createNotificationChannel(chan);
            }
    
            if (notifier != null){
                NotificationCompat.Builder nBuilder = new NotificationCompat.Builder(context, NotificationChannelID)
                        .setAutoCancel(true)
                        .setSmallIcon(R.drawable.ic_lungs)
                        .setContentTitle("Breathe")
                        .setContentText("Don't Forget to Breath Deep.")
                        .setContentInfo("SOME INFO");
    
    //                .setSubText("some sub text as well")
                if (!MainActivity.persistence) nBuilder.setTimeoutAfter(1000*10);
    
                notifier.notify(1, nBuilder.build());
                log("Breath Notification sent");
            } else log("Notifier null, Notification not displayed");
        }
    }
    
    manifest>
    
    MainActivitylayout>

    <?xml version="1.0" encoding="utf-8"?>
    <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:padding="18dp"
        tools:context=".MainActivity">
    
        <androidx.appcompat.widget.AppCompatToggleButton
            android:id="@+id/toggleButton"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:checked="true"
            android:onClick="toggleBreatheSwitch"
            android:padding="24dp"
            android:textStyle="bold"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent" />
    
        <androidx.appcompat.widget.AppCompatSeekBar
            android:id="@+id/intervalBar"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginBottom="32dp"
            android:max="15"
            android:progress="9"
            app:layout_constraintBottom_toTopOf="@+id/toggleButton"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent" />
    
        <com.google.android.material.textview.MaterialTextView
            android:id="@+id/intervalText"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginBottom="8dp"
            android:text="@string/reminder_interval"
            android:textAppearance="@style/TextAppearance.AppCompat.Medium"
            app:layout_constraintBottom_toTopOf="@+id/intervalBar"
            app:layout_constraintStart_toStartOf="parent" />
    
        <com.google.android.material.textview.MaterialTextView
            android:id="@+id/intervalValue"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginStart="32dp"
            app:layout_constraintBaseline_toBaselineOf="@+id/intervalText"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toEndOf="@+id/intervalText" />
    
        <Switch
            android:id="@+id/persistenceSwitch"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginBottom="32dp"
            android:checked="true"
            android:text="@string/persistence_text"
            android:textOff="disabled"
            android:textOn="enabled"
            app:layout_constraintBottom_toTopOf="@+id/intervalText"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent" />
    
        <com.google.android.material.textview.MaterialTextView
            android:id="@+id/voiceText"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginBottom="8dp"
            android:text="Notification Voice"
            android:textAppearance="@style/TextAppearance.AppCompat.Medium"
            app:layout_constraintBottom_toTopOf="@+id/radioGroup"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent" />
    
        <RadioGroup
            android:id="@+id/radioGroup"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginBottom="32dp"
            android:orientation="vertical"
            android:gravity="fill"
            app:layout_constraintBottom_toTopOf="@+id/persistenceSwitch"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent">
    
            <com.google.android.material.radiobutton.MaterialRadioButton
                android:id="@+id/radioButton"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="Male" />
    
            <com.google.android.material.radiobutton.MaterialRadioButton
                android:id="@+id/radioButton2"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="Female" />
        </RadioGroup>
    
    </androidx.constraintlayout.widget.ConstraintLayout>
    

    您可能会看到这个讨厌的、长期存在的Android bug:

    要进行检查,请在设备上安装应用程序,然后关闭应用程序(设置->应用程序->应用程序->强制退出),然后点击主屏幕上的图标启动应用程序,查看其现在是否正常运行

    <?xml version="1.0" encoding="utf-8"?>
    <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:padding="18dp"
        tools:context=".MainActivity">
    
        <androidx.appcompat.widget.AppCompatToggleButton
            android:id="@+id/toggleButton"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:checked="true"
            android:onClick="toggleBreatheSwitch"
            android:padding="24dp"
            android:textStyle="bold"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent" />
    
        <androidx.appcompat.widget.AppCompatSeekBar
            android:id="@+id/intervalBar"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginBottom="32dp"
            android:max="15"
            android:progress="9"
            app:layout_constraintBottom_toTopOf="@+id/toggleButton"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent" />
    
        <com.google.android.material.textview.MaterialTextView
            android:id="@+id/intervalText"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginBottom="8dp"
            android:text="@string/reminder_interval"
            android:textAppearance="@style/TextAppearance.AppCompat.Medium"
            app:layout_constraintBottom_toTopOf="@+id/intervalBar"
            app:layout_constraintStart_toStartOf="parent" />
    
        <com.google.android.material.textview.MaterialTextView
            android:id="@+id/intervalValue"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginStart="32dp"
            app:layout_constraintBaseline_toBaselineOf="@+id/intervalText"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toEndOf="@+id/intervalText" />
    
        <Switch
            android:id="@+id/persistenceSwitch"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginBottom="32dp"
            android:checked="true"
            android:text="@string/persistence_text"
            android:textOff="disabled"
            android:textOn="enabled"
            app:layout_constraintBottom_toTopOf="@+id/intervalText"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent" />
    
        <com.google.android.material.textview.MaterialTextView
            android:id="@+id/voiceText"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginBottom="8dp"
            android:text="Notification Voice"
            android:textAppearance="@style/TextAppearance.AppCompat.Medium"
            app:layout_constraintBottom_toTopOf="@+id/radioGroup"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent" />
    
        <RadioGroup
            android:id="@+id/radioGroup"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginBottom="32dp"
            android:orientation="vertical"
            android:gravity="fill"
            app:layout_constraintBottom_toTopOf="@+id/persistenceSwitch"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent">
    
            <com.google.android.material.radiobutton.MaterialRadioButton
                android:id="@+id/radioButton"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="Male" />
    
            <com.google.android.material.radiobutton.MaterialRadioButton
                android:id="@+id/radioButton2"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="Female" />
        </RadioGroup>
    
    </androidx.constraintlayout.widget.ConstraintLayout>