How to use signalr in android Service

2020-04-13 05:29发布

问题:

I used the signalr library and the problem that is created for me is that when the phone goes to sleep it will issue a connection time out error and will no longer connect to the server.

in Activity

public class MainActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);


        startService(new Intent(getApplicationContext(), signalRService.class));
}}

in Service

public class SignalRService extends Service {

     private static String Tag = "ServiceSignalR";
     public static HubConnection conn = null;
     private static AndroidPlatformComponent androidPlatformComponent = null;
     private Thread back;

    private static Logger logger = new Logger() {

       @Override
       public void log(String message, LogLevel level) {
           Log.d(Tag, message);
       }
    };

    private Runnable m = new Runnable() {
       @Override
       public void run() {
            pm = (PowerManager) getApplicationContext().getSystemService(Context.POWER_SERVICE);
            final PowerManager.WakeLock wakeLock = pm.newWakeLock((PowerManager.PARTIAL_WAKE_LOCK), "TAG");
            wakeLock.acquire();

           wm = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
           WifiManager.WifiLock lock =  wm.createWifiLock(WifiManager.WIFI_MODE_FULL, "LockTag");
           lock.acquire();

           startSignalR();

      }
   };

  @Override
  public void onCreate() {
     super.onCreate();
     Log.d(Tag, "Start Service");
     signalRService = this;
     back = new Thread(m);
  }

  @Override
  public int onStartCommand(Intent intent, int flags, int startId) {

       back.start();

   networkChangeReceiver = new NetworkChangeReceiver() {
          @Override
        public void onReceive(Context context, Intent intent) {
               final ConnectivityManager connMgr = (ConnectivityManager) context
                    .getSystemService(Context.CONNECTIVITY_SERVICE);

               final NetworkInfo wifi = connMgr
                    .getNetworkInfo(ConnectivityManager.TYPE_WIFI);

               final NetworkInfo mobile = connMgr
                    .getNetworkInfo(ConnectivityManager.TYPE_MOBILE);

               if (wifi.isAvailable() || mobile.isAvailable()) {
                if (isConnected(context)) {

                    if (back != null) {
                        if (back.isInterrupted()) {
                            back = null;
                            back = new Thread(m);
                            back.start();
                        }
                    }

                }
            }
        }
    };
        NetworkChangeReceiver.registerWifiReceiver(getApplicationContext(), networkChangeReceiver);
       return START_STICKY;
  }


   @Override
   public void onDestroy() {
       if (back != null)
          back.interrupt();
       super.onDestroy();
   }

  @Nullable
  @Override
  public IBinder onBind(Intent intent) {
      return null;
  }


   public static void startSignalR() {
    // Connect to the server

      if (androidPlatformComponent == null)
            androidPlatformComponent = new AndroidPlatformComponent();

      Platform.loadPlatformComponent(androidPlatformComponent);


       if (conn == null)
           conn = new HubConnection("http://*************/", "", true, logger);

       HubProxy proxy = conn.createHubProxy("ChatHub");
       proxy.subscribe(new Object() {
        @SuppressWarnings("unused")
        public void messageReceived(String name, String message) {
            System.out.println(name + ": " + message);
        }
    });

     conn.start();

    conn.error(new ErrorCallback() {
        @Override
        public void onError(Throwable throwable) {
            try {
                Thread.sleep(10000);
                conn = null;
                androidPlatformComponent = null;
                startSignalR();
            } catch (Exception ex) {
            }
        }
    });

    conn.received(new MessageReceivedHandler() {

        @Override
        public void onMessageReceived(JsonElement json) {
            Intent intent = new Intent("onReceiveMessage");
            intent.setAction("MessageAction");
            intent.putExtra("Message", json.toString());
            signalRService.sendBroadcast(intent);
        }
    });
   }


       @Override
       public void onTaskRemoved(Intent rootIntent) {
           if (android.os.Build.VERSION.SDK_INT >= 21) {          

               Intent restartServiceIntent = new  Intent(getApplicationContext(),
                SignalRService.class);
               restartServiceIntent.setPackage(getPackageName());

               PendingIntent restartServicePendingIntent = PendingIntent.getService(
                getApplicationContext(), 0, restartServiceIntent,
                PendingIntent.FLAG_ONE_SHOT);
               AlarmManager alarmService = (AlarmManager) getApplicationContext()
                .getSystemService(Context.ALARM_SERVICE);

              long thirtySecondsFromNow = 1000;
              alarmService.set(AlarmManager.RTC_WAKEUP, thirtySecondsFromNow, restartServicePendingIntent);

              super.onTaskRemoved(rootIntent);
       }
   }
 }

in Manifests.xml

<?xml version="1.0" encoding="utf-8"?>
   <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="************.signalr2">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">
    <activity android:name=".MainActivity">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>

    <receiver android:name=".MyStartServiceReceiver">
        <intent-filter>
            <action android:name="android.intent.action.BOOT_COMPLETED" />
        </intent-filter>
    </receiver>



    <service
        android:name=".SignalRService"
        android:enabled="true"
        android:exported="false"
        android:label="Sig"
        android:largeHeap="true"
        android:stopWithTask="false" />

    <receiver
        android:name=".BroadCastMessage"
        android:enabled="true">
        <intent-filter>
            <action android:name="MessageAction" />
        </intent-filter>
    </receiver>
    <receiver
        android:name=".NetworkChangeReceiver"
        android:enabled="true">
        <intent-filter>
            <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
        </intent-filter>
    </receiver>
    <receiver
        android:name=".Screen"
        android:enabled="true">
        <intent-filter>
            <action android:name="android.intent.action.SCREEN_OFF" />
            <action android:name="android.intent.action.SCREEN_ON" />
        </intent-filter>
    </receiver>

</application>

in Boot BroadCast

public class MyStartServiceReceiver extends BroadcastReceiver {

@Override
public void onReceive(Context context, Intent intent) {

    context.stopService(new Intent(context.getApplicationContext() , SignalRService.class));
        context.startService(new Intent(context.getApplicationContext(), SignalRService.class));
}
}

in Message BroadCast

public class BroadCastMessage extends BroadcastReceiver {

@Override
public void onReceive(Context context, Intent intent) {
    Log.d("Service" , "Message-----------------------------------------------------------------------");


    NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(context)
            .setSmallIcon(R.mipmap.ic_launcher)
            .setContentTitle("Hi")
            .setPriority(Notification.PRIORITY_MAX)
            .setCategory(Notification.CATEGORY_CALL)
            .setDefaults(Notification.FLAG_AUTO_CANCEL | Notification.DEFAULT_SOUND)
            .setContentText(intent.getStringExtra("Message") + "")
            .setAutoCancel(true)
            .setLights(Color.parseColor("red"), 2000, 1000);
    NotificationManager mNotifyMgr = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
    mNotifyMgr.notify(100, mBuilder.build());


  }
 }

in Network State BroadCast

public class NetworkChangeReceiver extends BroadcastReceiver {

private Boolean isConnected = false;

@Override
public void onReceive(final Context context, final Intent intent) {
    final ConnectivityManager connMgr = (ConnectivityManager) context
            .getSystemService(Context.CONNECTIVITY_SERVICE);

    final NetworkInfo wifi = connMgr
            .getNetworkInfo(ConnectivityManager.TYPE_WIFI);

    final NetworkInfo mobile = connMgr
            .getNetworkInfo(ConnectivityManager.TYPE_MOBILE);

    if (wifi.isAvailable() || mobile.isAvailable()) {
        if (isConnected(context)) {
            try {

                context.stopService(new Intent(context , SignalRService.class));
                context.startActivity(new Intent(context , SignalRService.class));
            } catch (Exception ex) {}
        }
    } else {
           //            isConnected = false;
    }
}


public static void registerWifiReceiver(Context context, BroadcastReceiver broadcastReceiver) {
    IntentFilter filter = new IntentFilter();
    filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
    filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
    filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
    context.registerReceiver(broadcastReceiver, filter);
}

public static boolean isConnected(Context context) {

    boolean connectedState = isNetworkAvailable(context) || isWifiAvailable(context);

    return connectedState;
}

public static boolean isNetworkAvailable(Context context) {
    ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo mobileNetworkInfo = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
    return mobileNetworkInfo != null && mobileNetworkInfo.isConnected();

}

public static boolean isWifiAvailable(Context context) {
    ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo wifiNetworkInfo = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
    return wifiNetworkInfo != null && wifiNetworkInfo.isConnected();
}
  }

回答1:

Yes, you can. first of all make sure your SignalR service is working fine and noted down your token and hub connection, group name from which you can subscribe those calls by invoking them.

1) Made one singleton class

public class SignalRSingleton {

private static SignalRSingleton mInstance = null;
public HubConnection mHubConnection;
public HubProxy mHubProxy;

public static SignalRSingleton getInstance(){
    if(mInstance == null)
    {
        mInstance = new SignalRSingleton();
    }
    return mInstance;
}

public void setmHubConnection()
{
    String serverUrl = "http://192.168.1.5:8089/XM/";
    //String serverUrl = "http://192.168.1.184/test";
    mHubConnection = new HubConnection(serverUrl);
}

public void setHubProxy()
{
   /* Credentials credentials = new Credentials() {
        @Override
        public void prepareRequest(Request request) {
            request.addHeader("User-Name", MainActivity.unm);
        }
    };*/

    //mHubConnection.setCredentials(credentials);
    String SERVER_HUB_CHAT = "messages";
    //String SERVER_HUB_CHAT = "Chat";
    mHubProxy = mHubConnection.createHubProxy(SERVER_HUB_CHAT);
}


/**
 * method for clients (activities)
 */
public void sendMessage(String name , String message) {

    String str = "{'RequestMessage':{'PID':'lr1','Password':'GIefhSIC5iBCnxioufbwEw == '},'RequestType':'Login'}";
    String SERVER_METHOD_SEND = "getMessage";
    //String SERVER_METHOD_SEND = "Send";
    mHubProxy.invoke(SERVER_METHOD_SEND,str);
  }
}

2) Then implement service

public class SignalRService extends Service {
    //private HubConnection mHubConnection;
    //private HubProxy mHubProxy;
    private Handler mHandler; // to display Toast message
    private final IBinder mBinder = new LocalBinder(); // Binder given to clients
    private SignalRSingleton mInstance;
    final static String MY_ACTION = "MY_ACTION";
    public SignalRService() {

    }

    @Override
    public void onCreate() {
        super.onCreate();
        mInstance = SignalRSingleton.getInstance();
        mHandler = new Handler(Looper.getMainLooper());
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        int result = super.onStartCommand(intent, flags, startId);
        startSignalR();
        return result;
    }

    @Override
    public void onDestroy() {
        mInstance.mHubConnection.stop();
        super.onDestroy();
    }

    @Override
    public IBinder onBind(Intent intent) {
        // Return the communication channel to the service.
        startSignalR();
        return mBinder;
    }

    /**
     * Class used for the client Binder.  Because we know this service always
     * runs in the same process as its clients, we don't need to deal with IPC.
     */
    public class LocalBinder extends Binder {
        public SignalRService getService() {
            // Return this instance of SignalRService so clients can call public methods
            return SignalRService.this;
        }
    }


    /**
     * method for clients (activities)
     */


    private void startSignalR() {
        Platform.loadPlatformComponent(new AndroidPlatformComponent());
        mInstance.setmHubConnection();
        mInstance.setHubProxy();
        ClientTransport clientTransport = new ServerSentEventsTransport(mInstance.mHubConnection.getLogger());
        SignalRFuture<Void> signalRFuture = mInstance.mHubConnection.start(clientTransport);

        try {
            signalRFuture.get();
        } catch (InterruptedException | ExecutionException e) {
            Log.e("SimpleSignalR", e.toString());
            return;
        }

        mInstance.sendMessage(MainActivity.unm,"Hello All!");

        String CLIENT_METHOD_BROADAST_MESSAGE = "recievedMessage";
        //String CLIENT_METHOD_BROADAST_MESSAGE = "messageReceived";
        mInstance.mHubProxy.on(CLIENT_METHOD_BROADAST_MESSAGE,
                new SubscriptionHandler2<String,LoginInfo>() {
                    @Override
                    public void run(final String msg,final LoginInfo loginInfo) {
                        final String finalMsg = loginInfo.FullName  + "  says " + loginInfo.Password;
                    Intent intent = new Intent();
                    intent.setAction(MY_ACTION);
                    intent.putExtra("DATAPASSED", finalMsg);
                    sendBroadcast(intent);
                }
            }
            , String.class,LoginInfo.class);
    }
}

After you will get calls from Service Hope you will get what you need.