Why is my String initialization throwing a NullPointerError? - java

I've been writing an android application in Android Studio with the purpose of getting a JSONObject from the Google directions API (using the Volley library), then passing it to a new activity (where it will then just be printed, so that I can debug prior to working on parsing it). However upon running the app on my phone through ADB, LogCat returns this.
The method called by a submit button's onClick (which is when the app crashes) is:
public void submit(View view) {
Location location = LocationServices.FusedLocationApi.getLastLocation(locationClient);
String destination = findViewById(R.id.destinationInput).toString();
String url = "https://maps.googleapis.com/maps/api/directions/json?origin="
+ location.getLatitude()
+ location.getLongitude()
+ "&destination=" + destination
+ "&mode=driving"
+ avoids()
+ "departure_time=now"
+ "&key=" + getString(R.string.API_KEY);
RequestQueue requestQueue;
// Instantiate the cache
Cache cache = new DiskBasedCache(getCacheDir(), 1024 * 1024); // 1MB cap
// Set up the network to use HttpURLConnection as the HTTP client.
Network network = new BasicNetwork(new HurlStack());
// Instantiate the RequestQueue with the cache and network.
requestQueue = new RequestQueue(cache, network);
// Start the queue
requestQueue.start();
JsonObjectRequest jsObjRequest = new JsonObjectRequest
(Request.Method.GET, url, null, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject dirs) {
Intent intent;
intent = new Intent(getApplicationContext(), DisplayDirections.class);
intent.putExtra("DIRECTIONS", dirs.toString());
startActivity(intent);
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
}
});
// Add the request to the RequestQueue.
requestQueue.add(jsObjRequest);
}
private String avoids() {
String avoid = "avoid=";
boolean any = false;
if(((Switch) findViewById(R.id.avoidTollsSwitch)).isChecked()) {
avoid += "tolls";
any = true;
}
if(((Switch) findViewById(R.id.avoidMotorwaysSwitch)).isChecked()) {
if(any) avoid += "|";
avoid += "highways";
any = true;
}
if(((Switch) findViewById(R.id.avoidFerriesSwitch)).isChecked()) {
if(any) avoid += "|";
avoid += "ferries";
any = true;
}
if(any) return avoid;
else return "";
}
The LogCat log links to the line String url =, but I'm confused as to what's wrong with this line. As far as I can tell, my code should work...
Volley tutorial: https://developer.android.com/training/volley/simple.html

Are you sure that location is not null? Put a breakpoint on the String url = line and see what its value is.

If you are running it on the emulator you need to have sent coordinates to the emulator. Otherwise location will be null.
I was pulling my hair over it the first time I used geolocation services.
Just do a check like
if (location!=null) {
foo.doSomethingWithLocation(bar);
} else {
Log.d(TAG, "Sorry. Location is null");
}
before you call anything

Related

Automatically reply to Message recieved by Broadcastreciever

Good day everyone.
I would like to make an application which replies to received SMS automatically.
For example.
Jon Doe sends me - "Hi", Application gets the message body, checks it with my database where I have a potential response:
ID | Text | Potential Answer
01 | Hi | Hello how are you?
and Application sends the Potential response.
So far what I have achieved -
App receives the Message, checks it with the database ( using Like '%') and gets the correct "Potential Answer" Column and passes it as message text body, but to send it I am using a button.
My Reciever is a sperate file class
public class MyReceiver extends BroadcastReceiver {
public static String textSmsbody="";
private static final String TAG=MyReceiver.class.getSimpleName();
public static final String pdu_type="pdus";
#TargetApi(Build.VERSION_CODES.M)
#Override
public void onReceive(Context context, Intent intent) {
// Get the SMS message.
Bundle bundle = intent.getExtras();
SmsMessage[] msgs;
String strMessage = "";
String format = bundle.getString("format");
// Retrieve the SMS message received.
Object[] pdus = (Object[]) bundle.get(pdu_type);
if (pdus != null) {
// Check the Android version.
boolean isVersionM =
(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M);
// Fill the msgs array.
msgs = new SmsMessage[pdus.length];
for (int i = 0; i < msgs.length; i++) {
// Check Android version and use appropriate createFromPdu.
if (isVersionM) {
// If Android version M or newer:
msgs[i] = SmsMessage.createFromPdu((byte[]) pdus[i], format);
} else {
// If Android version L or older:
msgs[i] = SmsMessage.createFromPdu((byte[]) pdus[i]);
}
// Build the message to show.
String a=msgs[i].getMessageBody();
textSmsbody=msgs[i].getMessageBody();
if (a.contains("?")) {
strMessage=msgs[i].getOriginatingAddress();
// strMessage += " :" + msgs[i].getMessageBody() + "\n";
}
else {
strMessage=a;
// strMessage += "SMS from" + msgs[i].getOriginatingAddress();
// strMessage += "ELSE:" + msgs[i].getMessageBody() + "\n";
}
// Log and display the SMS message.
Log.d(TAG, "onReceive: " + strMessage);
Toast.makeText(context, strMessage, Toast.LENGTH_LONG).show();
}
}
}
}
Sending method is in my MainActivity.
public void smsSendMessage(View view) {
databaseSearch();
// Set the destination phone number to the string in editText.
String destinationAddress = "2020";
// Find the sms_message view.
// Get the text of the SMS message.
String smsMessage = sendingText;
// Set the service center address if needed, otherwise null.
String scAddress = null;
// Set pending intents to broadcast
// when message sent and when delivered, or set to null.
PendingIntent sentIntent = null, deliveryIntent = null;
// Use SmsManager.
SmsManager smsManager = SmsManager.getDefault();
smsManager.sendTextMessage
(destinationAddress, scAddress, smsMessage,
sentIntent, deliveryIntent);
}
In layout I have a button which calls smsSendMessage () ;
My question is how I can make it automatically without button.
When the phone receives a message, the app shall check it with the database and send it by itself.
Please tell me if you need to see my Manifest file, or databasehelper.
Using JobService should be a suitable option in your case.
Create a JobService class like that
#RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public class ExampleJobService extends JobService {
#Override
public boolean onStartJob(JobParameters params) {
//send a message
return true;
}
#Override
public boolean onStopJob(JobParameters params) {
return true;
}
}
Also Declare In your Manifest
<service
android:name=".ExampleJobService"
android:permission="android.permission.BIND_JOB_SERVICE" />
Now in your Receiver, you can start it like that
ComponentName componentName = new ComponentName(context, ExampleJobService.class);
PersistableBundle bundle = new PersistableBundle();
bundle.putLong("lat", lat);
bundle.putLong("lon", lon);
JobInfo jobInfo = new JobInfo.Builder(0, componentName)
.setExtras(bundle)
.build();
For more details about JobServices https://www.vogella.com/tutorials/AndroidTaskScheduling/article.html

Location Tracking Service slows app down

for a project I needed an app that opens a webpage in a webview and at the same time tracks the users location, even if the phone is not active or another app is in front.
I got this working and everything works as it should. The location is retrieved and the server is able to work with the locations.
The problem is, that if I switch back into the app after more than two hours of background tracking, everything is slowed down and the response time in the webview is very bad.
It seems as if the location service is slowing down the app. Before the service was installed this problem did not exist. I cant explain, what causes the app to lack, maybe somebody can help me.
This is the code of my location service. It gets called as an Intent in the onCreate of the Webview. The Locations gets written in a string buffer that gets uploaded to a server. (Some empty override functions are left out)
public class MyLocationService extends Service {
double latService;
double lngService;
long timeService;
float accService;
long oldtime;
String hash = "";
String buffer = "";
private LocationManager lm;
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
final Handler handler = new Handler();
final Runnable r = new Runnable() {
public void run() {
LocationUpdates();
if ((timeService > 0) && (oldtime != timeService)) {
oldtime = timeService;
if (buffer.equals("")) {
buffer += latService + "," + lngService + "," + accService + "," + timeService;
} else {
buffer += ";" + latService + "," + lngService + "," + accService + "," + timeService;
}
AsyncHttpClient client = new AsyncHttpClient();
RequestParams params = new RequestParams();
params.put("d", buffer);
client.post("server.php", params, new TextHttpResponseHandler() {
#Override
public void onSuccess(int arg0, Header[] arg1, String arg2) {
System.out.println(arg2);
buffer = "";
}
});
}
handler.postDelayed(this, 15000);
}
};
handler.postDelayed(r, 10);
return Service.START_NOT_STICKY;
}
public void LocationUpdates() {
locListener locList = new locListener();
lm = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locList);
}
public class locListener implements LocationListener {
#Override
public void onLocationChanged(Location location) {
latService = location.getLatitude();
lngService = location.getLongitude();
timeService = Math.round(location.getTime() / 1000);
accService = location.getAccuracy();
}
}
}
Thanks in advance for any help.
I would highly recommend using the Fused location provider with PRIORITY_BALANCED_POWER_ACCURACY:
LocationRequest request = LocationRequest.create()
.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY)
.setInterval(POLLING_INTERVAL)
.setFastestInterval(POLLING_INTERVAL/2)
.setSmallestDisplacement(MIN_INTERVAL_METERS);
It is designed to provide you with a in a 40 meter range accuracy with battery consumption <= 0.6%/hour.
Also remember to turn location listening off immediately when no longer needed.

Download Manager Unable to Resume Download in case of Internet Disconnection and System Reboot

I have created a simple application which is supposed to download large zip files. After some R&D I came to the conclusion that I have to use Download Manager to achieve this. I want the download to resume automatically if the device is restarted or in case of unstable internet connectivity. Right now, the code is able to download large files as expected, but in case of internet connectivity fluctuations or system restart, it stops downloading.
The activity:
public class MainActivity extends ActionBarActivity {
String Download_path = "http://wickedbrains.com/map/mumbai.zip";
String Download_ID = "DOWNLOAD_ID";
SharedPreferences preferenceManager;
DownloadManager downloadManager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
preferenceManager = PreferenceManager.getDefaultSharedPreferences(this);
downloadManager = (DownloadManager)getSystemService(DOWNLOAD_SERVICE);
Button btnDownload = (Button)findViewById(R.id.download);
btnDownload.setOnClickListener(new Button.OnClickListener(){
#Override
public void onClick(View arg0) {
// Locate storage location
String filepath = "";
File folder = new File(
Environment.getExternalStorageDirectory() + "/osmdroid");
boolean success = true;
if (!folder.exists()) {
success = folder.mkdir();
}
if (success) {
// Do something on success
filepath = Environment.getExternalStorageDirectory()
.getPath() + "/osmdroid";
// Deleting if zip file exists
File folder2 = Environment.getExternalStorageDirectory();
String fileName = folder2.getPath() + "/osmdroid/mumbai.zip";
File myFile = new File(fileName);
if(myFile.exists())
myFile.delete();
}
//Starting download manager to download file
Uri Download_Uri = Uri.parse(Download_path);
DownloadManager.Request request = new DownloadManager.Request(Download_Uri);
long download_id = downloadManager.enqueue(request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI |DownloadManager.Request.NETWORK_MOBILE)
.setAllowedOverRoaming(false)
.setTitle("Test")
.setDescription("Map Download")
.setDestinationInExternalPublicDir("/osmdroid","mumbai.zip"));
// long download_id = downloadManager.enqueue(request);
//Save the download id
Editor PrefEdit = preferenceManager.edit();
PrefEdit.putLong(Download_ID, download_id);
PrefEdit.commit();
}});
}
#Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
IntentFilter intentFilter = new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE);
registerReceiver(downloadReceiver, intentFilter);
}
#Override
protected void onPause() {
// TODO Auto-generated method stub
super.onPause();
unregisterReceiver(downloadReceiver);
}
private BroadcastReceiver downloadReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context arg0, Intent arg1) {
// TODO Auto-generated method stub
DownloadManager.Query query = new DownloadManager.Query();
query.setFilterById(preferenceManager.getLong(Download_ID, 0));
Cursor cursor = downloadManager.query(query);
if(cursor.moveToFirst()){
int columnIndex = cursor.getColumnIndex(DownloadManager.COLUMN_STATUS);
int status = cursor.getInt(columnIndex);
int columnReason = cursor.getColumnIndex(DownloadManager.COLUMN_REASON);
int reason = cursor.getInt(columnReason);
if(status == DownloadManager.STATUS_SUCCESSFUL){
//Retrieve the saved download id
long downloadID = preferenceManager.getLong(Download_ID, 0);
ParcelFileDescriptor file;
try {
file = downloadManager.openDownloadedFile(downloadID);
Toast.makeText(MainActivity.this,
"File Downloaded: " + file.toString(),
Toast.LENGTH_LONG).show();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
Toast.makeText(MainActivity.this,
e.toString(),
Toast.LENGTH_LONG).show();
}
}else if(status == DownloadManager.STATUS_FAILED){
Toast.makeText(MainActivity.this,
"FAILED!\n" + "reason of " + reason,
Toast.LENGTH_LONG).show();
}else if(status == DownloadManager.STATUS_PAUSED){
Toast.makeText(MainActivity.this,
"PAUSED!\n" + "reason of " + reason,
Toast.LENGTH_LONG).show();
}else if(status == DownloadManager.STATUS_PENDING){
Toast.makeText(MainActivity.this,
"PENDING!",
Toast.LENGTH_LONG).show();
}else if(status == DownloadManager.STATUS_RUNNING){
Toast.makeText(MainActivity.this,
"RUNNING!",
Toast.LENGTH_LONG).show();
}
}
}
};
}
Where am I going wrong? What should I do to enable the resume capability of the download?
Quoting from docs,
The download manager will conduct the download in the background, taking care of HTTP interactions and retrying downloads after failures or across connectivity changes and system reboots.
I guess Download Manager, by default takes cares of retries.
If you are having issues you can use DownloadManager.Query class and query for COLUMN_STATUS and COLUMN_REASON to get the download status
Edit:
Starting a download
dm = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
Request request = new Request( YOUR_DOWNLOAD_URL );
long enqueue = dm.enqueue(request);
enqueue is more like a download reqeust id. You can use that enqueue to fetch the download progress/status
Querying the download Status
Query query = new Query();
query.setFilterById(enqueue);
Cursor c = dm.query(query);
if (c.moveToFirst()) {
int downloadStatus = c.getInt(c.getColumnIndex(DownloadManager.COLUMN_STATUS));
if (DownloadManager.STATUS_SUCCESSFUL == downloadStatus) {
// download succeded
} else if (DownloadManager.STATUS_FAILED == downloadStatus){
String failedReason = c.getString(c.getColumnIndex(DownloadManager.COLUMN_REASON));
// handle failures
}
}
Haven't tested the code myself. But it should work.
I confirm that this problem still exists in 2020, when testing in an emulator and having WiFi enabled, this error consistently appears (even with Android 10).
Switching off WiFi in the emulator seems to solve the problem.
Try to get the reason for the failed download.
e.g does it work on network switch wifi->data
(If your error reason is 1008- there seems to be a reported bug here
https://code.google.com/p/android/issues/detail?id=18462,
further:
http://papaya-backend.net/2013/04/12/why-http-etag-header-may-cause-your-downloading-apps-on-android-failed/)

How to start a new activity on android client when receive a message from server

I have problem with starting a new activity in android. I have looked through many other questions here, but I didn't find an answer. Here's the problem:
Four classes:
1. WelcomeActivity;
2. MainActivity;
3. PopUpActivity;
4. Client;
At the begining starts WelcomeActivity where you you type all needed credentials to connect to the server, after you clicked the button, string is sent to server. Server send validation string if everything is OK. If OK is received, then MainActivity is started. Users types different things in MainActivity, the presses another button, which send another string to the server. Server processes it (string) and send back a response, also a string. And here's the problem. When server send that last string to client I want to start PopUpActivity, where will be displayed this aprticualr string in TextView.
My code:
Client part (last else if):
public void run() throws Exception {
Socket client = new Socket(ip, port);
in = new BufferedReader(new InputStreamReader(client.getInputStream()));
out = new PrintWriter(client.getOutputStream(), true);
out.println(welcomeActivity.getCredentials());
while (true) {
final String line = in.readLine();
if (line.equals("#GO#")) {
System.out.println("#GO#");
mainActivityIntent = new Intent(welcomeActivity,
MainActivity.class);
welcomeActivity.startActivity(mainActivityIntent);
} else if (line.equals("#CLOSE#")) {
client.close();
break;
} else if (line.startsWith("#RESULTS")) {
Intent i = new Intent(MainActivity.getContext(), PopUpActivity.class);
i.putExtra(line, line);
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
MainActivity.getContext().startActivity(i);
}
}
}
WelcomeActivity:
public void onClick(View v) {
ip = ipText.getText().toString();
port = Integer.parseInt(portText.getText().toString());
login = loginText.getText().toString();
password = passwordText.getText().toString();
credentials = login + "#" + password + "#" + brand + "#" + device + "#"
+ hardware + "#" + manufacturer + "#" + product;
client = new Client(ip, port, this);
new Handler().start();
}
private class Handler extends Thread {
public void run() {
try {
client.run();
} catch (Exception e) {
e.printStackTrace();
}
}
}
PopUpActivity:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_pop_up);
closeButton = (Button) findViewById(R.id.closeButton);
testOutcome = (TextView) findViewById(R.id.textArea);
closeButton.setOnClickListener(this);
//
Bundle extras = getIntent().getExtras();
if (extras == null) {
return;
}
String value = extras.getString(Intent.EXTRA_TEXT);
if (value != null) {
testOutcome.setText(value);
}
}
PopUpActivity is started, but text is not displayed.
Before that I tried to use Context in MainActivity:
final static Context context;
....
public void onCreate() {
context = getBaseContext();
// or context = getApplicationContext();
....
}
...
public static Context getContext() {
return context;
}
And from clint tried to call:
MainActivity.getContext().getTextView().setText(line);
At the begining I tied to call a AlertDialog, but it also was bad, NullPointerException
The problem is with your intent calling, so you may write
i.putExtra("line",line); in your MainActivity
and you can retrieve it by
Intent intent = getIntent(); intent.getStringExtra("line"); in your PopUp Activity.

Google Cloud Messaging - Check if device is already registered

I just set up GCM in my Android App. But I have the problem that I don't know how to check if the device is already registered. I work with the new google play services library.
The register part looks like this:
#Override
protected String doInBackground(String... arg0) {
String msg = "";
try {
if (gcm == null) {
gcm = GoogleCloudMessaging.getInstance(context_app);
}
regid = gcm.register(SENDER_ID);
msg = "Dvice registered, registration ID=" + regid;
Log.d("111", msg);
sendRegistrationIdToBackend(regid);
} catch (IOException ex) {
msg = "Error :" + ex.getMessage();
}
return msg;
}
How can I modify this that it checks if the device is already registered?
Store the registration id in a databade table or shared preference and when app starting..check whether it is null or not
Google has provided very clear documentation with code.You should use following code:
// Make sure the device has the proper dependencies.
GCMRegistrar.checkDevice(this);
// Make sure the manifest was properly set - comment out this line
// while developing the app, then uncomment it when it's ready.
GCMRegistrar.checkManifest(this);
registerReceiver(mHandleMessageReceiver,
new IntentFilter(DISPLAY_MESSAGE_ACTION));
final String regId = GCMRegistrar.getRegistrationId(this);
if (regId.equals("")) {
// Automatically registers application on startup.
GCMRegistrar.register(this, SENDER_ID);
} else {
// Device is already registered on GCM, check server.
if (GCMRegistrar.isRegisteredOnServer(this)) {
// Skips registration.
mDisplay.append(getString(R.string.already_registered) + "\n");
} else {
// Try to register again, but not in the UI thread.
// It's also necessary to cancel the thread onDestroy(),
// hence the use of AsyncTask instead of a raw thread.
final Context context = this;
mRegisterTask = new AsyncTask<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... params) {
boolean registered =
ServerUtilities.register(context, regId);
// At this point all attempts to register with the app
// server failed, so we need to unregister the device
// from GCM - the app will try to register again when
// it is restarted. Note that GCM will send an
// unregistered callback upon completion, but
// GCMIntentService.onUnregistered() will ignore it.
if (!registered) {
GCMRegistrar.unregister(context);
}
return null;
}
#Override
protected void onPostExecute(Void result) {
mRegisterTask = null;
}
};
mRegisterTask.execute(null, null, null);
}
}
#Override
protected void onDestroy() {
if (mRegisterTask != null) {
mRegisterTask.cancel(true);
}
unregisterReceiver(mHandleMessageReceiver);
GCMRegistrar.onDestroy(this);
super.onDestroy();
}
private final BroadcastReceiver mHandleMessageReceiver =
new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String newMessage = intent.getExtras().getString(EXTRA_MESSAGE);
mDisplay.append(newMessage + "\n");
}
};
when you get registration Id, Store it in SharedPreferences, for example:
SharedPreferences shp = context.getSharedPreferences("anyNameYouLike",MODE_PRIVATE);
SharedPreferences.Editor editor=shp.edit();
editor.putString("RegID",registrationID).commit;
In the next time before you register check the "anyNameYouLike" if it contain field called RegID Like this:
private boolean isRegistered(Context context){
SharedPreferences shp = context.getSharedPreferences("anyNameYouLike",PRIVATE_MODE);
return shp.contains("RegID");
}

Categories