GVKun编程网logo

当应用程序在后台时,如何使 redux saga 保持响应?

5

本文将介绍当应用程序在后台时,如何使reduxsaga保持响应?的详细情况,。我们将通过案例分析、数据研究等多种方式,帮助您更全面地了解这个主题,同时也将涉及一些关于android–EventBus:

本文将介绍当应用程序在后台时,如何使 redux saga 保持响应?的详细情况,。我们将通过案例分析、数据研究等多种方式,帮助您更全面地了解这个主题,同时也将涉及一些关于android – EventBus:当应用程序在后台时,活动不会收到事件、android – Firebase展开式通知当应用程序在后台时显示图像、android – 当应用程序在后台时,Cordova本地通知不起作用、Android 应用程序:当应用程序处于后台操作时,如何在主屏幕上获取触摸事件的知识。

本文目录一览:

当应用程序在后台时,如何使 redux saga 保持响应?

当应用程序在后台时,如何使 redux saga 保持响应?

如何解决当应用程序在后台时,如何使 redux saga 保持响应??

我使用 React-Native,我有一个管理 websocket 状态的传奇。它实现重试并接收诸如位置更改之类的调度,以通过 websocket 将其发送到服务器。我正在使用 @mauron85/react-native-background-geolocation 在我的应用程序的根组件中获取位置事件,并将它们分派到 redux。 route saga 有一个生成器,它会监听并发送它。当应用程序在前台(当前正在使用)时,套接字可以从网络丢失中恢复并继续接收位置事件,但是当应用程序进入后台时,只要套接字打开,saga 就会响应事件并且仍然可以发送它们向上。一旦我标记飞行模式并丢失套接字,saga 就会停止响应重试和其他调度事件,例如位置更新。当我删除飞行模式(仍在后台时)时,它无法重新建立连接并接收调度。我该如何解决这个问题,才能让应用程序在不切换回前台的情况下恢复。

传奇代码:

function* sender(socket: WebSocket,eventType,data?) {
  const { token } = yield select(authState);
  if (socket && socket.readyState === WebSocket.OPEN) {
    let localData = {};
    if (data) {
      localData = data;
    }
    console.log(JSON.stringify({ type: eventType,data: { token,...localData } }));
    socket.send(JSON.stringify({ type: eventType,...localData } }));
    if (eventType === ROUTE_SOCKET_MESSSAGE_TYPES.PING) {
      const res = yield race({
        success: take(ROUTE_SOCKET_MESSAGE_RECEIVED),timeout: delay(SOCKET_PING_RESPONSE_EXPECTED)
      });

      if (res.timeout) {
        console.log(''ENCOUNTERED LAG IN MESSAGE RECEIPT'');
        yield put(markNetworkLost());
        yield put({ type: ROUTE_SOCKET_RETRY_ACTION_TYPE });
      } else {
        yield put(markHasNetwork());
      }
    }
  }
}

function* pinger(socket) {
  while (true) {
    yield call(sender,socket,ROUTE_SOCKET_MESSSAGE_TYPES.PING);
    yield delay(FORTY_FIVE_SECONDS);
  }
}

function* sendPosition(socket) {
  while (true) {
    const { latitude,longitude } = yield select(locationState);
    if (latitude && longitude) {
      yield call(positiondispatcher,{
        lat: latitude,lng: longitude
      });
    }
    yield take(''locations/ON_LOCATION_CHANGE'');
  }
}

function* locationApiRequest() {
  try {
    const res = yield call(getLocation);
    yield put(onPharmacyDetailsReceived(res.data));
  } catch (error) {
    console.log(''Could not fetch pharmacy location details'',error);
  }
}

function* positiondispatcher(socket,position) {
  yield call(sender,ROUTE_SOCKET_MESSSAGE_TYPES.DRIVER_LOCATION,position);
}

function dispatchPhotoFetch(route) {
  route.routeStops.forEach((stop) => {
    if (stop.address.photos) {
      console.log(stop.address.photos);
      PhotoService.readLocalFileOrDownload(
        stop.address.id,stop.address.photos.map((photo) => new Addressphoto(photo))
      );
    }
  });
}

function* socketChannelListener(socketChannel,socket) {
  let pingerProcess;
  let positionProcess;
  while (true) {
    const payload = yield take(socketChannel); // take incoming message
    const { type: baseSocketResponseType } = payload;

    switch (baseSocketResponseType) {
      case ''open'':
        yield fork(locationApiRequest);
        pingerProcess = yield fork(pinger,socket);
        positionProcess = yield fork(sendPosition,socket);
        PendingTasks.activate(); // activate pending task upload when the socket opens
        break;
      case ''error'':
        console.log(''ERROR'',payload.reason,payload);
        break;
      case ''close'':
        console.log(''CLOSE'',payload);
        if (payload.reason === ''Invalid creds'') {
          // console.log(''ENCOUNTERED INVALID CREDENTIALS/STALE TOKEN'');
          yield put(autologout());
        } else {
          yield put(markNetworkLost());
          yield put({ type: ROUTE_SOCKET_RETRY_ACTION_TYPE });
        }
        // console.log(''CALLING CLOSE'');
        yield cancel(pingerProcess);
        yield cancel(positionProcess);
        return;
      default:
        break;
    }

    let type;
    let data;
    let operation;
    let parsedData;

    if (payload && payload.data) {
      parsedData = JSON.parse(payload.data);
      const { type: incomingType,data: incomingData,op } = parsedData;
      type = incomingType;
      data = incomingData;
      operation = op;
    }
    // console.log(''PARSED MESSAGE'',parsedData);
    switch (type) {
      case ROUTE_SOCKET_TYPES.AUTH_STATUS:
        switch (data) {
          case PINGER_RESPONSE_TYPES.AUTH_SUCCESS:
            yield put({ type: ROUTE_SOCKET_MESSAGE_RECEIVED });
            break;
          case PINGER_RESPONSE_TYPES.TOKEN_EXPIRED:
            break;
          default:
            break;
        }
        break;
      case ROUTE_SOCKET_TYPES.DRIVER_ROUTE:
        console.log(
          `received DRIVER_ROUTE with ${JSON.stringify(data.routeStops.length)} stop(s)`,operation,data
        );
        switch (operation) {
          case DRIVER_ROUTE_OPERATIONS.I: {
            const currentRoute = yield select(driverRouteState);
            // if we do pick up a route..
            if (!currentRoute || currentRoute.id !== data.id) {
              yield fork(dispatchPhotoFetch,data);
              yield put(onDriverRouteChange(data));
            }
            break;
          }
          case DRIVER_ROUTE_OPERATIONS.U:
            // i believe we will ignore this if there are records in sqlite?
            // create address photo objects first?
            // yield put(onDriverRouteUpdate(data));
            break;
          case DRIVER_ROUTE_OPERATIONS.D:
            // Todo: deletion of a route needs to be handled most likely.
            break;
          default:
            break;
        }
        break;
      case ROUTE_SOCKET_TYPES.DRIVER_ROUTE_LOG_REQUEST:
        break;
      default:
        break;
    }
  }
}

function createSocketChannel(token) {
  // Todo: we need to pull this from config....
  const socket = new WebSocket(`${ROUTE_SOCKET_URL}${token}`);
  // establishes a redux emitter that saga can wait for (like an action)
  return {
    socket,socketChannel: eventChannel((emit) => {
      socket.onmessage = (event) => {
        // console.log(''--MESSAGE received--'',event);
        emit(event);
      };

      socket.onopen = (evt) => {
        emit(evt);
      };

      socket.onclose = (evt) => {
        emit(evt);
      };

      socket.onerror = (evt) => {
        emit(evt);
      };

      const unsubscribe = () => {
        socket.onmessage = null;
      };

      return unsubscribe;
    })
  };
}

function* routeSocket(token): any {
  const { socketChannel,socket } = yield call(createSocketChannel,token);
  yield fork(socketChannelListener,socketChannel,socket);
}

// this method will be retried
export function* RouteSocketSaga(): any {
  let task;

  while (true) {
    const routeSocketAction = yield take([
      ''DB_INITIALIZED'',PERSIST_REHYdratE,ON_AUTH_CHANGE,ROUTE_SOCKET_RETRY_ACTION_TYPE // retry will attempt to start the saga again..
    ]);
    console.log(routeSocketAction);

    if (routeSocketAction.type === PERSIST_REHYdratE) {
      const currentRoute = yield select(driverRouteState);
      if (currentRoute) {
        yield fork(dispatchPhotoFetch,currentRoute);
      }
    }

    // if the action is to retry,we will wait 5 seconds..
    if (routeSocketAction.type === ROUTE_SOCKET_RETRY_ACTION_TYPE) {
      yield delay(WAIT_BEFORE_RETRY_TIME);
    }
    const { token } = yield select(authState);
    if (token) {
      if (task) {
        yield cancel(task);
      }
      task = yield fork(routeSocket,token);
    }
  }
}

发送位置的组件代码

BackgroundGeolocation.configure({
      desiredAccuracy: BackgroundGeolocation.HIGH_ACCURACY,stationaryRadius: 1,distanceFilter: 1,notificationTitle: ''Background tracking'',debug: false,startOnBoot: false,url: null,stopOnTerminate: true,locationProvider: BackgroundGeolocation.ACTIVITY_PROVIDER,interval: 1000,fastestInterval: 1000,activitiesInterval: 1000,startForeground: false,stopOnStillActivity: false
    });

    BackgroundGeolocation.on(''background'',() => {
      console.log(''[INFO] App is in background'');
      setAppState(true);
    });

    BackgroundGeolocation.on(''foreground'',() => {
      console.log(''[INFO] App is in foreground'');
      setAppState(false);
    });

    BackgroundGeolocation.on(''location'',(location) => {
      dispatch(onLocationChange({ latitude: location.latitude,longitude: location.longitude }));
      console.log(''LOCATION'',location);
    });

    BackgroundGeolocation.on(''stationary'',(stationaryLocation) => {
      console.log(''STATIONARY LOCATION'',stationaryLocation);
    });

解决方法

最终将套接字逻辑移动到我的应用程序的根组件并响应那里的位置更新,这使我能够在后台保持套接字活动并发送位置更新。例如

  locationSendingEventHandler = (location) => {
    const {
      coords: { latitude,longitude }
    } = location;
    console.log(''LOCATION'',location);
    const { token } = this.props;
    let socketReopenTriggered = false;
    if ((!this.socket || (this.socket && this.socket.readyState >= 2)) && token) {
      // 2: CLOSING 3: CLOSED ... two cases where location event should trigger socket to re-open and there is a token
      socketReopenTriggered = true;
      if (this.setupSocketTimeout) {
        clearTimeout(this.setupSocketTimeout);
        this.setupSocketTimeout = null;
      }
      this.setUpSocket(''from location'');
    }

    if (!socketReopenTriggered && this.socket && this.socket.readyState === 1) {
      console.log(''SENDING LOCATION'',location,this.socket);
      this.socket.send(
        JSON.stringify({
          type: ''DRIVER_LOCATION'',data: { token,...{ lat: latitude,lng: longitude } }
        })
      );
    }
  };

android – EventBus:当应用程序在后台时,活动不会收到事件

android – EventBus:当应用程序在后台时,活动不会收到事件

我正在使用EventBus来进行活动和服务之间的沟通.
今天我有一个问题,不知道为什么.

>我有活动,片段和服务.他们都工作正常.
>在活动和片段我注册他们接收从服务提供的事件
>在Activity和Fragment中,当onDestroy()被调用时,我取消注册它们.
>在正常情况下,当服务提供事件时,片段和活动可以接收这些事件并且正常工作.
>但是当App被推送到背景(按Home或Power按钮)时,只有Fragment接收从Service发送的事件,Activity没有收到.
>我没有在活动和片段的onPause()中做任何事情.

题:

有什么解释吗?当应用程序在背景上被推送时,如何使我的Activity收到像Fragment那样的事件?

解决方法

当用户按下/ home按钮时,Activity可以随时销毁,因此您将无法使用EventBus接收数据.如果在Activity处于背景状态时如何尝试接收数据,则可能会泄漏内存并且应用程序将崩溃.

当用户恢复活动时,可以使用其他方法来获取活动中的数据.

您可以通过用户sharedpreferences或本地数据库来保存通过的结果.当用户导航回活动时,从sharedpreferences或数据库中读取.

这样就不会有内存泄漏或数据丢失的问题.

编辑1:

总是建议在onPause或onStop上取消注册监听器,因为活动不在前台时不需要这些事件.而且由于onDestroy()不能保证被调用,所以当Activity不再打开时,您可以继续接收广播.

android – Firebase展开式通知当应用程序在后台时显示图像

android – Firebase展开式通知当应用程序在后台时显示图像

我正在 Android中实施FCM通知,但根据应用状态(背景与前景)通知有何不同?

我正在使用FCM API与邮递员发送通知,这是通知结构:

{ "notification": {
      "title": "Notification title","body": "Notification message","sound": "default","color": "#53c4bc","click_action": "MY_BOOK","icon": "ic_launcher"
   },"data": {
       "main_picture": "URL_OF_THE_IMAGE"  
   },"to" : "USER_FCM_TOKEN"
}

要渲染的图像取自data.main_picture.

我已经实现了我自己的FirebaseMessagingService,它使通知在前台状态下完美显示.通知代码是下一个:

NotificationCompat.BigPictureStyle notiStyle = new NotificationCompat.BigPictureStyle();
notiStyle.setSummaryText(messageBody);
notiStyle.bigPicture(picture);

Uri defaultSoundUri= ringtoneManager.getDefaultUri(ringtoneManager.TYPE_NOTIFICATION);

NotificationCompat.Builder notificationBuilder = (NotificationCompat.Builder) new NotificationCompat.Builder(this)
            .setSmallIcon(R.drawable.ic_launcher)
            .setLargeIcon(bigIcon)
            .setContentTitle(title)
            .setContentText(messageBody)
            .setAutoCancel(true)
            .setSound(defaultSoundUri)
            .setContentIntent(pendingIntent)
            .setStyle(notiStyle); code here

notificationmanager notificationmanager =
            (notificationmanager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationmanager.notify(0,notificationBuilder.build());

但是,在后台,服务甚至不执行.在AndroidManifest.xml中,Firebase服务的声明如下:

<service
    android:name=".MyFirebaseMessagingService">
  <intent-filter>
    <action android:name="com.google.firebase.MESSAGING_EVENT"/>
  </intent-filter>
</service>

<service
    android:name=".MyFirebaseInstanceIDService">
  <intent-filter>
    <action android:name="com.google.firebase.INSTANCE_ID_EVENT"/>
  </intent-filter>
</service>

我的问题不是LargeIcon或SmallIcon,而是显示大图.

感谢您的支持.

解决方法

FCM通知消息不支持largeIcon或bigPicture.

如果您在后台需要它们,可以使用FCM数据消息.

对于数据消息,始终调用onMessageReceived(message)方法,因此可以使用message.getData()方法并创建自定义通知.

在这里阅读有关通知消息与数据消息的更多信息:
https://firebase.google.com/docs/cloud-messaging/concept-options#notifications_and_data_messages

android – 当应用程序在后台时,Cordova本地通知不起作用

android – 当应用程序在后台时,Cordova本地通知不起作用

我正在使用Cordova开发一个Android应用程序,它使用PushPlugin从我的服务器接收推送通知.

特别是,我正在使用PushPlugin Example进行一些测试.

我也在使用Cordova Local Notification plugin,因为我希望应用程序在收到推送通知后立即显示本地通知.

以下代码有效,并且仅在应用程序位于前台时显示本地通知.

即使应用程序在后台,我也希望显示本地通知.
可能吗?我怎样才能使它工作?

提前致谢

<!DOCTYPE HTML>
<html>
    <head>
        <title>com.PhoneGap.c2dm</title>
    </head>
    <body>

    <script type="text/javascript" charset="utf-8" src="cordova.js"></script>
    <script type="text/javascript" charset="utf-8" src="jquery_1.5.2.min.js"></script>
    <script type="text/javascript" src="PushNotification.js"></script>

    <script type="text/javascript">
        var pushNotification;

        function onDeviceReady() {
            $("#app-status-ul").append('<li>deviceready event received</li>');

                    document.addEventListener("backbutton", function(e){
                $("#app-status-ul").append('<li>backbutton event received</li>');

                    if( $("#home").length > 0){
                            // call this to get a new token each time. don't call it to reuse existing token.
                            //pushNotification.unregister(successHandler, errorHandler);
                            e.preventDefault();
                            navigator.app.exitApp();
                        }
                        else{
                            navigator.app.backHistory();
                        }
                    }, false);
                    try{ 
                    pushNotification = window.plugins.pushNotification;
                        $("#app-status-ul").append('<li>registering ' + device.platform + '</li>');
                        if (device.platform == 'android' || device.platform == 'Android' || device.platform == 'amazon-fireos' ){
                                 pushNotification.register(successHandler, errorHandler, {"senderID":"527085141383","ecb":"onNotification"});   
                                  } else {
                             pushNotification.register(tokenHandler, errorHandler, {"badge":"true","sound":"true","alert":"true","ecb":"onNotificationAPN"});   // obbligatorio!
                        }
                    }
                    catch(err) { 
                        txt="There was an error on this page.\n\n"; 
                        txt+="Error description: " + err.message + "\n\n"; 
                        alert(txt); 
                    } 
        }   // fine onDeviceReady


        function onNotificationAPN(e) {
            if (e.alert) {
                 $("#app-status-ul").append('<li>push-notification: ' + e.alert + '</li>');
                 // showing an alert also requires the org.apache.cordova.dialogs plugin
                 navigator.notification.alert(e.alert);
            }

            if (e.sound) {
                // playing a sound also requires the org.apache.cordova.media plugin
                var snd = new Media(e.sound);
                snd.play();
            }

            if (e.badge) {
                pushNotification.setApplicationIconBadgeNumber(successHandler, e.badge);
            }
        }

        function onNotification(e) {
            $("#app-status-ul").append('<li>EVENT -> RECEIVED:' + e.event + '</li>');

            switch( e.event ){
                case 'registered':
                            if ( e.regid.length > 0 )
                            {
                                $("#app-status-ul").append('<li>REGISTERED -> REGID:' + e.regid + "</li>");
                                // Your GCM push server needs to kNow the regID before it can push to this device
                                // here is where you might want to send it the regID for later use.
                                console.log("regID = " + e.regid);
                            }
                    break;

                case 'message':
                    // if this flag is set, this notification happened while we were in the foreground.
                    // you might want to play a sound to get the user's attention, throw up a dialog, etc.

                      var notificaOk = function(){
                        console.log("OK");
                      }
                      var notificaKo = function(){
                        console.log("KO");
                      }

                      window.plugin.notification.local.add({id: 1, title: "Product available", message: "Nexus 6 in stock", smallIcon: 'ic_dialog_email', icon: 'ic_launcher'}, notificaOk, notificaKo);

                    if (e.foreground){
                                   $("#app-status-ul").append('<li>--INLINE NOTIFICATION--' + '</li>');

                                  // on Android soundname is outside the payload. 
                                // On Amazon fireos all custom attributes are contained within payload
                                var soundfile = e.soundname || e.payload.sound;
                                // if the notification contains a soundname, play it.
                                // playing a sound also requires the org.apache.cordova.media plugin
                                var my_media = new Media("/android_asset/www/"+ soundfile);

                                     my_media.play();

                              }
                              else{ // otherwise we were launched because the user touched a notification in the notification tray.

                                if (e.coldstart)
                                     $("#app-status-ul").append('<li>--COLDSTART NOTIFICATION--' + '</li>');
                                else
                                   $("#app-status-ul").append('<li>--BACKGROUND NOTIFICATION--' + '</li>');
                            }

                            $("#app-status-ul").append('<li>MESSAGE -> MSG: ' + e.payload.message + '</li>');
                              //android only
                            $("#app-status-ul").append('<li>MESSAGE -> MSGCNT: ' + e.payload.msgcnt + '</li>');
                              //amazon-fireos only
                              $("#app-status-ul").append('<li>MESSAGE -> TIMESTAMP: ' + e.payload.timeStamp + '</li>');

                      break;

                case 'error':
                            $("#app-status-ul").append('<li>ERROR -> MSG:' + e.msg + '</li>');
                          break;

                          default:
                            $("#app-status-ul").append('<li>EVENT -> UnkNown, an event was received and we do not kNow what it is</li>');
                          break;
                  }
        }

        function tokenHandler (result) {
            $("#app-status-ul").append('<li>token: '+ result +'</li>');
            // Your iOS push server needs to kNow the token before it can push to this device
            // here is where you might want to send it the token for later use.
        }

        function successHandler (result) {
            $("#app-status-ul").append('<li>success:'+ result +'</li>');
        }

        function errorHandler (error) {
            $("#app-status-ul").append('<li>error:'+ error +'</li>');
        }

             document.addEventListener('deviceready', onDeviceReady, true);

     </script>
    <div id="home">
        <div id="app-status-div">
            <ul id="app-status-ul">
                <li>Cordova PushNotification Plugin Demo</li>
            </ul>
        </div>
    </div>
</body>
</html>

然后我使用以下nodeJS脚本向我的设备发送推送通知:

var GCM = require('gcm').GCM;

var apiKey = "***";

var gcm = new GCM(apiKey);

var devRegIdTarget = "APA9....";

var message = {
    message: "Text msg",
    registration_id : devRegIdTarget, 
    title : 'Title',
    msgcnt : '1',
    collapseKey : "msg1",
    soundname : 'beep.wav'
};

message.timetoLive = 3000;
message.delayWhileIdle = true;

gcm.send(message, function(err, messageId){
    if (err) {
        console.log("Something has gone wrong!");
    } else {
        console.log("Sent with message ID: ", messageId);
    }
});

解决方法:

我在使用PushPlugin和localnotification方面有类似的经验.

对于我的情况,通知在后台工作但是android的白色空白.

我整晚都在检查localnotification插件的源代码,但事实证明这是PushPlugin本身的问题. (我会说,确切的问题是两个插件之间断开连接)在PushPlugin的源代码中,它检查应用程序是在前台还是后台.

如果应用程序在后台,则不会向cordova应用程序触发通知事件,但PushPlugin会创建自己的本地通知.

    @Override
protected void onMessage(Context context, Intent intent) {
    Log.d(TAG, "onMessage - context: " + context);

    // Extract the payload from the message
    Bundle extras = intent.getExtras();
    if (extras != null)
    {
        // if we are in the foreground, just surface the payload, else post it to the statusbar
        if (PushPlugin.isInForeground()) {
            extras.putBoolean("foreground", true);
            PushPlugin.sendExtras(extras);
        }
        else {
            extras.putBoolean("foreground", false);

            // Send a notification if there is a message
            if (extras.getString("message") != null && extras.getString("message").length() != 0) {
                createNotification(context, extras);
            }
        }
    }
}

因此,如果您想在后面运行应用程序时使用自定义的smallicon.

我通过覆盖初始代码来快速破解

    public void createNotification(Context context, Bundle extras)
{
    notificationmanager mnotificationmanager = (notificationmanager) getSystemService(Context.NOTIFICATION_SERVICE);
    String appName = getAppName(this);

    Intent notificationIntent = new Intent(this, PushHandlerActivity.class);
    notificationIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
    notificationIntent.putExtra("pushBundle", extras);

    PendingIntent contentIntent = PendingIntent.getActivity(this, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);

    int defaults = Notification.DEFAULT_ALL;

    if (extras.getString("defaults") != null) {
        try {
            defaults = Integer.parseInt(extras.getString("defaults"));
        } catch (NumberFormatException e) {}
    }

    NotificationCompat.Builder mBuilder =
            new NotificationCompat.Builder(context)
                .setDefaults(defaults)
                .setSmallIcon(getResourceId(context, "pushicon", "drawable", context.getPackageName()))
                .setLargeIcon(BitmapFactory.decodeResource(context.getResources(), getResourceId(context, "icon", "drawable", context.getPackageName())))
                .setWhen(System.currentTimeMillis())
                .setContentTitle(extras.getString("title"))
                .setTicker(extras.getString("title"))
                .setContentIntent(contentIntent)
                .setAutoCancel(true);

    String message = extras.getString("message");
    if (message != null) {
        mBuilder.setContentText(message);
    } else {
        mBuilder.setContentText("<missing message content>");
    }

    String msgcnt = extras.getString("msgcnt");
    if (msgcnt != null) {
        mBuilder.setNumber(Integer.parseInt(msgcnt));
    }

    int notId = 0;

    try {
        notId = Integer.parseInt(extras.getString("notId"));
    }
    catch(NumberFormatException e) {
        Log.e(TAG, "Number format exception - Error parsing Notification ID: " + e.getMessage());
    }
    catch(Exception e) {
        Log.e(TAG, "Number format exception - Error parsing Notification ID" + e.getMessage());
    }

    mnotificationmanager.notify((String) appName, notId, mBuilder.build());
}

现在,您需要做的就是将名为“pushicon”的图像放在可绘制的文件夹平台/ android / res / drawable / pushicon.png中
(我为大图标使用图像“图标”)

如果这很麻烦,我为此做了一个git repo
https://github.com/zxshinxz/PushPlugin.git

cordova插件添加https://github.com/zxshinxz/PushPlugin.git

希望其他程序员不要经历我经历的痛苦.

Android 应用程序:当应用程序处于后台操作时,如何在主屏幕上获取触摸事件

Android 应用程序:当应用程序处于后台操作时,如何在主屏幕上获取触摸事件

如何解决Android 应用程序:当应用程序处于后台操作时,如何在主屏幕上获取触摸事件?

使用 WindowManager,我像 Facebook Messenger 一样在主屏幕上制作应用程序 floaintView。

MotionEvent 允许移动浮动视图。 我想设置 WindowManager Flag 并为 Floating 以外的屏幕获取触摸事件,但它不起作用...

当我触摸浮动视图时,它运行良好。通过调用 OnTouchListener,ACTION_DOWN ACTION_UP,

当我在窗口(主屏幕)外触摸时,我希望它在做其他工作(触摸其他应用程序)和调用侦听器时都能很好地工作 请任何人指导我如何在我的应用程序中获取触摸事件,以便我可以完成一些任务。 我使用了三个 all 标志 FLAG_WATCH_OUTSIDE_TOUCH FLAG_NOT_TOUCH_MODAL
FLAG_NOT_FOCUSABLE

  1. FLAG_NOT_FOCUSABLE |FLAG_NOT_TOUCH_MODAL
    在主屏幕上,它会触摸窗口的其余部分,但无法调用 OnClickListener 的触摸。

  2. FLAG_WATCH_OUTSIDE_TOUCH 浮动视图以外的触摸被阻止。

    @SuppressLint("ClickableViewAccessibility") 覆盖乐趣 onCreate() { super.onCreate() if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) startMyOwnForeground() else startForeground( 1、 通知() )

     //Inflate the floating view layout we created
     mFloatingView = LayoutInflater.from(this).inflate(R.layout.test,null)
    
     val LAYOUT_FLAG: Int
     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
         LAYOUT_FLAG = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
    
     } else {
         LAYOUT_FLAG = WindowManager.LayoutParams.TYPE_PHONE
    
     }
    
     params = WindowManager.LayoutParams(
         WindowManager.LayoutParams.WRAP_CONTENT,WindowManager.LayoutParams.WRAP_CONTENT,LAYOUT_FLAG,WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or  WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL or WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,PixelFormat.TRANSLUCENT
     )
    
     //Specify the view position
     params!!.gravity =
         Gravity.TOP or Gravity.LEFT //Initially view will be added to top-left corner
     params!!.x = 0
     params!!.y = 100
    
     //Add the view to the window
     mWindowManager = getSystemService(WINDOW_SERVICE) as WindowManager
     mWindowManager!!.addView(mFloatingView,params)
    
     var test = mFloatingView!!.findViewById<RelativeLayout>(R.id.wrap_container)
     with(test) {
         setonTouchListener(object : View.OnTouchListener {
             private var initialX = 0
             private var initialY = 0
             private var initialTouchX = 0f
             private var initialTouchY = 0f
             override fun onTouch(v: View?,event: MotionEvent): Boolean {
                 Log.d("aa","aa")
                 when (event.action) {
                     MotionEvent.ACTION_DOWN -> {
                         Log.d("ACTION_DOWN","ACTION_DOWN")
                         //remember the initial position.
                         initialX = params!!.x
                         initialY = params!!.y
    
                         //get the touch location
                         initialTouchX = event.rawX
                         initialTouchY = event.rawY
    
                         return true
                     }
                     MotionEvent.ACTION_UP -> {
                         Log.d("ACTION_UP","ACTION_UP")
    
                         val Xdiff = (event.rawX - initialTouchX).toInt()
                         val Ydiff = (event.rawY - initialTouchY).toInt()
    
    
                         //The check for Xdiff <10 && YDiff< 10 because sometime elements moves a little while clicking.
                         //So that is click event.
                         if (Xdiff < 10 && Ydiff < 10) {
                             val intent = Intent(applicationContext,MainActivity::class.java)
                             intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
                             intent.putExtra("fromwhere","ser")
                             startActivity(intent)
                         }
                         return true
                     }
                     MotionEvent.ACTION_MOVE -> {
    
                         Log.d("ACTION_MOVE","ACTION_MOVE")
                         //Calculate the X and Y coordinates of the view.
                         params!!.x = initialX + (event.rawX - initialTouchX).toInt()
                         params!!.y = initialY + (event.rawY - initialTouchY).toInt()
    
    
                         //Update the layout with new X & Y coordinate
                         mWindowManager!!.updateViewLayout(mFloatingView,params)
                         return true
                     }
                     MotionEvent.ACTION_OUTSIDE -> {
    
                         Log.d("ACTION_OUTSIDE","ACTION_OUTSIDE")
                         //Calculate the X and Y coordinates of the view.
                         initialX = params!!.x
                         initialY = params!!.y
    
                         //get the touch location
                         initialTouchX = event.rawX
                         initialTouchY = event.rawY
    
                         return true
                     }
                 }
                 return false
             }
         })
     }
    

    }

''''''

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)

今天关于当应用程序在后台时,如何使 redux saga 保持响应?的讲解已经结束,谢谢您的阅读,如果想了解更多关于android – EventBus:当应用程序在后台时,活动不会收到事件、android – Firebase展开式通知当应用程序在后台时显示图像、android – 当应用程序在后台时,Cordova本地通知不起作用、Android 应用程序:当应用程序处于后台操作时,如何在主屏幕上获取触摸事件的相关知识,请在本站搜索。

本文标签: