I'm having trouble with some async programming within an Android application. I have some code in the ClientLocation class that gets the user's lat/lon, but once I get them I need to pass them to a function. When stepping through the code I can see that the repository.getDeals call is run before the gotLocation closure is entered.
Here's the important bit of code:
...
this.repository = Repository.getInstance();
ClientLocation.LocationResult locationResult = new ClientLocation.LocationResult() {
#Override
public void gotLocation(Location location) {
userLatitude = Double.toString(location.getLatitude());
userLongitude = Double.toString(location.getLongitude());
}
};
ClientLocation clientLocation = new ClientLocation();
clientLocation.getLocation(getApplication().getApplicationContext(), locationResult);
// I need the latitude and longitude values at this point in order to properly call getDeals
// currently when this is called the userLat/lon values are 0.0 because gotLocation didn't run yet
deals = repository.getDeals(searchQuery, maxDistInKm, userLatitude, userLongitude);
What's a pattern where getDeals won't be called before gotLocation has completed running? New to async programming so any other tips are welcome!
Here:
boolean isFinished = false
Thread {
this.repository = Repository.getInstance();
ClientLocation.LocationResult locationResult = new
ClientLocation.LocationResult() {
#Override
public void gotLocation(Location location) {
userLatitude = Double.toString(location.getLatitude());
userLongitude = Double.toString(location.getLongitude());
isFinished = true
}
};
while(true){
if(isFinished ) break:
}
ClientLocation clientLocation = new ClientLocation()
clientLocation.getLocation(getApplication().getApplicationContext(), locationResult);
deals = repository.getDeals(searchQuery, maxDistInKm,
userLatitude, userLongitude);
Thread.currentThread().interrupt()
}
Related
I'm new to android programming and I'm having a problem with my codes. Can anyone help me or point out the cause of my error because I'm not really sure why it's giving me a NullPointerException when its a text view or if that is possible.
LogCat:
java.lang.NullPointerException: Attempt to invoke virtual method 'double java.lang.Double.doubleValue()' on a null object reference
at com.example.app.rosbridge.MainActivity$2$1.run(MainActivity.java:133)
Here is the code for that line:
current.setText(String.format("%.4f%s", batteryStateData.msg.current * Math.pow(10, 6), "A"));
But when i run my app my voltage is setting null and here is the code for the voltage:
voltage.setText(String.format("%.4f%s", batteryStateData.msg.voltage, "v"));
Here is the full code:
public class MainActivity extends Activity {
private TextView voltage, current, percentage, status;
private SubscribedData<BatteryState> batteryStateData;
private RosbridgeListener rosbridge;
private boolean subscribed = false;
private boolean advertised = false;
/** Indicates that Lint should ignore the specified warnings for the annotated element. */
#SuppressLint("ClickableViewAccessibility")
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_activity);
Button settings_btn = (Button) findViewById(R.id.connect_btn);
voltage = findViewById(R.id.voltage_txt);
current = findViewById(R.id.current_txt);
percentage = findViewById(R.id.percentage_txt);
status = findViewById(R.id.status_txt);
connectButton = findViewById(R.id.connect_btn);
batteryStateData = new SubscribedData<>();
final Type batteryStateType = new TypeToken<SubscribedData<BatteryState>>() {
}.getType();
// ROSBRIDGE protocol allows access to underlying ROS messages and services as serialized JavaScript Object Notation (JSON) objects
WebSocket protocol communicates to a server for the connection from a user's web browser
//A connection to the rosbridge thru the IP address of the robot from the socket
rosbridge = new RosbridgeListener("ws://10.24.204.231:9090");
rosbridge.setOnDataReceivedListener(new RosbridgeMessageListener() {
// a running thread that when the connection is made the data of the topic will serialize and deserialized java objects to (and from) JSON. #param msg
#Override
public void onDataReceived(final String msg) {
try {
runOnUiThread(new Runnable() {
#Override
public void run() {
batteryStateData = new Gson().fromJson(msg, batteryStateType);
voltage.setText(String.format("%.4f%s", batteryStateData.msg.voltage, "v"));
current.setText(String.format("%.4f%s", batteryStateData.msg.current * Math.pow(10, 6), "A"));
percentage.setText(String.format("%.2f%s", batteryStateData.msg.percentage, "%"));
status.setText(String.format("%s", PowerSupplyStatus.values()[batteryStateData.msg.powerSupplyStatus]));
}
});
Log.d("B9T", String.format("Received data: %s", msg));
}
catch (Exception e)
{
e.printStackTrace();
}
}
});
connectButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (!subscribed) {
rosbridge.Subscribe("/battery", "sensor_msgs/BatteryState");
subscribed = true;
connectButton.setText("Disconnect");
} else {
rosbridge.UnSubscribe("/battery");
subscribed = false;
connectButton.setText("Connect");
}
}
});
Everytime when you are setting the text to textview, you must need to check if it is not null.
You can check null before you set text on textview like the following.
#Override
public void run() {
batteryStateData = new Gson().fromJson(msg, batteryStateType);
// check null before set text or calculate something
if(batteryStateData.msg.current != null){
current.setText(String.format("%.4f%s", batteryStateData.msg.current * Math.pow(10, 6), "A"));
}
// you can check belows like above
voltage.setText(String.format("%.4f%s", batteryStateData.msg.voltage, "v"));
percentage.setText(String.format("%.2f%s", batteryStateData.msg.percentage, "%"));
status.setText(String.format("%s", PowerSupplyStatus.values()[batteryStateData.msg.powerSupplyStatus]));
}
Check weather your created class with GSON is not null
and then check class fields values is not null or 0.
batteryStateData = new Gson().fromJson(msg, batteryStateType);
if (batteryStateData != null) {
if (batteryStateData.msg.voltage!=0)
voltage.setText(String.format("%.4f%s", batteryStateData.msg.voltage, "v"));
if (batteryStateData.msg.current!=0)
current.setText(String.format("%.4f%s", batteryStateData.msg.current * Math.pow(10, 6), "A"));
if (batteryStateData.msg.percentage!=0)
percentage.setText(String.format("%.2f%s", batteryStateData.msg.percentage, "%"));
if (batteryStateData.msg.values !=null)
status.setText(String.format("%s", PowerSupplyStatus.values()[batteryStateData.msg.powerSupplyStatus]));
}
I want to create a modular class that I can use anytime I want to scan a barcode. Is this possible using Firebase ML Kit?
This is what I've got so far:
public List<FirebaseVisionBarcode> ScanBarcode(int... barcodeFormats)
{
//region Init, config and execution of the barcode scanning
final FirebaseVisionBarcodeDetectorOptions.Builder BUILDER =
new FirebaseVisionBarcodeDetectorOptions.Builder();
//Set barcode formats based on arguments
for (int formats : barcodeFormats)
{
BUILDER.setBarcodeFormats(formats);
}
final FirebaseVisionBarcodeDetectorOptions OPTIONS = BUILDER.build();
final FirebaseVisionImage IMAGE = FirebaseVisionImage.fromBitmap(bitmap);
final FirebaseVisionBarcodeDetector DETECTOR = FirebaseVision.getInstance()
.getVisionBarcodeDetector(OPTIONS);
DETECTOR.detectInImage(IMAGE)
.addOnSuccessListener(new OnSuccessListener<List<FirebaseVisionBarcode>>()
{
#Override
public void onSuccess(List<FirebaseVisionBarcode> _barcodes)
{
barcodes = _barcodes;
}
})
.addOnFailureListener(new OnFailureListener()
{
#Override
public void onFailure(#NonNull Exception e)
{
barcodes = new ArrayList<>();
}
});
//endregion
return barcodes;
Mostly taken from https://firebase.google.com/docs/ml-kit/
The problem here is that the listener, for the DETECTOR, is some kind of async call. Which means that it will return before onSuccess is called.
The barcode scanning part works, but I'm having a hard time wrapping it in a class of it's own.
Thanks.
I figured it out. Not sure if it's the best approach class structure wise, but it works quite nice.
public Task<List<FirebaseVisionBarcode>> ScanBarcode(int... barcodeFormats)
{
//region Init, config and execution of the barcode scanning. Mostly taken from https://firebase.google.com/docs/ml-kit/
final FirebaseVisionBarcodeDetectorOptions.Builder BUILDER =
new FirebaseVisionBarcodeDetectorOptions.Builder();
//Set barcode formats based on arguments
for (int formats : barcodeFormats)
{
BUILDER.setBarcodeFormats(formats);
}
final FirebaseVisionBarcodeDetectorOptions OPTIONS = BUILDER.build();
final FirebaseVisionImage IMAGE = FirebaseVisionImage.fromBitmap(bitmap);
final FirebaseVisionBarcodeDetector DETECTOR = FirebaseVision.getInstance()
.getVisionBarcodeDetector(OPTIONS);
final Task<List<FirebaseVisionBarcode>> DETECT_IMG_TASK = DETECTOR.detectInImage(IMAGE)
.addOnSuccessListener(new OnSuccessListener<List<FirebaseVisionBarcode>>()
{
#Override
public void onSuccess(List<FirebaseVisionBarcode> _barcodes)
{
barcodes = _barcodes;
}
})
.addOnFailureListener(new OnFailureListener()
{
#Override
public void onFailure(#NonNull Exception e)
{
barcodes = new ArrayList<>();
}
});
return DETECT_IMG_TASK;
//endregion
}
public List<FirebaseVisionBarcode> GetBarcodes()
{
return barcodes;
}
detectInImage returns a Task. What I did was return this task. Once this task completes, you can call GetBarcodes to obtain the parsed data. I hate to force calling additional methods to get the final results, but it was the only way I could get it to work.
on API > 21 when my phone is locked this service is stop working (when I wake up a phone a service is starting working). This is what I do :
public class JobDispacherService extends JobService {
private Preferences prefs = null;
public static final String GCM_ONEOFF_TAG = "oneoff|[0,0]";
public static final String GCM_REPEAT_TAG = "komunalRepeat|[7200,1800]";
private static final String TAG = JobDispacherService.class.getSimpleName();
private UplaudPossitionTask uplaudPossitionTask;
#Override
public boolean onStartJob(#NonNull JobParameters job) {
uplaudPossitionTask = new UplaudPossitionTask() {
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
jobFinished(job, false);
}
};
uplaudPossitionTask.execute();
return false; // Answers the question: "Is there still work going on?"
}
#Override
public boolean onStopJob(JobParameters job) {
return true; // Answers the question: "Should this job be retried?"
}
private class UplaudPossitionTask extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... params) {
uploadPosition();
return null;
}
}
}
And I call this service just like this :
FirebaseJobDispatcher dispatcher = new FirebaseJobDispatcher(new GooglePlayDriver(context));
Job myJob = dispatcher.newJobBuilder()
.setService(JobDispacherService.class)
.setTag("my-unique-tag")
.setRecurring(true)
.setLifetime(Lifetime.FOREVER)
.setTrigger(Trigger.executionWindow(10, (int) 15))
.setReplaceCurrent(false)
.setRetryStrategy(RetryStrategy.DEFAULT_EXPONENTIAL)
.setConstraints(Constraint.ON_ANY_NETWORK)
.build();
dispatcher.mustSchedule(myJob);
I want to repeat this time all the time and I do not have idea why this service is stop wrking when my phone is locked more than 1h
WorkManager :
public static void refreshCouponPeriodicWork() {
//define constraints
Constraints myConstraints = new Constraints.Builder()
.setRequiresDeviceIdle(false)
.setRequiresCharging(false)
.setRequiredNetworkType(NetworkType.CONNECTED)
.setRequiresBatteryNotLow(true)
.setRequiresStorageNotLow(true)
.build();
Data source = new Data.Builder()
.putString("workType", "PeriodicTime")
.build();
PeriodicWorkRequest refreshCpnWork =
new PeriodicWorkRequest.Builder(RefreshLatestCouponWorker.class, 10, TimeUnit.HOURS,30, TimeUnit.SECONDS)
.setConstraints(myConstraints)
.setInputData(source)
.build();
WorkManager.getInstance().enqueue(refreshCpnWork);
}
public class RefreshLatestCouponWorker extends Worker {
private Preferences prefs = null;
public RefreshLatestCouponWorker(#NonNull Context context, #NonNull WorkerParameters workerParams) {
super(context, workerParams);
}
#NonNull
#Override
public Worker.Result doWork() {
//read input argument
String workType = getInputData().getString("workType");
Log.i("refresh cpn work", "type of work request: " + workType);
uploadPosition();
//sending work status to caller
return success();
}
}
I do this for work manager but task run only once and never is repeating
I suggest you read about WorkManager, that will be the correct solution for you. The WorkManager API makes it easy to schedule deferrable, asynchronous tasks that are expected to run even if the app exits or device restarts. You can define Periodic requests with specified time interval and device state. Revert in case you find the implementation difficult, i could help you with it.
I’m trying to write a utility class to wrap the Google Play Services FusedLocationProviderClient API and location permissions request as I’m sick of writing all that boilerplate every time I want to add location functionality to an app. The problem I’m having though is I’m unable to remove location updates once I’ve started them. Here’s the relevant bits of my utility class:
public class UserLocationUtility extends LocationCallback
{
// Hold a WeakReference to the host activity (allows it to be garbage-collected to prevent possible memory leak)
private final WeakReference<Activity> weakActivity;
// Debug tag
private static final String TAG = "UserLocationUtility";
public static class RequestCodes
{
static final int CURRENT_LOCATION_ONE_TIME = 0;
static final int CURRENT_LOCATION_UPDATES = 1;
static final int LAST_KNOWN_LOCATION = 2;
static final int SMART_LOCATION = 3;
}
private FusedLocationProviderClient mLocationClient;
private Context mContext;
private LocationRequest mLocationRequest;
/* Constructor */
UserLocationUtility(Activity activity){
// assign the activity to the weak reference
this.weakActivity = new WeakReference<>(activity);
// Hold a reference to the Application Context
this.mContext = activity.getApplicationContext();
// Instantiate our location client
this.mLocationClient = LocationServices.getFusedLocationProviderClient(mContext);
// Set up the default LocationRequest parameters
this.mLocationRequest = new LocationRequest();
setLocationRequestParams(2000, 500, LocationRequest.PRIORITY_HIGH_ACCURACY);
// Sets up the LocationRequest with an update interval of 30 seconds, a fastest
// update interval cap of 5 seconds and using balanced power accuracy priority.
} /* Note: values for testing only. Will be dialed back for better power management when testing complete */
/* Stripped out other methods for brevity */
#SuppressLint("MissingPermission")
public void getCurrentLocationOneTime(final UserLocationCallback callback){
mLocationClient.requestLocationUpdates(mLocationRequest, new LocationCallback()
{
#Override
public void onLocationResult(LocationResult locationResult){
if (locationResult == null){
callback.onFailedRequest("getCurrentLocationOneTime(): Request failed: returned null");
return;
}
callback.onLocationResult(locationResult.getLastLocation());
stopLocationUpdates(); /* Stopping location updates here just for testing (NOT WORKING!!) */
}
}, null);
}
public void stopLocationUpdates(){
mLocationClient.removeLocationUpdates(new LocationCallback(){});
Log.i(TAG, "stopLocationUpdates(): Location updates removed");
}
}
Here’s how I’m trying to use it (from MainActivity):
UserLocationUtility locationUtility;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
locationUtility = new UserLocationUtility(this);
if (locationUtility.checkPermissionGranted()){
Log.i(TAG, "Permissions are granted.");
getLocationUpdates();
} else {
Log.i(TAG, "Permissions are not granted. Attempting to request...");
locationUtility.requestPermissions(UserLocationUtility.RequestCodes.CURRENT_LOCATION_UPDATES);
}
}
public void getLocationUpdates(){
locationUtility.getCurrentLocationOneTime(new UserLocationCallback() {
#Override
public void onLocationResult(Location location) {
Log.i(TAG, "getLocationUpdates result: " + location.toString());
}
#Override
public void onFailedRequest(String result) {
Log.e(TAG, "LocationUpdates result: " + result);
}
});
}
And here's a sample from the log:
I/MainActivity: getLocationUpdates result: Location[fused 34.421998,-125.084000 hAcc=731 et=+2h10m52s694ms vAcc=??? sAcc=??? bAcc=???]
I/UserLocationUtility: stopLocationUpdates(): Location updates removed
I/MainActivity: getLocationUpdates result: Location[fused 34.421998,-125.084000 hAcc=739 et=+2h10m57s697ms vAcc=??? sAcc=??? bAcc=???]
I/UserLocationUtility: stopLocationUpdates(): Location updates removed
I/MainActivity: getLocationUpdates result: Location[fused 34.421998,-125.084000 hAcc=763 et=+2h11m5s723ms vAcc=??? sAcc=??? bAcc=???]
I/UserLocationUtility: stopLocationUpdates(): Location updates removed
etc...
As you can see I’m receiving the location updates correctly but the call to stopLocationUpdates() isn’t working. I have a feeling it’s something to do with the fact that I’m passing a new LocationCallback to the removeUpdates() method, but I’m not sure what the alternative is, or even if there is an alternative. This being a non-activity class I can’t exactly initialise LocationCallback as a member in onCreate() then pass it around as needed. The google docs on this aren’t much help at all. Whether that’s because I lack the necessary understanding to decipher them or because they’re just not very good I don’t know but either way I’m stumped and having searched around a lot I can’t seem to find an existing answer elsewhere.
Thanks.
Posting my solution as an answer in case it helps anyone else.
I got it working by declaring a LocationCallback as a member variable and then initialising (or re-initialising) it in each method that requires it...
public void getCurrentLocationUpdates(final UserLocationCallback callback){
if (mIsReceivingUpdates){
callback.onFailedRequest("Device is already receiving updates");
return;
}
// Set up the LocationCallback for the request
mLocationCallback = new LocationCallback()
{
#Override
public void onLocationResult(LocationResult locationResult){
if (locationResult != null){
callback.onLocationResult(locationResult.getLastLocation());
} else {
callback.onFailedRequest("Location request returned null");
}
}
};
// Start the request
mLocationClient.requestLocationUpdates(mLocationRequest, mLocationCallback, null);
// Update the request state flag
mIsReceivingUpdates = true;
}
I check at the beginning of the method whether or not location updates are already being received and get out early if so. This prevents duplicate (and thus unstoppable) location update requests being initiated.
Calling the stopLocationUpdates (below for reference) method now works as it should.
public void stopLocationUpdates(){
mLocationClient.removeLocationUpdates(mLocationCallback);
mIsReceivingUpdates = false;
Log.i(TAG, "Location updates removed");
}
Here is my code:
public String addxyz ()
{
String returnStatus = "";
DBConnection conn = new DBConnection();
returnStatus = conn.fun_GetData();
ArrayList<String> emailList = new ArrayList<String>();
emailList.add("xyz#gmail.com");
emailList.add("asd#hotmail.com");
for(String email : emailList)
{
SendEmail sendEmail = new SendEmail();
boolean statusEmail = sendEmail.SendingEmail(email);
}
return returnStatus;
}
I want to know what is the best way to send email to every email address after returning method status.
For example I have 100 email list so the above method is first sending 100 email then return status.
But i want to return something then send email so is that possible?
You have to send emails asynchronously then.
You can very well right a multi threaded program wherein you are sending emails in a different executor thread and main thread returns back with a status without getting blocked on sending the emails.
You can use Java Executors api for this one.
For multi threading you can do like this:
public String addxyz (String qweqw)
{
String returnStatus = "status";
ArrayList<String> emailList = new ArrayList<String>();
emailList.add("xyz#gmail.com");
emailList.add("asd#hotmail.com");
for(String email : emailList)
{
// create a thread
Thread th = new Thread(){
#Override
public void run(){
// Your SendMail logic
SendEmail sendEmail = new SendEmail();
boolean statusEmail = sendEmail.SendingEmail(email);
}
};
th.start(); // start the thread & continue to next email
}
return returnStatus;
}
From the snippet in your question, the status and parameter seem completely useless. So you could do:
// in main execution path
String returnStatus = "status";
new Thread( new Runnable() {
#Override public void run(){ addxyz("dummy"); }
} ).start();
But I really doubt that this will work out. I guess your example misses where and why status could be changed in the function. Then this solution is void!
UPDATE
From the point where your status won't change inside the function, you can wrap the rest in a Thread/Runnable and run it. For example:
....
returnStatus = conn.fun_GetData();
new Thread( new Runnable() { #Override public void run() {
ArrayList<String> emailList = new ArrayList<String>();
emailList.add("xyz#gmail.com");
emailList.add("asd#hotmail.com");
for(String email : emailList)
{
SendEmail sendEmail = new SendEmail();
boolean statusEmail = sendEmail.SendingEmail(email);
}
}}).start();
return returnStatus;
In Java 8 you can also use Lambda:
new Thread( () -> {
// your code here
} ).start();