Androidで通知欄をクリックした後、アプリを起動してからターゲットActivityを開く

11101 ワード

状況の概要
Androidアプリを開発する過程で、appでは独立したプロセスで動作し、サーバーと長い接続を保ち、サーバーから送られてきたメッセージを通知欄に表示し、クリック動作を設定し、クリックしてappに対応するActivityにジャンプするサービスを起動する必要がある.現在発生している問題は、サービスが独立したプロセスで実行され、メッセージが受信され、通知がポップアップされた後、app自体のプロセスには2つの状況があります.
appはを実行しています
appはを終了しました
1つ目の場合、処理は非常に簡単で、パラメータをIntentに直接入力し、対応するActivityを開くことができます.
しかし、第2のケースは、appが終了したため複雑であり、開くActivityのいくつかの操作はappの初期化に依存する必要があり、これらの初期化操作はappの起動中に行われる.例えば、あるショッピングアプリはある新商品のメッセージをプッシュし、ユーザーは通知をクリックして商品の詳細のActivityに入り、そのActivityには注文Buttonがあり、そのButtonをクリックするとローカルからユーザーのIdなどの情報を取得してサーバーにメッセージを送り、あるユーザーがその商品を注文したことをサーバーに伝える.これらのユーザ情報はapp起動時にサーバと一連のインタラクションを行った後に取得される.アプリ終了後に詳細Activityに直接アクセスして購入をクリックすると、ユーザー情報が取得できずエラーが発生します.
したがって、現在解決すべき問題は、Notificationでクリック動作を設定し、app自体が実行されている場合は、ターゲットActivityに直接ジャンプします.appが終了した場合は、appを起動して初期化を完了し、ターゲットActivityにジャンプします.
方案と構想
現在3つのActivityがあると仮定します.
SplashActivityは、appの大図を表示しながらユーザー登録などの操作を行い、サーバがデータを返してMainActivityにジャンプします.
MainActivityアプリのメインActivity.
DetailActivity MainActivityでButtonが入ったActivityをクリックして、ある商品の詳細を表示します.
また、ポップアップ通知のサービスは別のプロセスにあります.
私たちが達成しなければならない目的は:
通知欄の通知をクリックし、appが実行中である場合、直接DetailActivityにジャンプして具体的な内容を表示し、DetailActivityでBackキーを押してMainActivity に戻る
通知欄をクリックして、appが終了した場合、SplashActivityから入り、app起動画面を表示し、初期化操作が完了したらMainActivityに入り、DetailActivityにジャンプして具体的な内容を表示し、DetailActivityでBackキーを押してMainActivityに戻るように通知します.
初歩的な考え方は,まずappプロセスが存在するか否かを判断し,存在する場合はstartActivitiesを用いてMainActivityとDetailActivityを起動することである.なぜ直接DetailActivityだけを起動せずにMainActivityを起動するのですか?プロセス内のすべてのActivityが終了している場合がありますが、プロセスがシステムによって回収されていない場合は、プロセスに戻りtrueがあるかどうかを判断し、DetailActivityのみを起動すると、Backキーを押すとタスクスタックはそのままデスクトップに戻ります.私たちが望む効果は、Backキーを押して前のレベルのActivity、つまりMainActivityに戻ることです.
アプリプロセスが終了して存在しなくなった場合は、SplashActivityに転送された後、SplashActivityからMainActivityに転送され、MainActivityに判断が加えられ、このパラメータがあれば通知欄から起動したことを示し、DetailActivityにジャンプする操作を行うIntentでアプリケーションを起動します.そうでない場合は、通常の起動です.
コード実装
大まかな実現構想ができたら、demoを実際に操作してみましょう.まず、私たちのdemoには簡単なコンポーネントがあります.
PushServiceは、新しいプロセスで起動されたサービスで、サーバの傍受を担当し、サーバの情報を受信した後にメッセージをブロードキャストします.このdemoでは、簡略化のため、メッセージを簡単にブロードキャストします.
ShowNotificationReceiver、新しいプロセスに登録されているBroadcastReceiverは、PushServiceからのメッセージを受信すると、通知バーにという通知がポップアップされます.
NotificationReceiver、新しいプロセスに登録されたBroadcastReceiverは、通知バーをクリックして通知する動作を設定し、appのActivity を開く
SplashActivity,app起動ページは、まず起動画像、3 s後にMainActivity に入ります.
MainActivity,appのメインActivity DetailActivity,appに詳細を表示するActivity PushService.java
まずPushServiceです.新しいプロセスで起動するにはAndroidManifestです.xmlに以下のサービス登録コードを追加
<service android:name=".PushService"
                 android:process=":push"/>

PushServiceの作業は簡単で、起動後にブロードキャストを送信して通知欄に通知を表示し、バックグラウンドに常駐します.
public class PushService extends Service{
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.i("PushService", "PushService onCreate");
        // AlarmManager      
        AlarmManager am = (AlarmManager)getSystemService(Context.ALARM_SERVICE);

        Intent intent = new Intent(this, ShowNotificationReceiver.class);

        PendingIntent pendingIntent =
                PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);

        am.set(AlarmManager.ELAPSED_REALTIME, SystemClock.currentThreadTimeMillis(), pendingIntent);

    }

}

ShowNotificationReceiver.java
このブロードキャストクラスは、通知バーで通知をポップアップするために使用されます.
public class ShowNotificationReceiver extends BroadcastReceiver{
    private static final String TAG = "RepeatReceiver";
    @Override
    public void onReceive(Context context, Intent intent) {
        Log.d(TAG, "ShowNotificationReceiver onReceive");
        //                   
        Intent broadcastIntent = new Intent(context, NotificationReceiver.class);
        PendingIntent pendingIntent = PendingIntent.
                getBroadcast(context, 0, broadcastIntent, PendingIntent.FLAG_UPDATE_CURRENT);

        NotificationCompat.Builder builder = new NotificationCompat.Builder(context);
        builder.setContentTitle("       ")
                .setTicker("     ticker")
                .setContentIntent(pendingIntent)
                .setSmallIcon(android.R.drawable.ic_lock_idle_charging);

        Log.i("repeat", "showNotification");
        NotificationManager manager = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);
        manager.notify(2, builder.build());
    }
}

NotificationReceiver.java
通知欄をクリックすると、アナウンスが送信され、NotificationReceiverがそのアナウンスを受信すると、appプロセスが存続しているか否かが判断され、appプロセスの状態によって異なるapp起動方式が定義されます
public class NotificationReceiver extends BroadcastReceiver{

    @Override
    public void onReceive(Context context, Intent intent) {
        //  app      
        if(SystemUtils.isAppAlive(context, "com.liangzili.notificationlaunch")){
            //      ,     DetailActivity,        ,  app        
            // Task     ,      Back     ,           ,      
            //DetailActivity,  Back      MainActivity 。     
            //DetailActivity ,    MainActivity。
            Log.i("NotificationReceiver", "the app process is alive");
            Intent mainIntent = new Intent(context, MainActivity.class);
            // MainAtivity launchMode   SingleTask,      flag   Intent.FLAG_CLEAR_TOP,
            //  Task   MainActivity   ,        ,      Activity     ,
            //  Task    MainActivity  ,      
            mainIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

            Intent detailIntent = new Intent(context, DetailActivity.class);
            detailIntent.putExtra("name", "   ");
            detailIntent.putExtra("price", "58 ");
            detailIntent.putExtra("detail", "      ,   app    ,    Activity ");

            Intent[] intents = {mainIntent, detailIntent};

            context.startActivities(intents);
        }else {
            //  app       ,     app, DetailActivity       Intent ,    
            //SplashActivity  MainActivity,  app        , MainActivity                     //     DetailActivity   
            Log.i("NotificationReceiver", "the app process is dead");
            Intent launchIntent = context.getPackageManager().
                    getLaunchIntentForPackage("com.liangzili.notificationlaunch");
            launchIntent.setFlags(
                    Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
            Bundle args = new Bundle();
            args.putString("name", "   ");
            args.putString("price", "58 ");
            args.putString("detail", "      ,   app     ,        Activity ");
            launchIntent.putExtra(Constants.EXTRA_BUNDLE, args);
            context.startActivity(launchIntent);
        }
    }
}

SplashActivity.java
SplashActivity.JAvaはまずappが起動した画像で、3 s後にMainActivityに入り、SplashActivityを起動したIntentにパラメータがついている場合はパラメータを取り出し、MainActivityを起動したIntentに入れる
public class SplashActivity extends AppCompatActivity{
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_splash);
        //  ActionBar
        getSupportActionBar().hide();
        //  handler  3    MainActivity
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                Intent intent = new Intent(SplashActivity.this, MainActivity.class);
                //    app Intent        ,  app              
                //     ,   MainActivity 
                if(getIntent().getBundleExtra(Constants.EXTRA_BUNDLE) != null){
                    intent.putExtra(Constants.EXTRA_BUNDLE,
                            getIntent().getBundleExtra(Constants.EXTRA_BUNDLE));
                }
                startActivity(intent);
                finish();
            }
        }, 3000);
    }
}

MainActivity.java
MainActivityでは、パラメータ入力がある場合は初期化終了後、パラメータに従ってDetailActivityを起動し、パラメータ入力がない場合は自分のタスクを終了します
public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Intent intent = new Intent(this, PushService.class);
        startService(intent);
        setTitle("MainActivity");
        Bundle bundle = getIntent().getBundleExtra(Constants.EXTRA_BUNDLE);
        if(bundle != null){
            //  bundle  ,       ,  DetailActivity
            String name = bundle.getString("name");
            String price = bundle.getString("price");
            String detail = bundle.getString("detail");
            SystemUtils.startDetailActivity(this, name, price, detail);
            Log.i(TAG, "launchParam exists, redirect to DetailActivity");
        }
    }

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

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }
}

DetailActivity.java
入力パラメータを表示すると簡単です.-D
public class DetailActivity extends AppCompatActivity{
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_detail);
        getSupportActionBar().setTitle("DetailActivity");
        String name = getIntent().getStringExtra("name");
        String price = getIntent().getStringExtra("price");
        String detail = getIntent().getStringExtra("detail");

        ((TextView)findViewById(R.id.name)).setText(name);
        ((TextView)findViewById(R.id.price)).setText(price);
        ((TextView)findViewById(R.id.detail)).setText(detail);
    }
}

効果の表示
http://v.youku.com/v_show/id_XMTMwMjgyNTUwMA==.html?from=y1.7-1.2
demoダウンロード
https://github.com/slimhippo/androidcode