web-dev-qa-db-ja.com

新しいインテントを作成するのではなく、通知インテントを再開する方法は?

ここにあるのは、ロードされると継続的な通知を自動的に表示する単純なwebviewアクティビティです。アイデアは、ドロップダウンメニューをプルダウンして選択することで、ユーザーがこのアクティビティから移動し、必要な画面からすばやくアクセスできることです。その後、必要なときにメニューボタンを押して終了を押すだけで通知を閉じることができます。その後、通知はクリアされます。これはすべて正常に動作します。ただし、通知が押されると、アクティビティの新しいインスタンスが開始されます。アクティビティがまだ破棄されていないかどうかを確認するために何を変更する必要がありますか?そのインスタンスをコールバックするだけで再開できますので、再びロードする必要がなく、スタックに別のアクティビティを追加する必要がありません。何か案は?どんな助けも大歓迎です。

package com.my.app;

import com.flurry.Android.FlurryAgent;

import Android.app.Activity;
import Android.app.Notification;
import Android.app.NotificationManager;
import Android.app.PendingIntent;
import Android.app.ProgressDialog;
import Android.content.Context;
import Android.content.Intent;
import Android.os.Bundle;
import Android.util.Log;
import Android.view.KeyEvent; 
import Android.view.Menu;
import Android.view.MenuInflater;
import Android.view.MenuItem;
import Android.webkit.CookieSyncManager;
import Android.webkit.WebView;
import Android.webkit.WebViewClient;
import Android.widget.Toast;

public class Chat extends Activity { 
    private ProgressDialog progressBar;
    public WebView webview;
    private static final String TAG = "Main";

    private NotificationManager mNotificationManager;
    private int SIMPLE_NOTFICATION_ID;

    @Override
    public void onStart() {
       super.onStart();
       CookieSyncManager.getInstance().sync();
       FlurryAgent.onStartSession(this, "H9QGMRC46IPXB43GYWU1");
    }

    public void onCreate(Bundle savedInstanceState) { 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.chat);

        mNotificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);

        final Notification notifyDetails = new Notification(R.drawable.chat_notification,"Chat Started",System.currentTimeMillis());

        notifyDetails.flags |= Notification.FLAG_ONGOING_EVENT;

        Context context = getApplicationContext();

        CharSequence contentTitle = "Chat";
        CharSequence contentText = "Press to return to chat";

        Intent notifyIntent = new Intent(context, Chat.class);

        PendingIntent intent =
        PendingIntent.getActivity(Chat.this, 0,
        notifyIntent, Android.content.Intent.FLAG_ACTIVITY_NEW_TASK);
        notifyDetails.setLatestEventInfo(context, contentTitle, contentText, intent);

        mNotificationManager.notify(SIMPLE_NOTFICATION_ID, notifyDetails);

        CookieSyncManager.createInstance(this);
        CookieSyncManager.getInstance().startSync();
        webview = (WebView) findViewById(R.id.webviewchat);
        webview.setWebViewClient(new chatClient());
        webview.getSettings().setJavaScriptEnabled(true);
        webview.getSettings().setPluginsEnabled(true);
        webview.loadUrl("http://google.com");

        progressBar = ProgressDialog.show(Chat.this, "", "Loading Chat...");  
    }

    private class chatClient extends WebViewClient { 
        @Override 
        public boolean shouldOverrideUrlLoading(WebView view, String url) {
            Log.i(TAG, "Processing webview url click...");
            view.loadUrl(url);
            return true;
        }

        public void onPageFinished(WebView view, String url) {
            Log.i(TAG, "Finished loading URL: " +url);
            if (progressBar.isShowing()) {
                progressBar.dismiss();
            }
        }
    }

    public boolean onKeyDown(int keyCode, KeyEvent event) { 
        if ((keyCode == KeyEvent.KEYCODE_BACK) && webview.canGoBack()) { 
            webview.goBack(); 
            return true; 
        }
        return super.onKeyDown(keyCode, event); 
    }

    @Override
    public boolean onCreateOptionsMenu (Menu menu) {
        super.onCreateOptionsMenu(menu);
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.chatmenu, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected (MenuItem item) {
        switch (item.getItemId()) {
            case R.id.home:
                Intent a = new Intent(this, Home.class);
                startActivity(a);
                return true;
            case R.id.closechat:
                mNotificationManager.cancel(SIMPLE_NOTFICATION_ID);
                Intent v = new Intent(this, Home.class);
                startActivity(v);
                return true;
        }
        return false;
    }

    public void onStop() {
       super.onStop();
       CookieSyncManager.getInstance().sync();
       FlurryAgent.onEndSession(this);
    }
}

@Commonsware

正しいことを確認するために、これはあなたが提案していたことですか?

私はこの行について少し心配していました、

PendingIntent.getActivity(Chat.this, 0, notifyIntent, SIMPLE_NOTFICATION_ID);

public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState);
    setContentView(R.layout.chat);

    mNotificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);

    final Notification notifyDetails = new Notification(R.drawable.chat_notification,"Chat Started",System.currentTimeMillis());

    notifyDetails.flags |= Notification.FLAG_ONGOING_EVENT;


    Context context = getApplicationContext();

    CharSequence contentTitle = "Chat";
    CharSequence contentText = "Press to return to chat";

    Intent notifyIntent = new Intent(context, Chat.class);

    PendingIntent intent =
    PendingIntent.getActivity(Chat.this, 0, notifyIntent, SIMPLE_NOTFICATION_ID);
    notifyDetails.setLatestEventInfo(context, contentTitle, contentText, intent);
    notifyIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);

    mNotificationManager.notify(SIMPLE_NOTFICATION_ID, notifyDetails);


    CookieSyncManager.createInstance(this);
    CookieSyncManager.getInstance().startSync();
    webview = (WebView) findViewById(R.id.webviewchat);
    webview.setWebViewClient(new chatClient());
    webview.getSettings().setJavaScriptEnabled(true);
    webview.getSettings().setPluginsEnabled(true);
    webview.loadUrl("http://google.com");

    progressBar = ProgressDialog.show(Chat.this, "", "Loading Chat...");        
}
39
brybam

ユーザーは、ドロップダウンメニューをプルダウンして選択することで、ユーザーがこのアクティビティから離れて、必要な画面からすばやくすばやくアクセスできるようにするという考え方です。

これをオプションにしてください。

ただし、通知が押されると、アクティビティの新しいインスタンスが開始されます。

それはデフォルトで起こります。

アクティビティがまだ破棄されていないかどうかを確認するために何を変更する必要がありますか?そのインスタンスをコールバックするだけで再開できますので、再びロードする必要がなく、スタックに別のアクティビティを追加する必要がありません。

_FLAG_ACTIVITY_NEW_TASK_を取り除きます。 notifyIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);を追加します- このサンプルプロジェクト を参照してください。

_Context context = getApplicationContext();
_

これをしないでください。 ActivityContextとして使用するだけです。

55
CommonsWare

これは通知を表示する私の方法です。それがあなたのお役に立てば幸いです。

private static void generateNotification(Context context, String message){
    Intent notificationIntent = new Intent(context, YOUR_ACTIVITY.class);
    notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
    PendingIntent intent = PendingIntent.getActivity(context, 0, notificationIntent, 0);

    NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(context)
        .setSmallIcon(R.drawable.ic_launcher)
        .setContentTitle(context.getString(R.string.app_name))
        .setContentIntent(intent)
        .setPriority(PRIORITY_HIGH) //private static final PRIORITY_HIGH = 5;
        .setContentText(message)
        .setAutoCancel(true)
        .setDefaults(Notification.DEFAULT_SOUND | Notification.DEFAULT_VIBRATE | Notification.DEFAULT_LIGHTS);
    NotificationManager mNotificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
    mNotificationManager.notify(0, mBuilder.build());
}
21
Pedro Romão

他の誰かが私と同じ困難を抱えている場合のために....

上記のすべてのコードを試してみましたが、成功していませんが、通知項目はアプリのまったく新しいインスタンスを起動し続けました。 (一度に1つのインスタンスのみを使用できるようにします。)最後に、他のスレッド( https://stackoverflow.com/a/20724199/4307281 )に気付きました。マニフェスト内:

Android:launchMode="singleInstance"

それをアプリケーションのメインアクティビティセクションの下のマニフェストに配置し、通知アイテムは既に進行中のインスタンスを再利用しました。

14
jkincali

解決策のどれも私のために働いたので、私は自分の道を見つけました。私のすべてのアクティビティは、BaseActivityから拡張されます。簡単な一連の手順に従って、プッシュ通知をクリックしてアプリケーションを再開します。

ステップ1:現在のアクティビティを記録する定数:

_public static Context currentContext;
_

ステップ2:BaseActivityによって拡張されたアクティビティのonCreate()またはonResume()

_currentContext = this;
_

ステップ3:通知を作成するときのIntent

_Class activity = BaseActivity.commonContext.getClass();
Intent intent = new Intent(this, activity);
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);

//FLAG_UPDATE_CURRENT is important
PendingIntent pendingIntent = PendingIntent.getActivity(this, (int)System.currentTimeMillis(), intent, PendingIntent.FLAG_UPDATE_CURRENT);
_
1
TharakaNirmana

マルチタスクアプリケーションでは、どの回答も機能しないことがわかりました。当然のことながら、Intent.FLAG_ACTIVITY_CLEAR_TOPとIntent.FLAG_ACTIVITY_SINGLE_TOPは、複数のタスクの場合にまったく同じ動作をしないようです。私のアプリケーションでは、複数のタスクルートアクティビティがあります。ある時点で、これらのタスクのいずれかで実行すべき作業があるという通知がユーザーに表示されます。 OPとは異なり、これらのタスクの1つに埋もれる可能性のある特定のアクティビティではなく、これらのタスクの1つに戻る必要があります。これは、他の人に役立つかもしれないという質問とよく似ていると思います。

私のソリューションは、現在のタスクを追跡する静的タスクID、保留中のインテントを処理するブロードキャストレシーバー、新しい使用許可タグ、ActivityManagerの簡単な使用で構成されています。

private static int taskID;

public static void setResumeTask(int tID)
{
    Log.e("TaskReturn", "Setting Task ID: " + tID);
    taskID = tID;
}

public static PendingIntent getResumeTask(Context appContext)
{
    return PendingIntent.getBroadcast(appContext, 0, new Intent(appContext, TaskReturn.class).putExtra(TaskReturn.EXTRA_TASK_ID, taskID), PendingIntent.FLAG_UPDATE_CURRENT);
}

public void onReceive(Context context, Intent intent)
{
    Log.e("TaskReturn", "Task Return!");
    if (intent.hasExtra(EXTRA_TASK_ID))
    {
        int taskToStart = intent.getIntExtra(EXTRA_TASK_ID, -1);
        Log.e("TaskReturn", "Returning To Task: " + taskToStart);
        ActivityManager activityManager = (ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE);
        List<ActivityManager.AppTask> allAppTasks = activityManager.getAppTasks();

        for (ActivityManager.AppTask task : allAppTasks)
        {
            Log.e("TaskReturn", "AllTasks: " + task.getTaskInfo().id + " " + task.getTaskInfo().affiliatedTaskId + " " + task.getTaskInfo().persistentId);
        }

        activityManager.moveTaskToFront(taskToStart, ActivityManager.MOVE_TASK_WITH_HOME);
    }
    else
    {
        Log.e("TaskReturn", "WHERE IS MY EXTRA!?!?!");
        //Boo...
    }
}

<uses-permission Android:name="Android.permission.REORDER_TASKS"/>

...

<receiver Android:name=".TaskReturn"/>

基本的には、Activity.getTaskId()の呼び出しの結果を状態にマークするという考え方です。後で、そのアクティビティのタスクに再開する通知を作成するときに、タスクIDを取得して、それを追加にスローします。次に、タスクIDを引き出してそのタスクを起動するブロードキャストレシーバーを指すように保留インテントを設定します。

これは、使用した呼び出しでAPI 21を必要とするように見えます。タスクが既に終了している場合は、追加のエラーチェックが必要になる可能性がありますが、それは私の目的に役立ちます。

1
dhakim