我试图写一个应用程序,做一些具体的时候,它被带回前台后一段时间。是否有一种方法可以检测应用程序是被发送到后台还是被带到前台?
当前回答
考虑使用onUserLeaveHint。它只会在应用进入后台时被调用。onPause会有一些极端情况需要处理,因为它可以被用于其他原因;例如,如果用户在你的应用程序中打开另一个活动,比如你的设置页面,你的主活动的onPause方法将被调用,即使它们仍然在你的应用程序中;当你可以简单地使用onUserLeaveHint回调函数来做你所要求的事情时,跟踪正在进行的事情将导致错误。
当调用on UserLeaveHint时,你可以设置一个boolean inBackground标志为true。当onResume被调用时,如果inBackground标志被设置,只假设你回到前台。这是因为onResume也将被调用在你的主要活动,如果用户只是在你的设置菜单,从来没有离开应用程序。
Remember that if the user hits the home button while in your settings screen, onUserLeaveHint will be called in your settings activity, and when they return onResume will be called in your settings activity. If you only have this detection code in your main activity you will miss this use case. To have this code in all your activities without duplicating code, have an abstract activity class which extends Activity, and put your common code in it. Then each activity you have can extend this abstract activity.
例如:
public abstract AbstractActivity extends Activity {
private static boolean inBackground = false;
@Override
public void onResume() {
if (inBackground) {
// You just came from the background
inBackground = false;
}
else {
// You just returned from another activity within your own app
}
}
@Override
public void onUserLeaveHint() {
inBackground = true;
}
}
public abstract MainActivity extends AbstractActivity {
...
}
public abstract SettingsActivity extends AbstractActivity {
...
}
其他回答
如果你的应用由多个活动和/或堆叠的活动组成,就像一个标签栏小部件,那么覆盖onPause()和onResume()将不起作用。例如,当启动一个新的活动,当前的活动将得到暂停之前,新的一个被创建。当完成一个活动(使用“后退”按钮)时,也同样适用。
我发现有两种方法似乎很有效。
第一个需要GET_TASKS权限,由一个简单的方法组成,通过比较包名来检查设备上运行最多的活动是否属于应用程序:
private boolean isApplicationBroughtToBackground() {
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<RunningTaskInfo> tasks = am.getRunningTasks(1);
if (!tasks.isEmpty()) {
ComponentName topActivity = tasks.get(0).topActivity;
if (!topActivity.getPackageName().equals(context.getPackageName())) {
return true;
}
}
return false;
}
这种方法是在Droid-Fu(现在称为Ignition)框架中发现的。
我自己实现的第二个方法不需要GET_TASKS权限,这很好。相反,它的实现有点复杂。
在MainApplication类中,有一个变量用于跟踪应用程序中正在运行的活动的数量。在onResume()中为每个活动增加变量,在onPause()中减少变量。
当正在运行的activity数量达到0时,如果满足以下条件,应用程序将被放入后台:
正在暂停的活动没有结束(使用了“后退”按钮)。这可以通过使用activity.isFinishing()方法来完成。 没有启动一个新活动(相同的包名)。你可以重写startActivity()方法来设置一个变量来指示这一点,然后在onPostResume()中重置它,这是创建/恢复活动时运行的最后一个方法。
当您可以检测到应用程序已经退出到后台时,当它被带回前台时也很容易检测到。
通过使用下面的代码,我能够得到我的应用程序的前台或后台状态。
更多关于它的工作细节,强文本点击这里
import android.content.ComponentCallbacks2;
import android.content.Context;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
private Context context;
private Toast toast;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
context = this;
}
private void showToast(String message) {
//If toast is already showing cancel it
if (toast != null) {
toast.cancel();
}
toast = Toast.makeText(context, message, Toast.LENGTH_SHORT);
toast.show();
}
@Override
protected void onStart() {
super.onStart();
showToast("App In Foreground");
}
@Override
public void onTrimMemory(int level) {
super.onTrimMemory(level);
if (level == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {
showToast("App In Background");
}
}
}
这些答案似乎不正确。当另一个活动开始和结束时,也会调用这些方法。你能做的是保留一个全局标志(是的,全局不好:),并在每次启动一个新活动时将其设置为true。在每个活动的onCreate中将其设置为false。然后,在onPause中检查这个标志。如果为假,你的应用就会进入后台,或者被杀死。
我知道有点晚了,但我认为所有这些答案都有一些问题,而我这样做了,这是完美的。
创建一个活动生命周期回调,如下所示:
class ActivityLifeCycle implements ActivityLifecycleCallbacks{
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
}
@Override
public void onActivityStarted(Activity activity) {
}
Activity lastActivity;
@Override
public void onActivityResumed(Activity activity) {
//if (null == lastActivity || (activity != null && activity == lastActivity)) //use this condition instead if you want to be informed also when app has been killed or started for the first time
if (activity != null && activity == lastActivity)
{
Toast.makeText(MyApp.this, "NOW!", Toast.LENGTH_LONG).show();
}
lastActivity = activity;
}
@Override
public void onActivityPaused(Activity activity) {
}
@Override
public void onActivityStopped(Activity activity) {
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
@Override
public void onActivityDestroyed(Activity activity) {
}
}
然后像下面这样在你的应用类上注册它:
public class MyApp extends Application {
@Override
public void onCreate() {
super.onCreate();
registerActivityLifecycleCallbacks(new ActivityLifeCycle());
}
编辑2:我在下面写的东西实际上是行不通的。谷歌拒绝了一个包含对ActivityManager.getRunningTasks()调用的应用程序。从文档中可以明显看出,这个API仅用于调试和开发。一旦我有时间更新下面的GitHub项目,我就会更新这篇文章,使用一个使用计时器的新方案,几乎一样好。
编辑1:我已经写了一篇博客文章,并创建了一个简单的GitHub存储库,使这非常容易。
公认的和最高评价的答案都不是最好的方法。排名最高的答案是isApplicationBroughtToBackground()的实现,它不处理应用程序的主活动屈服于同一个应用程序中定义的活动,但它有不同的Java包的情况。我想到了一种方法,在这种情况下行得通。
在onPause()中调用它,它会告诉你你的应用程序是否因为另一个应用程序已经启动而进入后台,或者用户已经按下了home键。
public static boolean isApplicationBroughtToBackground(final Activity activity) {
ActivityManager activityManager = (ActivityManager) activity.getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningTaskInfo> tasks = activityManager.getRunningTasks(1);
// Check the top Activity against the list of Activities contained in the Application's package.
if (!tasks.isEmpty()) {
ComponentName topActivity = tasks.get(0).topActivity;
try {
PackageInfo pi = activity.getPackageManager().getPackageInfo(activity.getPackageName(), PackageManager.GET_ACTIVITIES);
for (ActivityInfo activityInfo : pi.activities) {
if(topActivity.getClassName().equals(activityInfo.name)) {
return false;
}
}
} catch( PackageManager.NameNotFoundException e) {
return false; // Never happens.
}
}
return true;
}
推荐文章
- 警告:API ' variable . getjavacompile()'已过时,已被' variable . getjavacompileprovider()'取代
- 安装APK时出现错误
- 碎片中的onCreateOptionsMenu
- TextView粗体通过XML文件?
- 如何使线性布局的孩子之间的空间?
- DSL元素android.dataBinding。enabled'已过时,已被'android.buildFeatures.dataBinding'取代
- ConstraintLayout:以编程方式更改约束
- PANIC: AVD系统路径损坏。检查ANDROID_SDK_ROOT值
- 如何生成字符串类型的buildConfigField
- Recyclerview不调用onCreateViewHolder
- Android API 21工具栏填充
- Android L中不支持操作栏导航模式
- 如何在TextView中添加一个子弹符号?
- PreferenceManager getDefaultSharedPreferences在Android Q中已弃用
- 在Android Studio中创建aar文件