当前位置:  开发笔记 > 编程语言 > 正文

清算意图

如何解决《清算意图》经验,为你挑选了6个好方法。

我的Android应用程序被传递信息的意图调用(状态栏中的pendingintent).

当我按下主页按钮并通过按住主页按钮重新打开我的应用程序时,它再次调用了意图,并且仍然存在相同的附加功能.

    @Override
    public void onSaveInstanceState(Bundle savedInstanceState) {
      super.onSaveInstanceState(savedInstanceState);
    }
    @Override
    public void onRestoreInstanceState(Bundle savedInstanceState) {
      super.onRestoreInstanceState(savedInstanceState);
    }

这是不像它应该运行的代码

    String imgUrl;
    Bundle extras = this.getIntent().getExtras();


    if(extras != null){
        imgUrl = extras.getString("imgUrl");
        if( !imgUrl.equals(textView01.getText().toString()) ){

            imageView.setImageDrawable( getImageFromUrl( imgUrl ) );
            layout1.setVisibility(0);
            textView01.setText(imgUrl);//textview to hold the url

        }

    }

我的意图是:

public void showNotification(String ticker, String title, String message, 
    String imgUrl){
    String ns = Context.NOTIFICATION_SERVICE;
    NotificationManager mNotificationManager = 
        (NotificationManager) getSystemService(ns);
    int icon = R.drawable.icon;        // icon from resources
    long when = System.currentTimeMillis();         // notification time
    CharSequence tickerText = ticker;              // ticker-text

    //make intent
    Intent notificationIntent = new Intent(this, activity.class);
    notificationIntent.putExtra("imgUrl", imgUrl);
    notificationIntent.setFlags(
        PendingIntent.FLAG_UPDATE_CURRENT | 
        PendingIntent.FLAG_ONE_SHOT);
    PendingIntent contentIntent = 
        PendingIntent.getActivity(this, 0, 
        notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT | 
        PendingIntent.FLAG_ONE_SHOT);

    //make notification
    Notification notification = new Notification(icon, tickerText, when);
    notification.setLatestEventInfo(this, title, message, contentIntent);
    //flags
    notification.flags = Notification.FLAG_SHOW_LIGHTS | 
        Notification.FLAG_ONGOING_EVENT | 
        Notification.FLAG_ONLY_ALERT_ONCE | 
        Notification.FLAG_AUTO_CANCEL;
    //sounds
    notification.defaults |= Notification.DEFAULT_SOUND;
    //notify
    mNotificationManager.notify(1, notification);
}

有没有办法清除意图或检查它是否曾被使用过?



1> Maks..:
更新:

当我5年前第一次写这篇文章时,我没有意识到这个答案会被提到这么多!

我要澄清一点,根据@ tato-rodrigo的回答,这不会帮助你在某些情况下检测已经处理过的意图.

另外我应该指出我把"明确"放在引号中是有原因的 - 你并没有真正通过这样做清除意图,你只是使用额外的删除作为一个标志,这个意图已被活动看到.


我有完全相同的问题.

以上回答让我走上正轨,我发现更简单的解决方案,使用:

getIntent().removeExtra("key"); 

方法调用"清除"意图.

自从一年前被问到这个问题以后,它的回答有点迟了,但希望这对未来的其他人有所帮助.


@Maks我可能错了,但我认为这在以下情况下不起作用:1)通过通知打开活动; 2)按后退按钮完成活动; 3)通过历史记录(最近的应用程序)重新打开活动.另一种情况是,由于缺乏资源,系统会杀死应用程序(在开发人员选项下启用"不要保留活动",之后只需按回原点,然后再从历史记录中再次打开活动).我发布了我正在使用的解决方案.如果你能评论这个会很好.
removeExtra()方法不采用String参数吗?像这样的getIntent().removeExtra("String");
不幸的是,它对我们不起作用.我们发现启动一个新活动反过来启动初始活动会导致OnNewIntent再次以相同的意图启动.

2> tato.rodrigo..:

编辑:我正在编辑发布我正在使用的完整解决方案.

如果问题是"当活动从历史记录(最近的应用程序)启动时不执行某些代码",则此解决方案将起作用.

首先,boolean在你的声明中Activity指示是否Intent已经消耗了:

    private boolean consumedIntent;

然后,使用onSaveInstanceStateonCreate方法安全地存储和恢复此值,以处理配置更改以及系统Activity在进入后台时可能会将其杀死的情况.

    private final String SAVED_INSTANCE_STATE_CONSUMED_INTENT = "SAVED_INSTANCE_STATE_CONSUMED_INTENT";

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putBoolean(SAVED_INSTANCE_STATE_CONSUMED_INTENT, consumedIntent);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //set content view ...

        if( savedInstanceState != null ) {
            consumedIntent = savedInstanceState.getBoolean(SAVED_INSTANCE_STATE_CONSUMED_INTENT);
        }

        //other initializations
    }

现在,检查您是否可以在onResume方法下运行代码.

    @Override
    protected void onResume() {
        super.onResume();

        //check if this intent should run your code
        //for example, check the Intent action
        boolean shouldThisIntentTriggerMyCode = [...];
        Intent intent = getIntent();
        boolean launchedFromHistory = intent != null ? (intent.getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) != 0 : false;
        if( !launchedFromHistory && shouldThisIntentTriggerMyCode && !consumedIntent ) {
            consumedIntent = true;
            //execute the code that should be executed if the activity was not launched from history
        }
    }

此外,如果您Activity的配置为singleTop,则应在Intent交付新标志时重置标记.

    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        setIntent(intent);
        consumedIntent = false;
    }


非常感谢!我帮助了这个代码`(intent.getFlags()&Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY)`所以现在我可以弄清楚活动的开始是从历史开始的,我可以忽略我的额外内容.

3> Slynk..:

Maks的答案适用于清除额外的:

    getIntent().removeExtra("key"); 

另一个有用的命令是:

    getIntent().setAction("");

您还可以通过调用标记意图:

    getIntent().putExtra("used", true);

然后只需检查值.



4> B.B...:

当我们从历史(最近的应用程序)启动Android应用程序时,可以使用主要三种不同的Intent标志启动应用程序.

    FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY
    这是从最小化的应用程序的历史记录启动活动时(长按主页键).
    常数值:1048576(0x00100000)

    FLAG_ACTIVITY_NEW_TASK
    这是通过"单击应用程序图标"或通过" 意图过滤器 "启动活动的时间.这里的活动将成为此历史堆栈上新任务的开始.
    常数值:268435456(0x10000000)

    FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY | FLAG_ACTIVITY_NEW_TASK
    这是当按下后退按钮退出应用程序然后从历史记录(最近的应用程序)恢复时.
    常数值:269484032(0x10100000)

可以通过检索常量值 getIntent().getFlags()

在第三种情况下,Android从其内存重新加载最后的Intent值.因此,您的应用的intent(getIntent)将具有启动应用的最后一个意图的值.

实际上,应用应该表现得好像是一个新的发布,新的发布的意图值而不是上一次发布的意图值.如果通过单击应用程序图标启动应用程序,则可以看到此行为,它将永远不会具有旧的意图值.这是因为Android为此方案使用以下intent过滤器

 
        
        
 

但在第三种情况下(已退出的应用程序,是从最近的应用程序的历史记录启动),Android OS使用在退出之前启动应用程序的最后一个意图(通过按下后退按钮).所以你最终得到旧的意图值并且应用流程不合适.

删除意图是解决问题的一种方法,但它不能完全解决问题!随着Android OS从上次启动的应用程序重新加载Intent,而不是启动意图的最后一个实例.

避免这种情况发生的一种干净方法是通过获取Intent类型来确定启动类型来处理它.

因此,在您LaunchActivity(这在清单中定义的意图过滤器中的一个),你可以在使用下面的代码onCreate(),onStart()onResume()方法.

if(getIntent().getFlags() == (Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY)) {
    //app is launched from recent apps after it was closed
        normalLaunch();
    } else {
        String intentAction = getIntent().getAction();
        String scheme = getIntent().getScheme();
        //app is launched via other means
        // URL intent scheme, Intent action etc
        if("https".equalsIgnoreCase(scheme)) {
            // URL intent for browser
        } else if("com.example.bb".equalsIgnoreCase(intentAction)) {
            // App launched via package name
        } else {
            // App was launched via Click on App Icon, or other means
            normalLaunch();
        }
    }

我认为normalLaunch(),不应该使用Intent中的参数; 否则你需要隔离并优化你的默认启动方法,不要使用Intent参数.



5> Mickey Tin..:
intent.replaceExtras(new Bundle());
intent.setAction("");
intent.setData(null);
intent.setFlags(0);


这应该是公认的答案.工作得很好!
在开发者选项上选中"不保留活动"时不起作用

6> Eugene Wechs..:

简短的回答是没有办法

答案很长.没有"一次性"的意图.从实验中可以看出,现代机器人最近的活动历史只不过是"意图历史".传递给活动的最新意图只是登录到系统,这就是交易.上面的人建议使用

setAction("")

但它不起作用,因为意图已经记录,直到你在onNewIntent()或onStart()方法中获取它.

我通过避免使用意图来解决问题.我的问题与作者发布的问题相似.我尝试通过通知区域中的控件实现应用程序的全局退出.它应该停止底层服务并关闭应用程序的所有活动.您可以在Waze应用程序中找到相同的行为.

算法:

    为通知控制创建PendingIntent,将"退出"操作传递给活动.但对于一个简单代理的特殊活动.

    代理活动onStart()代码解析intent,检查action并将某个模型的状态设置为"Exited".

    代理活动onStart()代码使用setIntent("")清除原始意图,然后通过调用startActivity(intent)将其转发到目标"Root"活动.

    代理活动onStart()代码调用finish().

    在目标活动的onStart()和onNewIntent()内部检查模型状态,如果它是"已退出"则调用finish()(在我的情况下也调用stopService()).

我希望这会对某人有所帮助,因为我没有在互联网上找到答案.

推荐阅读
小白也坚强_177
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有