Android:APP长时间后台,再打开崩溃的问题

本文介绍了一种解决Android应用在长时间后台运行后重新打开时崩溃的问题。通过在activity加载前检查程序状态,若被系统回收,则重启应用,避免数据丢失引起的异常。采用AppStatusManager单例模式控制状态,修改MainActivity启动模式为singleTask,并在BaseActivity中统一处理回收状态。

Android:APP长时间后台,再打开崩溃的问题

导致原因

后台时间过长,activity被回收或其它数据被回收。
当调至前台时,或重新打开时,需要使用之前的数据,所以,就报异常了。

解决办法

网上大多解决这种问题的做法是使用onSaveInstanceState和onRestoreInstanceState来保存UI状态的,基本上就是在按home键或者其他情况的时候存储数据,然后再次点开APP的时候读取bundle的数据。不过一般一个项目都有很多页面,存储数据这种方法就会很麻烦。

这里介绍个简单粗暴的方法:activity加载布局之前判断当前程序是否被系统回收,如果是则重新启动app。

首先新建AppStatus 类

public class AppStatus {
    public static final int STATUS_RECYVLE =-1; //被回收
    public static final int STATUS_NORMAL=1;    //正常
}

新建AppStatusManager类控制状态

public class AppStatusManager {
    public int appStatus = AppStatus.STATUS_RECYCLE;    //APP状态 初始值为不在前台状态

    private static AppStatusManager appStatusManager;

    private AppStatusManager(){}

	//单例模式
    public static AppStatusManager getInstance() {
        if (appStatusManager == null) {
            appStatusManager = new AppStatusManager();
        }
        return appStatusManager;
    }

    public int getAppStatus() {
        return appStatus;
    }

    public void setAppStatus(int appStatus) {
        this.appStatus = appStatus;
    }
}

闪屏页修改状态

    public class SplashActivity extends AppCompatActivity {

   	private ImageView sp;
   	
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.startup);
        
        sp=(ImageView) findViewById(R.id.imageView);
        //AlphaAnimation anima = new AlphaAnimation(0.3f, 1.0f);
        //anima.setDuration(2500);// 设置动画显示时间
        //sp.startAnimation(anima);
        //anima.setAnimationListener( new MyAnimationListener());
        
        sp.postDelayed(new Runnable() {
            @Override
            public void run() {
                Intent intent = new Intent(SplashActivity.this, MainActivity.class);
            	//app状态改为正常
            	AppStatusManager.getInstance().setAppStatus(AppStatus.STATUS_NORMAL);
            	startActivity(intent);
            	finish();
            }
        }, 2500);
    }
}

清单文件中MainActivity的启动模式要设为singleTask

<activity 
		android:name=".MainActivity"
		android:launchMode="singleTask" />

MainActivity:

public class MainActivity extends AppCompatActivity {
	@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (AppStatusManager.getInstance().getAppStatus() == AppStatus.STATUS_RECYCLE){
            //跳到闪屏页
            Intent intent = new Intent(this, SplashActivity.class);
            startActivity(intent);
            finish();
            return;
        }
        setContentView(R.layout.activity_main);
        Button bt = (Button) findViewById(R.id.bt);
        bt.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(MainActivity.this, TestActivity.class);
            	startActivity(intent);
            }
        });
    }
}

新建一个BaseActivity继承AppCompatActivity,其他Activity继承BaseActivity

public class BaseActivity extends AppCompatActivity {
	@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (AppStatusManager.getInstance().getAppStatus() == AppStatus.STATUS_RECYCLE){
            //跳到MainActivity,让MainActivity也finish掉
            Intent intent = new Intent(this, MainActivity.class);
            startActivity(intent);
            finish();
            return;
        }
    }
}
public class TestActivity extends BaseActivity {
	@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test);
    }
}
### 原因 - **系统内存管理**:Android 系统为了保证前台应用的流畅运行,会根据内存使用情况清理后台服务。当系统内存不足时,优先级较低的后台 Service 会被优先杀死以释放资源。 - **系统更新与限制**:随着 Android 系统不断更新,对后台服务的限制越来越严格。例如 Android 7 引入了后台执行限制和电量优化等策略,不符合规则的后台 Service 可能会被系统强制停止。 - **代码异常**:软件自身代码存在 bug,如空指针异常、内存泄漏等,会导致服务运行过程中报错崩溃,进而被系统杀死。 - **第三方软件干扰**:部分第三方安全软件或内存管理软件会对后台服务进行监控和清理,可能误判软件后台服务为不必要进程而将其杀死。 ### 解决方法 - **使用前台服务**:将后台服务转换为前台服务(ForegroundService),让服务一直以前台任务的方式运行。可在服务的 `onCreate` 方法中实现前台服务,此方法需发送一个通知栏,让用户知道服务在运行,提高服务的优先级,降低被系统杀死的概率。例如: ```java import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationManager; import android.app.PendingIntent; import android.app.Service; import android.content.Intent; import android.os.Build; import android.os.IBinder; import androidx.core.app.NotificationCompat; public class MyForegroundService extends Service { private static final int NOTIFICATION_ID = 1; private static final String CHANNEL_ID = "MyChannel"; @Override public void onCreate() { super.onCreate(); createNotificationChannel(); Notification notification = createNotification(); startForeground(NOTIFICATION_ID, notification); } private void createNotificationChannel() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { NotificationChannel channel = new NotificationChannel( CHANNEL_ID, "My Channel", NotificationManager.IMPORTANCE_DEFAULT ); NotificationManager manager = getSystemService(NotificationManager.class); manager.createNotificationChannel(channel); } } private Notification createNotification() { Intent notificationIntent = new Intent(this, MainActivity.class); PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0); return new NotificationCompat.Builder(this, CHANNEL_ID) .setContentTitle("Foreground Service") .setContentText("Running...") .setSmallIcon(R.drawable.ic_notification) .setContentIntent(pendingIntent) .build(); } @Override public IBinder onBind(Intent intent) { return null; } } ``` - **白名单保活**:将应用程序或 Service 加入到系统的白名单中,使其在后台保持运行状态。不过不同手机厂商的白名单设置方式可能不同 [^1]。 - **优化代码**:仔细检查软件代码,修复可能存在的空指针异常、内存泄漏等问题。可使用 Android Studio 自带的内存分析工具(如 Memory Profiler)来检测内存泄漏情况。 - **适配系统限制**:遵循 Android 系统的后台执行限制和电量优化规则,合理安排后台任务的执行时间和频率。例如,使用 `JobScheduler` 来安排后台任务,确保在系统允许的情况下执行。 ```java import android.app.job.JobInfo; import android.app.job.JobScheduler; import android.content.ComponentName; import android.content.Context; public class JobSchedulerHelper { private static final int JOB_ID = 1; public static void scheduleJob(Context context) { ComponentName serviceComponent = new ComponentName(context, MyJobService.class); JobInfo.Builder builder = new JobInfo.Builder(JOB_ID, serviceComponent); builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY); builder.setRequiresDeviceIdle(false); builder.setRequiresCharging(false); JobScheduler jobScheduler = context.getSystemService(JobScheduler.class); jobScheduler.schedule(builder.build()); } } ``` - **处理第三方软件干扰**:在相关第三方软件的设置中,将该软件加入白名单,避免被误清理。例如在 MIUI 系统中,需在自启动管理里允许软件自启动,否则相关后台服务策略可能无法生效。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值