MQTT Callback context not defined during publish - java

public class MqttService extends Service implements MqttCallback {
public MqttAsyncClient mClient;
mOpts = new MqttConnectOptions();
mOpts.setCleanSession(MQTT_CLEAN_SESSION);
mOpts.setUserName(String.valueOf(userMigration.getId()));
mOpts.setPassword(userMigration.getPassword().toCharArray());
mOpts.setAutomaticReconnect(true);
mOpts.setKeepAliveInterval(MQTT_KEEP_ALIVE);
mClient.connect(mOpts, this, connectListener);
#Override
public void messageArrived(String topic, MqttMessage message) throws Exception {
}
#Override
public void deliveryComplete(IMqttDeliveryToken token) {
//Log.e(DEBUG_TAG, "Completed Delivery");
}
#Override
public void connectionLost(Throwable arg0) {
stopKeepAlives();
Log.e(DEBUG_TAG, "Lost");
mClient = null;
}
IMqttActionListener connectListener = new IMqttActionListener() {
public void onSuccess(IMqttToken asyncActionToken) {
mStarted = true; // Service is now connected
Log.i(DEBUG_TAG,"Successfully connected");
mClient.setCallback(MqttService.this);
}
public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
Log.e(DEBUG_TAG, "con failed "+exception.toString());
}
};
mClient.publish("message/"+jsonObject.get("userBId").getAsInt(),jsonObject.toString().getBytes(), 1, false, this, new IMqttActionListener() {
#Override
public void onSuccess(IMqttToken asyncActionToken) {
}
#Override
public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
Log.e(DEBUG_TAG,"failed");
}
});
}
//If I am not setting callback after connection, it is working perfectly but message recevied is not triggering. If I set callback after connection, them message arrived is triggering but during publish, I am getting IMqttActionListener defined on null. Could you help me. I need callback just after the publish to update that data in my database.

Try moving the mClient.setCallback(MqttService.this); line up, before connect is initiated:
mOpts.setKeepAliveInterval(MQTT_KEEP_ALIVE);
mClient.setCallback(this);
mClient.connect(mOpts, this, connectListener);

Related

How to use ApplicationContext in Handler

i am really new to Android and i was trying to use the Thread class with a message handler, in there i need to use the ApplicationContext but when i try to run it it crashes, here is the code that makes the application crash
if (!connected.isState()) {
client = new MqttAndroidClient(myContext.context, SERVERURI, CLIENTID);
try {
IMqttToken token = client.connect();
token.setActionCallback(new IMqttActionListener() {
#Override
public void onSuccess(IMqttToken asyncActionToken) {
//we are connected
connected.setState(true);
}
#Override
public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
//we are not connected
}
});
} catch (Exception e) {
e.printStackTrace();
}
return;
}
here is the myContext class
class myContext extends Application {
public static Context context;
#Override
public void onCreate() {
super.onCreate();
context = getApplicationContext();
}
}
what can i do to fix the problem?
You probably haven't told Android to use your custom Application class, so myContext.onCreate() isn't being called. To do this you need to add this to your <application> declaration in your manifest:
android:name=".myContext"
OP here.
in the end i solved it by sending a message containing the applicationContext in message.obj, here is the code now
if (!connected.isState()) {
client = new MqttAndroidClient((Context) msg.obj, SERVERURI, CLIENTID);
try {
IMqttToken token = client.connect();
token.setActionCallback(new IMqttActionListener() {
#Override
public void onSuccess(IMqttToken asyncActionToken) {
//we are connected
connected.setState(true);
}
#Override
public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
//we are not connected
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
return;
}
thanks to everybody for the suggestions and for keeping up with my inexperience
:-)

Calling dispose() when passing a subscriber that overrides onSubscribe

I am new to RxJava and if I understand correctly the Observer is passed the Disposable on the onSubscribe so it can manually stop the processing if the dispose() has already been called.
I created the following code:
#NonNull Observable<Long> src = Observable.interval(1, TimeUnit.SECONDS);
src.subscribe(new Observer<Long>() {
private Disposable d;
#Override
public void onSubscribe(#NonNull Disposable d) {
this.d = d;
}
#Override
public void onNext(#NonNull Long aLong) {
if(!d.isDisposed()) {
System.out.println("Number onNext = " + aLong);
}
}
#Override
public void onError(#NonNull Throwable e) {
}
#Override
public void onComplete() {
System.out.println("completed");
}
});
but I can't figure out how to call dispose() for that subscription. subscribe with passing Observer as an argument returns void and subscribeWith does not accept my Observer without compile errors.
How is this supposed to work? What am I misunderstanding here?
The JavaDocs of Observable has a straightforward example:
Disposable d = Observable.just("Hello world!")
.delay(1, TimeUnit.SECONDS)
.subscribeWith(new DisposableObserver<String>() {
#Override public void onStart() {
System.out.println("Start!");
}
#Override public void onNext(String t) {
System.out.println(t);
}
#Override public void onError(Throwable t) {
t.printStackTrace();
}
#Override public void onComplete() {
System.out.println("Done!");
}
});
Thread.sleep(500);
// the sequence can now be disposed via dispose()
d.dispose();
Edit
The following examples are ways to get the Disposable out of the onSubscribe method but are generally not recommended:
// field in the owner class
Disposable disposable;
public void doReactive() {
Observable<Long> src = Observable.interval(1, TimeUnit.SECONDS);
src.subscribe(new Observer<Long>() {
#Override
public void onSubscribe(#NonNull Disposable d) {
disposable = d;
}
// ...
});
}
public void cleanup() {
if (disposable != null) {
disposable.dispose();
disposable = null;
}
}
or
SerialDisposable sd = new SerialDisposable();
Observable<Long> src = Observable.interval(1, TimeUnit.SECONDS);
src.subscribe(new Observer<Long>() {
#Override
public void onSubscribe(#NonNull Disposable d) {
sd.set(d);
}
// ...
});
// ...
sd.dispose();
You can use the DisposableObserver which can be easily disposed when you are done observing.
#NonNull Observable<Long> src = Observable.interval(1, TimeUnit.SECONDS);
src.subscribe(new DisposableObserver<Long>() {
#Override
public void onNext(#NotNull Long aLong) {
//Do anything you want to do..
dispose();
}
#Override
public void onError(#NotNull Throwable e) {
//Handle the errors here..
dispose();
}
#Override
public void onComplete() {
dispose();
}
});
You can also use CompositeDisposable to dispose many observers at one time, For more details check this out.
https://www.tutorialspoint.com/rxjava/rxjava_compositedisposable.htm

RxJava OnNext only works with the mainThread

When I switch from running the observeOn on the Main thread to a newThread, the onNext only runs once.
That only way I can get it to work is to keep it on the Main thread, but then I get that it does too much work on the Main Thread.
Without the setErrorHandler it just crashes (Also, can I use doOnError instead of RxJavaPlugins?)
PS. It works on the emulator fine, but it's on the physical device that the issue comes up.
public void updatePie() {
RxJavaPlugins.setErrorHandler(Functions.<Throwable>emptyConsumer());
Observable<Long> intervalObservable = Observable
.interval(1, TimeUnit.SECONDS)
//.doOnError(Functions.<Throwable>emptyConsumer())
.subscribeOn(Schedulers.io())
.takeWhile(new Predicate<Long>() {
#Override
public boolean test(Long aLong) throws Exception {
if (isMyServiceRunning(MyService.class) == false) {
RxB = false;
}
return RxB;
}
})
.observeOn(Schedulers.newThread());
intervalObservable.subscribe(new io.reactivex.Observer<Long>() {
#Override
public void onSubscribe(Disposable d) {
}
#Override
public void onNext(Long aLong) {
triple = mService.Time;
entries.set(0, new PieEntry(mService.Time, "kronk"));
entries.set(1, new PieEntry(mService.Time2, "notre dame"));
pie_chart.notifyDataSetChanged();
pie_chart.invalidate();
}
#Override
public void onError(Throwable e) {
Log.d(TAG, "Pie Update " + e.toString());
}
#Override
public void onComplete() {
Log.d(TAG, "Pie Update completed");
}
});
}

Execute function in current activity after onReponse() of Retrofit itself outside a service

I am currently working on an Android Application, and i have a problem to handle a request and execute a function just after.
The fact is my Retrofit request is in a Controller, used by a Service, and i am calling the service function inside my Activity (am i clear?).
Clearly, i have to manage one user (get and refresh access token from a webservice) and i need to be able to call my refreshToken() function and execute some code after getting and parsing the response.
This is my code :
UserActivity
public class UserActivity extends AppCompatActivity {
private final static String TAG = "UserActivity";
private User user;
private TextView textViewAccessTokenShow, textViewExpiresInShow, textViewIGPShow, textViewRefreshTokenShow;
private LoginController loginController;
private Wso2Service wso2Service, wso2ServiceIS;
boolean mBounded;
private LoginService loginService;
private Intent mIntent;
//Connection to LoginService
ServiceConnection mConnection = new ServiceConnection() {
#Override
public void onServiceDisconnected(ComponentName name) {
Toast.makeText(UserActivity.this, "Service is disconnected", Toast.LENGTH_LONG).show();
mBounded = false;
loginService = null;
Log.e(TAG, "onServiceDisconnected: " );
}
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
Toast.makeText(UserActivity.this, "Service is connected", Toast.LENGTH_LONG).show();
mBounded = true;
LoginService.LocalBinder mLocalBinder = (LoginService.LocalBinder) service;
loginService = mLocalBinder.getServerInstance();
user = loginService.getUser();
refreshIHM();
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_user);
mIntent = new Intent(this, LoginService.class);
textViewAccessTokenShow = findViewById(R.id.textViewAccessTokenShow);
textViewRefreshTokenShow = findViewById(R.id.textViewRefreshTokenShow);
textViewExpiresInShow = findViewById(R.id.textViewExpiresInShow);
textViewIGPShow = findViewById(R.id.textViewIGPShow);
}
#Override
protected void onResume() { //Getting my user updated outside this activity and printing his informations
super.onResume();
Log.i(TAG, "onResume: ");
if(mBounded == false){
bindService(mIntent, mConnection, BIND_AUTO_CREATE);
} else {
user = loginService.getUser();
refreshIHM();
}
}
public void onClickRefreshToken(View view){
//Where i have to refresh my token, and after that executing refreshIHM()
refreshIHM();
}
public void refreshIHM(){
Log.d(TAG, "refreshIHM() called");
Log.i(TAG, "refreshIHM: "+user.toString());
textViewExpiresInShow.setVisibility(View.VISIBLE);
textViewAccessTokenShow.setVisibility(View.VISIBLE);
textViewRefreshTokenShow.setVisibility(View.VISIBLE);
textViewIGPShow.setVisibility(View.VISIBLE);
textViewAccessTokenShow.setText(user.getAccess_token());
textViewAccessTokenShow.invalidate();
textViewAccessTokenShow.requestLayout();
textViewRefreshTokenShow.setText(user.getRefresh_token());
textViewRefreshTokenShow.invalidate();
textViewRefreshTokenShow.requestLayout();
textViewExpiresInShow.setText(String.valueOf(user.getExpire_in()));
textViewExpiresInShow.invalidate();
textViewExpiresInShow.requestLayout();
textViewIGPShow.setText(user.getId_group_parent());
textViewIGPShow.invalidate();
textViewIGPShow.requestLayout();
}
}
LoginController, where i execute every functions about User data
public class LoginController {
public static final String TAG = "LOGINSERVICE";
private User usertemp;
private Wso2Service wso2Service, wso2ServiceIS;
public LoginController(){
this.wso2Service = new Retrofit.Builder()
.baseUrl(Wso2Service.APIMENDPOINT)
.addConverterFactory(ScalarsConverterFactory.create())
.build()
.create(Wso2Service.class);
this.wso2ServiceIS = new Retrofit.Builder()
.baseUrl(Wso2Service.ISENDPOINT)
.addConverterFactory(ScalarsConverterFactory.create())
.build()
.create(Wso2Service.class);
}
public User parseUserInfo(String request, User user) {
try {
JSONObject jo = new JSONObject(request);
user.setAccess_token(jo.getString("access_token"));
user.setRefresh_token(jo.getString("refresh_token"));
user.setScope(jo.getString("scope"));
user.setId_token(jo.getString("id_token"));
user.setToken_type(jo.getString("token_type"));
user.setExpire_in(jo.getInt("expires_in"));
return user;
} catch (Exception e){
Log.e(TAG, "getUserInfo: "+e.toString());
}
return null;
}
public User parseIdGroupParentInfo(String request, User user){
try {
Log.i(TAG, "parseIdGroupParentInfo: "+request);
JSONObject jo = new JSONObject(request);
user.setId_group_parent(jo.getString("id_group_parent"));
return user;
} catch (Exception e){
Log.e(TAG, "parseIdGroupParentInfo: "+e.toString());
}
return null;
}
public void refreshToken(User user){
this.usertemp = user;
Log.i(TAG, "refreshToken: ");
this.wso2Service.getTokensByRefresh("refresh_token",user.getRefresh_token(),"openid", ApiConstants.token).enqueue(new Callback<String>() {
#Override
public void onResponse(Call<String> call, Response<String> response) {
if(response.isSuccessful()) {
//On parse la réponse
usertemp.setLogin_request_responseJSON(response.body());
parseUserInfo(response.body(), usertemp);
Log.i(TAG, "onLoginReady: " + usertemp.toString());
wso2ServiceIS.getUserInfo("Bearer "+usertemp.getAccess_token()).enqueue(new Callback<String>() {
#Override
public void onResponse(Call<String> call, Response<String> response) {
Log.i(TAG, "onResponse: "+response.code()+response.body());
usertemp = parseIdGroupParentInfo(response.body(),usertemp);
}
#Override
public void onFailure(Call<String> call, Throwable t) {
Log.e(TAG, "onFailure: ",t );
}
});
} else {
Log.e(TAG, "onResponse: " );
Log.e(TAG, "onResponse: Code "+response.code()+" Body : "+response.body() );
}
}
#Override
public void onFailure(Call<String> call, Throwable t) {
Log.e(TAG, "onFailure: ",t );
}
});
}
}
LoginService, what i call in every activities to use the same User everytime
public class LoginService extends Service {
public final String TAG = "LoginService";
private User user;
private LoginController loginController;
IBinder mBinder = new LocalBinder();
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
public class LocalBinder extends Binder {
public LoginService getServerInstance() {
return LoginService.this;
}
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i(TAG, "onStartCommand: ");
this.user = (User)intent.getSerializableExtra("user");
Log.i(TAG, "onStartCommand: "+user.toString());
loginController = new LoginController();
return START_STICKY;
}
#Override
public void onCreate() {
super.onCreate();
Log.i(TAG, "onCreate: ");
}
#Override
public void onDestroy() {
Log.i(TAG, "onDestroy: ");
super.onDestroy();
}
public User getUser(){
Log.i(TAG, "getUser: ");
return this.user;
}
public void regenerateByRefreshToken(){
Log.d(TAG, "regenerateByRefreshToken: ");
loginController.refreshToken(user);
Log.d(TAG, "regenerateByRefreshToken: end");
}
}
Do you have any idea about how to make my RefroFit function handle its response and only after executing another function inside my UI ? Or inside my regenerateByRefreshToken() function ?
Thank you !
Do you have any idea about how to make my RefroFit function handle its
response and only after executing another function inside my UI ? Or
inside my regenerateByRefreshToken() function ?
As per the current implementation, You can achieve this using Callbacks. Create two callbacks to
Get the usertemp inside service from the controller after successful execution.
Second callback to send the user object back to activity from service
So follow below steps:
a) Create callback interface
// create new OnUserRefresh.java
public interface OnUserRefresh{
void onRefresh(User user);
void onError(Throwable t);
}
b) Modify the controller to receive the callback reference
public class LoginController {
// code...
public void refreshToken(User user, OnUserRefresh onUserRefresh){
this.usertemp = user;
Log.i(TAG, "refreshToken: ");
this.wso2Service.getTokensByRefresh("refresh_token",user.getRefresh_token(),"openid", ApiConstants.token).enqueue(new Callback<String>() {
#Override
public void onResponse(Call<String> call, Response<String> response) {
if(response.isSuccessful()) {
//On parse la réponse
usertemp.setLogin_request_responseJSON(response.body());
parseUserInfo(response.body(), usertemp);
Log.i(TAG, "onLoginReady: " + usertemp.toString());
wso2ServiceIS.getUserInfo("Bearer "+usertemp.getAccess_token()).enqueue(new Callback<String>() {
#Override
public void onResponse(Call<String> call, Response<String> response) {
Log.i(TAG, "onResponse: "+response.code()+response.body());
usertemp = parseIdGroupParentInfo(response.body(),usertemp);
onUserRefresh.onRefresh(usertemp);
}
#Override
public void onFailure(Call<String> call, Throwable t) {
Log.e(TAG, "onFailure: ",t );
onUserRefresh.onError(t);
}
});
} else {
Log.e(TAG, "onResponse: " );
Log.e(TAG, "onResponse: Code "+response.code()+" Body : "+response.body() );
}
}
#Override
public void onFailure(Call<String> call, Throwable t) {
Log.e(TAG, "onFailure: ",t );
}
});
}
}
c) Pass callback object from service to controller
public class LoginService extends Service {
/*Add interface, to be used for data passing*/
public void regenerateByRefreshToken(OnUserRefresh onUserRefresh){
Log.d(TAG, "regenerateByRefreshToken: ");
loginController.refreshToken(user, new OnUserRefresh(){
#Override
void onRefresh(User user){
this.user = user;
onUserRefresh.onRefresh(user); // trigger onRefresh in client i.e. activity
}
#Override
void onError(Throwable t){
onUserRefresh.onError(t);
// log error etc
}
});
Log.d(TAG, "regenerateByRefreshToken: end");
}
}
d) Pass callback object from activity to service and implement UI updates method call
public class UserActivity extends AppCompatActivity {
public void onClickRefreshToken(View view){
//Where i have to refresh my token, and after that executing refreshIHM()
loginService.regenerateByRefreshToken(new OnUserRefresh(){
#Override
void onRefresh(User user){
this.user = user;
refreshIHM();
}
#Override
void onError(Throwable t){
// log error etc
}
});
}
}
Note: The initial user reference is always null as you are receiving it from intent in your service
this.user = (User)intent.getSerializableExtra("user");
but you are neither initialising any user object in UserActivity nor adding it in the mIntent object so you need to a user object with token and other required properties in activity for network calls.
You can optimize the flow with lambdas, Rxjava etc as well.

MQTT Android Studio and Raspberry PI Broker

I'm learning MQTT and Android Studio.
I want to make a simple application in Android Studio but I'm fighting from 4 days and I can`t cope with it.
Application Description:
1 Button ---> Push ---> Send to mqtt topic / message ( "mqtt" / "test" )
That`s all.
Mqtt Broker = rpi (IP: namerpibrok.ddns.net )
Broker works fine and it does not need a password or username
Problem is with Aplication - that is my first work with Android Studio.
I did everything as described on the page: https://www.hivemq.com/blog/mqtt-client-library-enyclopedia-paho-android-service
Now, when I push the button .... nothing happens.
MqttAndroidClient client;
private static final String TAG = "LOG";
// Used to load the 'native-lib' library on application startup.
static {
System.loadLibrary("native-lib");
}
private Object bytes;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
String clientId = MqttClient.generateClientId();
client = new MqttAndroidClient(this.getApplicationContext(), "rpidomwroled.ddns.net:1883", clientId);
MqttConnectOptions options = new MqttConnectOptions();
try {
IMqttToken token = client.connect(options);
token.setActionCallback(new IMqttActionListener() {
#Override
public void onSuccess(IMqttToken asyncActionToken) {
// We are connected
Toast.makeText(MainActivity.this,"Połączono", Toast.LENGTH_LONG).show();
}
#Override
public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
// Something went wrong e.g. connection timeout or firewall problems
Toast.makeText(MainActivity.this,"Połączono", Toast.LENGTH_LONG).show();
}
});
} catch (MqttException e) {
e.printStackTrace();
}
}
MqttAndroidClient client;
private static final String TAG = "LOG";
// Used to load the 'native-lib' library on application startup.
static {
System.loadLibrary("native-lib");
}
private Object bytes;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
String clientId = MqttClient.generateClientId();
client = new MqttAndroidClient(this.getApplicationContext(), "rpidomwroled.ddns.net:1883", clientId);
MqttConnectOptions options = new MqttConnectOptions();
try {
IMqttToken token = client.connect(options);
token.setActionCallback(new IMqttActionListener() {
#Override
public void onSuccess(IMqttToken asyncActionToken) {
// We are connected
Toast.makeText(MainActivity.this,"Połączono", Toast.LENGTH_LONG).show();
}
#Override
public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
// Something went wrong e.g. connection timeout or firewall problems
Toast.makeText(MainActivity.this,"Połączono", Toast.LENGTH_LONG).show();
}
});
} catch (MqttException e) {
e.printStackTrace();
}
}
public void pub(View v)
{
String topic = "mqtt";
String payload = "mqtt";
byte[] encodedPayload = new byte[0];
try {
encodedPayload = payload.getBytes("UTF-8");
MqttMessage message = new MqttMessage(encodedPayload);
client.publish(topic, message);
} catch (UnsupportedEncodingException | MqttException e) {
e.printStackTrace();
}
}
}
Can anybody tell me what I'm doing wrong?
This code is worked for me
String topic = "mqtt";
MqttMessage message = new MqttMessage();
message.setPayload("Message from IoT dev".getBytes());
client.publish(topic, message);
you can get call backs in
client.setCallback(new IoTCallbacks() {
#Override
public void connectionLost(Throwable cause) {
}
#Override
public void messageArrived(String topic, MqttMessage message) throws Exception {
}
#Override
public void deliveryComplete(IMqttDeliveryToken token) {
}
});

Categories

Resources