androidandroid-jobschedulerandroid-workmanagerandroid-runonuithread

runOnUiThread is not executing


I am trying to run this code but code inside my runOnUi thread is not executing. I am using evernote-android-job.

He is the code which runs periodically:

public class TempJob extends Job {

public static final String TAG = "job_temp_mqtt";

@Override
@NonNull
protected Result onRunJob(@NonNull Params params) {

    Log.d("I'm here", "Position 0");
    Looper.prepare();
    PubSubActivityTemp worker = new PubSubActivityTemp();

    Log.d("I'm here", "Position 1");
    worker.exe();

    return Result.SUCCESS;
}

public static void scheduleJob() {
    Set<JobRequest> jobRequests =  
 JobManager.instance().getAllJobRequestsForTag(TempJob.TAG);
    if (!jobRequests.isEmpty()) {
        Log.d("Check: ", "Job is not Empty");
       // return;
    }
    new JobRequest.Builder(TempJob.TAG)
            .setPeriodic(TimeUnit.MINUTES.toMillis(15), 
   TimeUnit.MINUTES.toMillis(7))
            .setUpdateCurrent(true) // calls 
    cancelAllForTag(NoteSyncJob.TAG) for you
            .setRequiredNetworkType(JobRequest.NetworkType.ANY)
            .setRequirementsEnforced(true)
            .build()
            .schedule();
 }
   }

Here is the code from the activity:

public class PubSubActivityTemp extends Activity {


static final String LOG_TAG = GraphSelectType.class.getCanonicalName();

// --- Constants to modify per your configuration ---

// IoT endpoint
// AWS Iot CLI describe-endpoint call returns: XXXXXXXXXX.iot.                     
   <region>.amazonaws.com
private static final String CUSTOMER_SPECIFIC_ENDPOINT = "*************- 
 ats.iot.us-east-1.amazonaws.com";
// Cognito pool ID. For this app, pool needs to be unauthenticated pool 
 with
// AWS IoT permissions.
private static final String COGNITO_POOL_ID = "us-east- 
1:*************-75c2-4258-b663-21*********83e";
// Name of the AWS IoT policy to attach to a newly created certificate
private static final String AWS_IOT_POLICY_NAME = "PubSub******Cert";

// Region of AWS IoT
private static final Regions MY_REGION = Regions.US_EAST_1;
// Filename of KeyStore file on the filesystem
private static final String KEYSTORE_NAME = "iot_keystore";
// Password for the private key in the KeyStore
private static final String KEYSTORE_PASSWORD = "password";
// Certificate and key aliases in the KeyStore
private static final String CERTIFICATE_ID = "default";

TextView tvStatus;
// TextView tvLastMessage;

Handler mHandler;

AWSIotClient mIotAndroidClient;
AWSIotMqttManager mqttManager;
String clientId;
String keystorePath;
String keystoreName;
String keystorePassword;

KeyStore clientKeyStore = null;
String certificateId;

CognitoCachingCredentialsProvider credentialsProvider;

int tracker = 0;  //0 is on, 1 is off
private String topic = "Simran*****";
private String msg0 = "on";
private String msg1 = "off";

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

public void exe() {
    Log.d("I'm here", "Position 2");
    new Thread() {
        public void run() {
            Log.d("I'm here", "Position 3");

                runOnUiThread(() -> {
                    Log.d("I'm here", "Position 4");
                    Toast.makeText(PubSubActivityTemp.this, "Storage not 
          available", Toast.LENGTH_SHORT).show();
                });

            Log.d("I'm here", "Position 5");
        }
    }.start();
}

public void mqtt() {


    // tvStatus = (TextView) findViewById(R.id.tvStatus);
    // tvLastMessage = (TextView) findViewById(R.id.tvLastMessage);


    // MQTT client IDs are required to be unique per AWS IoT account.
    // This UUID is "practically unique" but does not _guarantee_
    // uniqueness.
    clientId = UUID.randomUUID().toString();

    // Initialize the AWS Cognito credentials provider
    credentialsProvider = new CognitoCachingCredentialsProvider(
            // getApplicationContext(), // context
            TempApplication.getAppContext(),
            COGNITO_POOL_ID, // Identity Pool ID
            MY_REGION // Region
    );

    Region region = Region.getRegion(MY_REGION);

    // MQTT Client
    mqttManager = new AWSIotMqttManager(clientId,         
      CUSTOMER_SPECIFIC_ENDPOINT);

    // Set keepalive to 10 seconds.  Will recognize disconnects more 
    quickly but will also send
    // MQTT pings every 10 seconds.
    mqttManager.setKeepAlive(10);

    // Set Last Will and Testament for MQTT.  On an unclean disconnect 
      (loss of connection)
    // AWS IoT will publish this message to alert other clients.
    AWSIotMqttLastWillAndTestament lwt = new 
    AWSIotMqttLastWillAndTestament("my/lwt/topic",
            "Android client lost connection", AWSIotMqttQos.QOS0);
    mqttManager.setMqttLastWillAndTestament(lwt);

    // IoT Client (for creation of certificate if needed)
    mIotAndroidClient = new AWSIotClient(credentialsProvider);
    mIotAndroidClient.setRegion(region);

    keystorePath = getFilesDir().getPath();
    keystoreName = KEYSTORE_NAME;
    keystorePassword = KEYSTORE_PASSWORD;
    certificateId = CERTIFICATE_ID;

    // To load cert/key from keystore on filesystem
    try {
        if (AWSIotKeystoreHelper.isKeystorePresent(keystorePath, 
         keystoreName)) {
            if (AWSIotKeystoreHelper.keystoreContainsAlias(certificateId, 
            keystorePath,
                    keystoreName, keystorePassword)) {
                Log.i(LOG_TAG, "Certificate " + certificateId
                        + " found in keystore - using for MQTT.");
                // load keystore from file into memory to pass on 
                    connection
                clientKeyStore = 
             AWSIotKeystoreHelper.getIotKeystore(certificateId,
                        keystorePath, keystoreName, keystorePassword);
                // btnConnect.setEnabled(true);
            } else {
                Log.i(LOG_TAG, "Key/cert " + certificateId + " not found 
           in keystore.");
            }
        } else {
            Log.i(LOG_TAG, "Keystore " + keystorePath + "/" + keystoreName 
       + " not found.");
        }
    } catch (Exception e) {
        Log.e(LOG_TAG, "An error occurred retrieving cert/key from 
     keystore.", e);
    }

    if (clientKeyStore == null) {
        Log.i(LOG_TAG, "Cert/key was not found in keystore - creating new 
    key and certificate.");

        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    // Create a new private key and certificate. This call
                    // creates both on the server and returns them to the
                    // device.
                    CreateKeysAndCertificateRequest 
        createKeysAndCertificateRequest =
                            new CreateKeysAndCertificateRequest();
                    createKeysAndCertificateRequest.setSetAsActive(true);
                    final CreateKeysAndCertificateResult 
          createKeysAndCertificateResult;
                    createKeysAndCertificateResult =

       mIotAndroidClient.createKeysAndCertificate
        (createKeysAndCertificateRequest);
                    Log.i(LOG_TAG,
                            "Cert ID: " +

            createKeysAndCertificateResult.getCertificateId() +
                                    " created.");

                    // store in keystore for use in MQTT client
                    // saved as alias "default" so a new certificate isn't
                    // generated each run of this application

           AWSIotKeystoreHelper.saveCertificateAndPrivateKey
          (certificateId,

   createKeysAndCertificateResult.getCertificatePem(),

   createKeysAndCertificateResult.getKeyPair().getPrivateKey(),
                            keystorePath, keystoreName, keystorePassword);

                    // load keystore from file into memory to pass on
                    // connection
                    clientKeyStore = 
             AWSIotKeystoreHelper.getIotKeystore(certificateId,
                            keystorePath, keystoreName, keystorePassword);

                    // Attach a policy to the newly created certificate.
                    // This flow assumes the policy was already created in
                    // AWS IoT and we are now just attaching it to the
                    // certificate.
                    AttachPrincipalPolicyRequest policyAttachRequest =
                            new AttachPrincipalPolicyRequest();

       policyAttachRequest.setPolicyName(AWS_IOT_POLICY_NAME);

      policyAttachRequest.setPrincipal(createKeysAndCertificateResult
                            .getCertificateArn());

      mIotAndroidClient.attachPrincipalPolicy(policyAttachRequest);

                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            // btnConnect.setEnabled(true);
                        }
                    });
                } catch (Exception e) {
                    Log.e(LOG_TAG,
                            "Exception occurred when generating new 
       private key and certificate.",
                            e);
                }

            }
        }).start();
    }
    connect();
    subscribe();
   }

   public void connect() {

    try {
        mqttManager.connect(clientKeyStore, new 
   AWSIotMqttClientStatusCallback() {
            @Override
            public void onStatusChanged(final AWSIotMqttClientStatus 
       status,
                                        final Throwable throwable) {
                Log.d(LOG_TAG, "Status = " + String.valueOf(status));

                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        if (status == AWSIotMqttClientStatus.Connecting) {
                            tvStatus.setText("Connecting...");

                        } else if (status == 
                AWSIotMqttClientStatus.Connected) {
                            tvStatus.setText("Connected");

                        } else if (status == 
             AWSIotMqttClientStatus.Reconnecting) {
                            if (throwable != null) {
                                Log.e(LOG_TAG, "Connection error.", 
            throwable);
                            }
                            tvStatus.setText("Reconnecting");
                        } else if (status == 
             AWSIotMqttClientStatus.ConnectionLost) {
                            if (throwable != null) {
                                Log.e(LOG_TAG, "Connection error.", 
         throwable);
                            }
                            tvStatus.setText("Disconnected");
                        } else {
                            tvStatus.setText("Disconnected");

                        }
                    }
                });
            }
        });
    } catch (final Exception e) {
        Log.e(LOG_TAG, "Connection error.", e);
        tvStatus.setText("Error! " + e.getMessage());
    }
    }

       public void subscribe() {
    try {
        mqttManager.subscribeToTopic(topic, AWSIotMqttQos.QOS0,
                new AWSIotMqttNewMessageCallback() {
                    @Override
                    public void onMessageArrived(final String topic, final 
            byte[] data) {
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                try {
                                    String message = new String(data, 
                         "UTF-8");
                                    Log.d(LOG_TAG, "Message arrived:");
                                    Log.d(LOG_TAG, "   Topic: " + topic);
                                    Log.d(LOG_TAG, " Message: " + 
             message);

                                    //       
             tvLastMessage.setText(message);

                                } catch (UnsupportedEncodingException e) {
                                    Log.e(LOG_TAG, "Message encoding 
            error.", e);
                                }
                            }
                        });
                    }
                });
    } catch (Exception e) {
        Log.e(LOG_TAG, "Subscription error.", e);
    }
    }

    }

Here is the output from logcat. I ahve filtered out only necessary output. I am not getting any warning or errors:

  09-30 11:55:23.662 5705-6268/com.simran.powermanagement D/I'm here: 
  Position 0
  09-30 11:55:23.663 5705-6268/com.simran.powermanagement D/I'm here: 
  Position 1
 Position 2
 09-30 11:55:23.665 5705-6269/com.simran.powermanagement D/I'm here: 
  Position 3
 09-30 11:55:23.665 5705-6269/com.simran.powermanagement D/I'm here: 
    Position 5

Solution

  • Toast needs context and when you instantiate an Activity class using new you just create a java class that it has no context.if you need some method of your activity you must send your activity or its context object to your Job class and use it for create your activity. like this :

    public class PubSubActivityTemp extends Activity {
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        yourJob job=new yourJob (this);
    }
    }
    

    in your job class :

    public class TempJob extends Job {
    Activity activity;
    public TempJob (Activity activity){
    this.activity=activity;
    PubSubActivityTemp worker=(PubSubActivityTemp)activity;
    }
    }
    

    if you you don't want to create your job in PubSubActivityTemp i suggest you use this way to instantiate PubSubActivityTemp : first create a class that extends Application class :

    public class Myapp extends Application{
    public PubSubActivityTemp pubSubActivityTemp;
    
    }
    

    in AndroidManifast.xml file in <application> tag use this class for name attribute :

    <application name=".Myapp ">
    

    in your PubSubActivityTemp onCreate() methode :

    public class PubSubActivityTemp extends Activity {
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        MyApp myApp=(MyApp) getApplicationContext();// or getApplication();
       myApp.pubSubActivityTemp=this;
    }
    }
    

    in every class you need PubSubActivityTemp activity just send to it getApplicationContext as Context an in it :

    public class TempJob extends Job {
    Activity activity;// or use Context context;
    public TempJob (Activity activity){
    this.activity=activity;
    MyApp myApp=(MyApp)activity.getApplicationContext();
    PubSubActivityTemp worker=myApp.pubSubActivityTemp;
      }
    }
    

    in another class that you need job :

    public class AnotherActivity extends Activity{
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        TempJob job=new TempJob(this);
    }
    }
    

    and if you just want to find out some code working you can log it with Log.v()instead Toast