I have problem with my music app. I have made a MediaPlayer and application is crashing on this:
2021-08-03 22:54:09.621 6494-6494/com.example.musiclistenerremake E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.musiclistenerremake, PID: 6494
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.musiclistenerremake/com.example.musiclistenerremake.PlayerActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.media.MediaPlayer.start()' on a null object reference
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3270)
...
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.media.MediaPlayer.start()' on a null object reference
at com.example.musiclistenerremake.PlayerActivity.getIntentMethod(PlayerActivity.java:106)
at com.example.musiclistenerremake.PlayerActivity.onCreate(PlayerActivity.java:36)
...
Full logcat log:
2021-08-03 22:54:09.621 6494-6494/com.example.musiclistenerremake E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.musiclistenerremake, PID: 6494
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.musiclistenerremake/com.example.musiclistenerremake.PlayerActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.media.MediaPlayer.start()' on a null object reference
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3270)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3409)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2016)
at android.os.Handler.dispatchMessage(Handler.java:107)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7356)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.media.MediaPlayer.start()' on a null object reference
at com.example.musiclistenerremake.PlayerActivity.getIntentMethod(PlayerActivity.java:106)
at com.example.musiclistenerremake.PlayerActivity.onCreate(PlayerActivity.java:36)
at android.app.Activity.performCreate(Activity.java:7802)
at android.app.Activity.performCreate(Activity.java:7791)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1299)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3245)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3409)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2016)
at android.os.Handler.dispatchMessage(Handler.java:107)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7356)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
2021-08-03 22:54:15.300 6494-6509/com.example.musiclistenerremake W/MediaPlayer-JNI: MediaPlayer finalized without being released
In my opinion I did initialize MediaPlayer correctly, I tried to move mediaPlayer before if statement (I don't know why I thought it will help) only, don't have idea what is wrong here.
Im using Android API 29.
private void getIntentMethod() {
position = getIntent().getIntExtra("position", -1);
listSongs = musicFiles;
if (listSongs != null)
{
playPauseBtn.setImageResource(R.drawable.ic_baseline_pause_24);
uri = Uri.parse(listSongs.get(position).getPath());
}
if (mediaPlayer != null)
{
mediaPlayer.stop();
mediaPlayer.release();
mediaPlayer = MediaPlayer.create(getApplicationContext(), uri);
mediaPlayer.start();
}
else
{
mediaPlayer = MediaPlayer.create(getApplicationContext(), uri);
mediaPlayer.start();
}
seekBar.setMax(mediaPlayer.getDuration() / 1000);
}
Here is full code of this activity (PlayerActivity):
package com.example.musiclistenerremake;
import androidx.appcompat.app.AppCompatActivity;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.widget.ImageView;
import android.widget.SeekBar;
import android.widget.TextView;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import java.util.ArrayList;
import static com.example.musiclistenerremake.MainActivity.musicFiles;
public class PlayerActivity extends AppCompatActivity {
TextView song_name, artist_name, duration_played, duration_total;
ImageView cover_art, nextBtn, prevBtn, backBtn, shuffleBtn, repeatBtn;
FloatingActionButton playPauseBtn;
SeekBar seekBar;
int position = -1;
static ArrayList<MusicFiles> listSongs = new ArrayList<>();
static Uri uri;
static MediaPlayer mediaPlayer;
private Handler handler = new Handler();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_player);
initViews();
getIntentMethod();
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
#Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
if(mediaPlayer != null && fromUser)
{
mediaPlayer.seekTo(progress * 1000);
}
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
PlayerActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
if(mediaPlayer != null)
{
int mCurrentPosition = mediaPlayer.getCurrentPosition() / 1000;
seekBar.setProgress(mCurrentPosition);
duration_played.setText(formattedTime(mCurrentPosition));
}
handler.postDelayed(this, 1000);
}
});
}
private String formattedTime(int mCurrentPosition) {
String totalOut = "";
String totalNew = "";
String seconds = String.valueOf(mCurrentPosition % 60);
String minutes = String.valueOf(mCurrentPosition / 60);
totalOut = minutes + ":" + seconds;
totalNew = minutes + ":" + "0" + seconds;
if (seconds.length() == 1)
{
return totalNew;
}
else
{
return totalOut;
}
}
private void getIntentMethod() {
position = getIntent().getIntExtra("position", -1);
listSongs = musicFiles;
if (listSongs != null)
{
playPauseBtn.setImageResource(R.drawable.ic_baseline_pause_24);
uri = Uri.parse(listSongs.get(position).getPath());
}
if (mediaPlayer != null)
{
mediaPlayer.stop();
mediaPlayer.release();
mediaPlayer = MediaPlayer.create(getApplicationContext(), uri);
mediaPlayer.start();
}
else
{
mediaPlayer = MediaPlayer.create(getApplicationContext(), uri);
mediaPlayer.start();
}
seekBar.setMax(mediaPlayer.getDuration() / 1000);
}
private void initViews() {
song_name = findViewById(R.id.song_name);
artist_name = findViewById(R.id.song_artist);
duration_played = findViewById(R.id.durationPlayed);
duration_total = findViewById(R.id.durationTotal);
cover_art = findViewById(R.id.cover_art);
nextBtn = findViewById(R.id.id_next);
prevBtn = findViewById(R.id.id_prev);
backBtn = findViewById(R.id.back_btn);
shuffleBtn = findViewById(R.id.shuffle);
repeatBtn = findViewById(R.id.id_repeat);
playPauseBtn = findViewById(R.id.play_pause);
seekBar = findViewById(R.id.seekBar);
}
}
Don't use mediaplayer.release()
because after resetting player after mediaplayer.reset() is uninitialized state and if the player is not initialized then it will throw an exception
I am writing a simple stopwatch application for android which will just keep the counter updating each second when pressed start, and pause it with the same button. In my main.xml layout I have a TextView and a Button, and nothing else.
Here's what I've written so far.
public class MainActivity extends Activity implements View.OnClickListener {
private Button btnToggle;
private TextView tvStopwatch;
public Handler updateStopwatch;
private enum Status {
WORKING,
STOPPED
}
private Status stopwatchStatus;
private void toggleStatus() {
if (stopwatchStatus == Status.WORKING) {
stopwatchStatus = Status.STOPPED;
Stopwatch.getStopwatch().dispose();
btnToggle.setText("Start");
}else{
stopwatchStatus = Status.WORKING;
Stopwatch.getStopwatch().start();
btnToggle.setText("Stop");
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
initView();
}
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btnToggle:
toggleStatus();
break;
}
}
private void initView() {
btnToggle = (Button) findViewById(R.id.btnToggle);
tvStopwatch = (TextView) findViewById(R.id.tvStopwatch);
updateStopwatch = new Handler(){
#Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
tvStopwatch.setText(msg.what);
}
};
Stopwatch.getStopwatch().setHandler(updateStopwatch);
btnToggle.setOnClickListener(this);
stopwatchStatus = Status.STOPPED;
}
public static class Stopwatch {
private int timestamp;
private boolean working;
private Handler updateStopwatch;
private Stopwatch() {
}
private static Stopwatch stopwatch;
public static Stopwatch getStopwatch() {
if (stopwatch == null) {
stopwatch = new Stopwatch();
}
return stopwatch;
}
public void setHandler(Handler updateStopwatch){
this.updateStopwatch = updateStopwatch;
}
public void start() {
if (!working) {
working = true;
Thread tick = new Thread() {
public void run() {
while (working) {
try {
sleep(1000);
} catch (InterruptedException ex) {
ex.printStackTrace();
} finally {
timestamp++;
updateStopwatch.sendEmptyMessage(timestamp);
}
}
}
};
tick.start();
}
}
public void dispose() {
working = false;
}
}
}
The point is, I want my Stopwatch work in it's separate thread, and to have a handler in my main UI thread which will keep updating the TextView, but when I debug my app, it keeps throwing an exception on this line
tvStopwatch.setText(msg.what);
I am quite new to Handlers, so I guess I'm just missing something fundamental.
Here is also the log for the exception
android.content.res.Resources$NotFoundException: String resource ID #0x1
at android.content.res.Resources.getText(Resources.java:1057)
at android.widget.TextView.setText(TextView.java:4186)
at unisoftdevelopment.com.stopwatch.MainActivity$1.handleMessage(MainActivity.java:61)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:5279)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1102)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:869)
at dalvik.system.NativeStart.main(Native Method)
Please help to find out the problem, thanks in advance.
Common mistake to make: setText() has an overload that takes an integer (which must be a string resource ID, e.g. R.string.my_string).
When you receive the message:
tvStopwatch.setText(msg.what);
It's attempting to resolve msg.what as a string resource, and crashing when it can't be found. You should instead cast the timestamp to a string, and use that instead:
tvStopwatch.setText(String.valueOf(msg.what));
I try to get current location and user activity, following the guide from
http://j.mp/io13-location the "checkpoint_final"
but i got those error when i run the program.
my logCat:
02-21 18:12:38.439: E/AndroidRuntime(3798): FATAL EXCEPTION: main
02-21 18:12:38.439: E/AndroidRuntime(3798): Process: com.android.google.codelab.location, PID: 3798
02-21 18:12:38.439: E/AndroidRuntime(3798): java.lang.RuntimeException: Unable to resume activity {com.android.google.codelab.location/com.android.google.codelab.location.LocationActivity}: java.lang.IllegalStateException: Not connected. Call connect() and wait for onConnected() to be called.
02-21 18:12:38.439: E/AndroidRuntime(3798): at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2788)
02-21 18:12:38.439: E/AndroidRuntime(3798): at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2817)
02-21 18:12:38.439: E/AndroidRuntime(3798): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2250)
02-21 18:12:38.439: E/AndroidRuntime(3798): at android.app.ActivityThread.access$800(ActivityThread.java:135)
02-21 18:12:38.439: E/AndroidRuntime(3798): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1196)
02-21 18:12:38.439: E/AndroidRuntime(3798): at android.os.Handler.dispatchMessage(Handler.java:102)
02-21 18:12:38.439: E/AndroidRuntime(3798): at android.os.Looper.loop(Looper.java:136)
02-21 18:12:38.439: E/AndroidRuntime(3798): at android.app.ActivityThread.main(ActivityThread.java:5017)
02-21 18:12:38.439: E/AndroidRuntime(3798): at java.lang.reflect.Method.invokeNative(Native Method)
02-21 18:12:38.439: E/AndroidRuntime(3798): at java.lang.reflect.Method.invoke(Method.java:515)
02-21 18:12:38.439: E/AndroidRuntime(3798): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)
02-21 18:12:38.439: E/AndroidRuntime(3798): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)
02-21 18:12:38.439: E/AndroidRuntime(3798): at dalvik.system.NativeStart.main(Native Method)
02-21 18:12:38.439: E/AndroidRuntime(3798): Caused by: java.lang.IllegalStateException: Not connected. Call connect() and wait for onConnected() to be called.
02-21 18:12:38.439: E/AndroidRuntime(3798): at com.google.android.gms.internal.dk.bB(Unknown Source)
02-21 18:12:38.439: E/AndroidRuntime(3798): at com.google.android.gms.internal.fm.a(Unknown Source)
02-21 18:12:38.439: E/AndroidRuntime(3798): at com.google.android.gms.internal.fm$c.bB(Unknown Source)
02-21 18:12:38.439: E/AndroidRuntime(3798): at com.google.android.gms.internal.fl.requestLocationUpdates(Unknown Source)
02-21 18:12:38.439: E/AndroidRuntime(3798): at com.google.android.gms.internal.fm.requestLocationUpdates(Unknown Source)
02-21 18:12:38.439: E/AndroidRuntime(3798): at com.google.android.gms.internal.fm.requestLocationUpdates(Unknown Source)
02-21 18:12:38.439: E/AndroidRuntime(3798): at com.google.android.gms.location.LocationClient.requestLocationUpdates(Unknown Source)
02-21 18:12:38.439: E/AndroidRuntime(3798): at com.android.google.codelab.location.LocationActivity.restartLocationClient(LocationActivity.java:248)
02-21 18:12:38.439: E/AndroidRuntime(3798): at com.android.google.codelab.location.LocationActivity.onResume(LocationActivity.java:197)
02-21 18:12:38.439: E/AndroidRuntime(3798): at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1192)
02-21 18:12:38.439: E/AndroidRuntime(3798): at android.app.Activity.performResume(Activity.java:5310)
02-21 18:12:38.439: E/AndroidRuntime(3798): at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2778)
02-21 18:12:38.439: E/AndroidRuntime(3798): ... 12 more
my Code
public class LocationActivity extends FragmentActivity {
public static String TAG = "LocationActivity";
public static boolean isAppForeground = false;
private static final int ERROR_DIALOG_ON_CREATE_REQUEST_CODE = 4055;
private static final int ERROR_DIALOG_ON_RESUME_REQUEST_CODE = 4056;
// Shared variables
private GoogleMap mMap;
private Dialog errorDialog;
// Location Request variables
private LocationClient mLocationClient;
private TextView mLocationStatus;
private LocationCallback mLocationCallback = new LocationCallback();
private Location mLastLocation;
private static final int LOCATION_UPDATES_INTERVAL = 10000; // Setting 10 sec interval for location updates
// Activity Recognition variables
private ActivityRecognitionClient mActivityRecognitionClient;
private ActivityRecognitionCallback mActivityRecognitionCallback = new ActivityRecognitionCallback();
public static final String ACTION_ACTIVITY_RECOGNITION =
"com.android.google.codelab.location.LocationActivity.ACTIVITY_RECOGNITION";
private static final int ACTIVITY_UPDATES_INTERVAL = 4000;
private PendingIntent mActivityRecognitionPendingIntent;
private Switch mSwitch;
private ActivityRecognitionIntentReceiver mActivityRecognitionIntentReceiver;
// Geo Fencing variables
private GeoFenceCallback mGeoFenceCallback = new GeoFenceCallback();
private int id = 0;
private static final float GEOFENCE_RADIUS = 100;
private HashMap<String, Circle> mGeoFences;
private HashMap<String, Circle> mTriggeringFences;
public static final String ACTION_GEOFENCE =
"com.android.google.codelab.location.LocationActivity.GEOFENCE";
private TextView mGeoFenceStatus;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
checkGooglePlayServiceAvailability(ERROR_DIALOG_ON_CREATE_REQUEST_CODE);
}
private void init() {
// Initialize map
if (mMap == null) {
FragmentManager myFragmentManager = getSupportFragmentManager();
SupportMapFragment myMapFragment =
(SupportMapFragment) myFragmentManager.findFragmentById(R.id.map);
mMap = myMapFragment.getMap();
}
// Initialize Location Client
mLocationStatus = (TextView) findViewById(R.id.location_status);
if (mLocationClient == null) {
mLocationClient = new LocationClient(this, mLocationCallback, mLocationCallback);
Log.v(LocationActivity.TAG, "Location Client connect");
if (!(mLocationClient.isConnected() || mLocationClient.isConnecting())) {
mLocationClient.connect();
}
}
// Initialize Action Recognition
if (mActivityRecognitionClient == null) {
mActivityRecognitionClient =
new ActivityRecognitionClient(this,
mActivityRecognitionCallback, mActivityRecognitionCallback);
}
mSwitch = (Switch) findViewById(R.id.swtich);
mSwitch.setOnCheckedChangeListener(new OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
startActivityDetection(buttonView);
} else {
stopActivityDetection(buttonView);
}
}
});
if (mActivityRecognitionIntentReceiver == null) {
mActivityRecognitionIntentReceiver = new ActivityRecognitionIntentReceiver();
registerReceiver(mActivityRecognitionIntentReceiver,
new IntentFilter(LocationActivity.ACTION_ACTIVITY_RECOGNITION));
}
// Initialize Geo Fencing
mGeoFenceStatus = (TextView) findViewById(R.id.geo_fence_status);
if (mGeoFences == null) {
mGeoFences = new HashMap<String, Circle>();
}
if (mTriggeringFences == null) {
mTriggeringFences = new HashMap<String, Circle>();
}
// Setup map to allow adding Geo Fences
mMap.getUiSettings().setAllGesturesEnabled(true);
mMap.setOnMapLongClickListener(mGeoFenceCallback);
}
#Override
public void onPause() {
super.onPause();
// Indicate the application is in background
isAppForeground = false;
if (mLocationClient.isConnected()) {
mLocationClient.removeLocationUpdates(mLocationCallback);
mLocationClient.disconnect();
}
}
#Override
public void onResume() {
super.onResume();
// Indicate the application is in foreground
isAppForeground = true;
checkGooglePlayServiceAvailability(ERROR_DIALOG_ON_RESUME_REQUEST_CODE);
restartLocationClient();
}
#Override
public void onDestroy() {
super.onDestroy();
unregisterReceiver(mActivityRecognitionIntentReceiver);
mActivityRecognitionIntentReceiver = null;
}
private void checkGooglePlayServiceAvailability(int requestCode) {
// Query for the status of Google Play services on the device
int statusCode = GooglePlayServicesUtil
.isGooglePlayServicesAvailable(getBaseContext());
if (statusCode == ConnectionResult.SUCCESS) {
init();
} else {
if (GooglePlayServicesUtil.isUserRecoverableError(statusCode)) {
errorDialog = GooglePlayServicesUtil.getErrorDialog(statusCode,
this, requestCode);
errorDialog.show();
} else {
// Handle unrecoverable error
}
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK) {
switch (requestCode) {
case ERROR_DIALOG_ON_CREATE_REQUEST_CODE:
init();
break;
case ERROR_DIALOG_ON_RESUME_REQUEST_CODE:
restartLocationClient();
break;
}
}
}
private void restartLocationClient() {
if (!(mLocationClient.isConnected() || mLocationClient.isConnecting())) {
mLocationClient.connect(); // Somehow it becomes connected here
return;
}
LocationRequest request = LocationRequest.create();
request.setInterval(LOCATION_UPDATES_INTERVAL);
request.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
mLocationClient.requestLocationUpdates(request, mLocationCallback);
}
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuItem menuItem = menu.add(R.string.clear_map);
menuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
menuItem.setOnMenuItemClickListener(new OnMenuItemClickListener() {
#Override
public boolean onMenuItemClick(MenuItem item) {
clearMap();
return true;
}
});
return true;
}
public void clearMap() {
mMap.clear();
mLastLocation = null;
mGeoFenceCallback.removeGeoFences();
}
private class LocationCallback implements ConnectionCallbacks, OnConnectionFailedListener,
LocationListener {
#Override
public void onConnected(Bundle connectionHint) {
Log.v(LocationActivity.TAG, "Location Client connected");
// Display last location
Location location = mLocationClient.getLastLocation();
if (location != null) {
handleLocation(location);
}
// Request for location updates
LocationRequest request = LocationRequest.create();
request.setInterval(LOCATION_UPDATES_INTERVAL);
request.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
mLocationClient.requestLocationUpdates(request, mLocationCallback);
}
#Override
public void onDisconnected() {
Log.v(LocationActivity.TAG, "Location Client disconnected by the system");
}
#Override
public void onConnectionFailed(ConnectionResult result) {
Log.v(LocationActivity.TAG, "Location Client connection failed");
}
#Override
public void onLocationChanged(Location location) {
if (location == null) {
Log.v(LocationActivity.TAG, "onLocationChanged: location == null");
return;
}
// Add a marker iff location has changed.
if (mLastLocation != null &&
mLastLocation.getLatitude() == location.getLatitude() &&
mLastLocation.getLongitude() == location.getLongitude()) {
return;
}
handleLocation(location);
}
private void handleLocation(Location location) {
// Update the mLocationStatus with the lat/lng of the location
Log.v(LocationActivity.TAG, "LocationChanged == #" +
location.getLatitude() + "," + location.getLongitude());
mLocationStatus.setText("Location changed #" + location.getLatitude() + "," +
location.getLongitude());
// Add a marker of that location to the map
LatLng latlongzoom = new LatLng(location.getLatitude(),
location.getLongitude());
String snippet = location.getLatitude() + "," + location.getLongitude();
Marker marker = mMap.addMarker(
new MarkerOptions().position(latlongzoom));
marker.setSnippet(snippet);
marker.setTitle(snippet);
// Center the map to the first marker
if (mLastLocation == null) {
mMap.moveCamera(CameraUpdateFactory.
newCameraPosition(CameraPosition.fromLatLngZoom(
new LatLng(location.getLatitude(), location.getLongitude()),
(float) 16.0)));
}
mLastLocation = location;
}
};
public void startActivityDetection(View v) {
if (!mActivityRecognitionClient.isConnected()) {
mActivityRecognitionClient.connect();
}
}
public void stopActivityDetection(View v) {
if (mActivityRecognitionClient.isConnected()) {
mActivityRecognitionClient.removeActivityUpdates(mActivityRecognitionPendingIntent);
mActivityRecognitionClient.disconnect();
}
}
private class ActivityRecognitionCallback implements ConnectionCallbacks, OnConnectionFailedListener {
#Override
public void onConnected(Bundle connectionHint) {
Log.v(LocationActivity.TAG, "Activity Recognition Client connected");
// Request activity updates
Intent intent = new Intent(LocationActivity.this,
ActivityRecognitionIntentService.class);
intent.setAction(LocationActivity.ACTION_ACTIVITY_RECOGNITION);
mActivityRecognitionPendingIntent = PendingIntent.getService(LocationActivity.this, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
mActivityRecognitionClient.requestActivityUpdates(ACTIVITY_UPDATES_INTERVAL,
mActivityRecognitionPendingIntent);
}
#Override
public void onDisconnected() {
Log.v(LocationActivity.TAG, "Activity Recognition Client disconnected by the system");
}
#Override
public void onConnectionFailed(ConnectionResult result) {
Log.v(LocationActivity.TAG,
"Activity Recognition Client connection failed " + result.getErrorCode());
}
};
private class GeoFenceCallback implements OnMapLongClickListener,
OnAddGeofencesResultListener, OnRemoveGeofencesResultListener {
#Override
public void onMapLongClick(LatLng point) {
Log.v(LocationActivity.TAG,
"onMapLongClick == " + point.latitude + "," + point.longitude);
CircleOptions circleOptions = new CircleOptions();
circleOptions.center(point).radius(GEOFENCE_RADIUS).strokeColor(
android.graphics.Color.BLUE).strokeWidth(2);
Circle circle = mMap.addCircle(circleOptions);
String key = Integer.toString(id);
id++;
mGeoFences.put(key, circle);
addGeoFences();
}
// Creates Geofence objects from all circles on the map and calls addGeofences API.
private void addGeoFences() {
List<Geofence> list = new ArrayList<Geofence>();
for (Map.Entry<String, Circle> entry : mGeoFences.entrySet()) {
Circle circle = entry.getValue();
Log.v(LocationActivity.TAG, "points == " +
circle.getCenter().latitude + "," +
circle.getCenter().longitude);
Geofence geofence = new Geofence.Builder()
.setRequestId(entry.getKey())
.setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER |
Geofence.GEOFENCE_TRANSITION_EXIT)
.setCircularRegion(circle.getCenter().latitude,
circle.getCenter().longitude,
(float) circle.getRadius())
.setExpirationDuration(Geofence.NEVER_EXPIRE).build();
list.add(geofence);
}
if (list.isEmpty()) {
return;
}
// Clear off all the currently triggering geo_fences before new fences
// are added.
for (Circle triggeringGeoFence : mTriggeringFences.values()) {
triggeringGeoFence.remove();
}
mTriggeringFences.clear();
Log.v(LocationActivity.TAG, "addingGeoFences size = " + list.size());
mLocationClient.addGeofences(list, getPendingIntent(), this);
}
private PendingIntent getPendingIntent() {
Intent intent = new Intent(ACTION_GEOFENCE);
intent.setComponent(new ComponentName(LocationActivity.this,
GeoFenceIntentReceiver.class));
return PendingIntent.getBroadcast(LocationActivity.this, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
}
private void removeGeoFences() {
List<String> requestIdsForRemoval = new ArrayList<String>();
if (mGeoFences.isEmpty()) return;
for (Map.Entry<String, Circle> entry : mGeoFences.entrySet()) {
String requestId = entry.getKey();
Circle circle = entry.getValue();
if (circle != null) {
circle.remove();
id --;
Log.v(LocationActivity.TAG, "RemoveGeoFence requestId == " + requestId);
Circle triggeringCircle = mTriggeringFences.get(requestId);
if (triggeringCircle != null) {
triggeringCircle.remove();
}
requestIdsForRemoval.add(requestId);
}
}
mGeoFences.clear();
mTriggeringFences.clear();
mLocationClient.removeGeofences(requestIdsForRemoval, this);
}
#Override
public void onAddGeofencesResult(int statusCode,
String[] geofenceRequestIds) {
StringBuilder builder = new StringBuilder();
for (int i = 0 ; i < geofenceRequestIds.length - 1; ++i) {
builder.append(geofenceRequestIds[i]);
builder.append(",");
}
builder.append(geofenceRequestIds[geofenceRequestIds.length - 1]);
Log.v(LocationActivity.TAG, "Added Geofences == "
+ statusCodeToString(statusCode) + " " + builder.toString());
mGeoFenceStatus.setText("Added Geofences "
+ statusCodeToString(statusCode) + " " + builder.toString());
}
private String statusCodeToString(int statusCode) {
switch(statusCode) {
case LocationStatusCodes.SUCCESS :
return "SUCCESS";
case LocationStatusCodes.GEOFENCE_NOT_AVAILABLE :
return "GEOFENCE_NOT_AVAILABLE";
case LocationStatusCodes.GEOFENCE_TOO_MANY_GEOFENCES :
return "GEOFENCE_TOO_MANY_GEOFENCES";
case LocationStatusCodes.GEOFENCE_TOO_MANY_PENDING_INTENTS :
return "GEOFENCE_TOO_MANY_PENDING_INTENTS";
case LocationStatusCodes.ERROR :
return "ERROR";
}
return "UNKNOWN";
}
#Override
public void onRemoveGeofencesByPendingIntentResult(int statusCode, PendingIntent pendingIntent) {
// Do nothing
}
#Override
public void onRemoveGeofencesByRequestIdsResult(int statusCode,
String[] geofenceRequestIds) {
StringBuilder builder = new StringBuilder();
for (int i = 0 ; i < geofenceRequestIds.length - 1; ++i) {
builder.append(geofenceRequestIds[i]);
builder.append(",");
}
builder.append(geofenceRequestIds[geofenceRequestIds.length - 1]);
Log.v(LocationActivity.TAG, "Removed Geofence " +
statusCodeToString(statusCode) + " " + builder.toString());
mGeoFenceStatus.setText("Removed Geofences request_ids = " +
builder.toString() + " " + statusCodeToString(statusCode));
}
};
// Triggered when startAcitivity method is called in GeoFenceIntentReceiver.
// Updates UI as geofences are entered/exited.
#Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
// getIntent() should always return the most recent
setIntent(intent);
boolean receiverStarted =
intent.getBooleanExtra("RECEIVER_STARTED", false);
if (!receiverStarted) {
return;
}
Bundle bundle = intent.getParcelableExtra("geo_fences");
ArrayList<String> requestIds =
bundle.getStringArrayList("request_ids");
if (requestIds == null) {
Log.v(LocationActivity.TAG, "request_ids == null");
return;
}
int transition = intent.getIntExtra("transition", -2);
for (String requestId : requestIds) {
Log.v(LocationActivity.TAG, "Triggering Geo Fence requestId "
+ requestId);
if (transition == Geofence.GEOFENCE_TRANSITION_ENTER) {
Circle circle = mGeoFences.get(requestId);
if (circle == null) {
continue;
}
Log.v(LocationActivity.TAG, "triggering_geo_fences enter == "
+ requestId);
// Add a superimposed red circle when a geofence is entered and
// put the corresponding object in triggering_fences.
CircleOptions circleOptions = new CircleOptions();
circleOptions.center(circle.getCenter())
.radius(circle.getRadius())
.fillColor(Color.argb(100,100, 0, 0));
Circle newCircle = mMap.addCircle(circleOptions);
mTriggeringFences.put(requestId, newCircle);
} else if (transition == Geofence.GEOFENCE_TRANSITION_EXIT) {
Log.v(LocationActivity.TAG, "triggering_geo_fences exit == "
+ requestId);
Circle circle = mTriggeringFences.get(requestId);
if (circle == null) {
continue;
}
// Remove the superimposed red circle from the map and the
// corresponding Circle object from triggering_fences hash_map.
circle.remove();
mTriggeringFences.remove(requestId);
}
}
return;
}
}
2nd class
public class ActivityRecognitionIntentService extends IntentService {
public ActivityRecognitionIntentService() {
super("ActivityRecognitionIntentService");
}
public ActivityRecognitionIntentService(String name) {
super(name);
}
#Override
protected void onHandleIntent(Intent intent) {
if (intent.getAction() != LocationActivity.ACTION_ACTIVITY_RECOGNITION) {
return;
}
if (ActivityRecognitionResult.hasResult(intent)) {
ActivityRecognitionResult result = ActivityRecognitionResult
.extractResult(intent);
DetectedActivity detectedActivity = result
.getMostProbableActivity();
int activityType = detectedActivity.getType();
Log.v(LocationActivity.TAG, "activity_type == " + activityType);
// Put the activity_type as an intent extra and send a broadcast.
Intent send_intent = new Intent(
LocationActivity.ACTION_ACTIVITY_RECOGNITION);
send_intent.putExtra("activity_type", activityType);
sendBroadcast(send_intent);
}
}
}
edited add the main part of the code
Please Modify your restartLocationClient() Method like this:
private void restartLocationClient() {
if (mLocationClient == null) {
mLocationClient = new LocationClient(this, mLocationCallback, mLocationCallback);
Log.v(LocationActivity.TAG, "Location Client connect");
if (!(mLocationClient.isConnected() || mLocationClient.isConnecting()))
{
mLocationClient.connect(); // Somehow it becomes connected here
return;
}
}
LocationRequest request = LocationRequest.create();
request.setInterval(LOCATION_UPDATES_INTERVAL);
request.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
mLocationClient.requestLocationUpdates(request, mLocationCallback);
}
It seems that your mLocationClient is null in this Method.
I hope this helps.
I know it's pretty late for this answer.
But for future reference, I'll post it anyways.
Basically, we have to understand the onConnect() method better. I find the explanation in this thread to be useful.
From there the workaround for this issue is pretty much straightforward.
Solution: restartLocationClient() is only called when mLocationClient.isConnected() returns true.
So, in your onResume method should look like the following:
if (mLocationClient.isConnected()) {
restartLocationClient();
}
Now it will work.
I have used the OrientationEventListener which I have coupled with a Handler to update a TextView when the screen rotates:
MainHandler handler;
TextView tv;
MyOrientationEventListener listener;
class MainHandler extends Handler
{
#Override
public void handleMessage(Message msg)
{
switch(msg.what)
{
case MSG_ORIENTATION:
if(tv!=null)
tv.setText(msg.arg1);
break;
default:
if(tv!=null)
tv.setText("Nothing to see here");
}
}
}
This is my OrientationEventListener here:
class MyOrientationEventListener extends OrientationEventListener
{
public MyOrientationEventListener(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
public MyOrientationEventListener(Context context,int attrs)
{
super(context,attrs);
}
#Override
public void onOrientationChanged(int orientation) {
// TODO Auto-generated method stub
Log.d("MainActivity", "Orientation before rounding: "+orientation);
orientation=roundRotation(orientation,0);
Log.d("MainActivity", "Orientation after rounding: "+orientation);
Message msg=handler.obtainMessage(MSG_ORIENTATION);
msg.arg1=orientation;
handler.sendMessage(msg);
}
public int getDisplayOrientation()
{
int rotation=getWindowManager().getDefaultDisplay().getRotation();
switch(rotation)
{
case Surface.ROTATION_0:
return 0;
case Surface.ROTATION_90:
return 90;
case Surface.ROTATION_180:
return 180;
case Surface.ROTATION_270:
return 270;
}
return 0;
}
public int roundRotation(int orientation,int orientationHistory)
{
final int ORIENTATION_HYSTERESIS=5;
boolean changeOrientation=false;
if(orientationHistory==ORIENTATION_UNKNOWN)
changeOrientation=true;
else
{
int dist=Math.abs(orientation-orientationHistory);
dist=Math.min(dist, 360-dist);
changeOrientation=(dist>=45+ORIENTATION_HYSTERESIS);
}
if(changeOrientation)
{
int nOrientation=((orientation+45)/90*90)%360;
Log.d("OrientationEventHandler", "New orientation: "+nOrientation);
return nOrientation;
}
return orientationHistory;
}
}
I am using the Handler in onCreate to register my Handler to the UI thread,thus it can be used to update the Views on screen.However,this code does not seem to work:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv=(TextView)findViewById(R.id.tv);
handler=new MainHandler();
listener=new MyOrientationEventListener(this);
}
I am using listener.enable() in onResume and listener.disable() in onPause methods after invoking their respective superclass methods.When I try to rotate the screen and the rounding occurs:
MainActivity(9724): Orientation before rounding: 55
OrientationEventHandler(9724): New orientation: 90
MainActivity(9724): Orientation after rounding: 90
ResourceType(9724): No package identifier when getting value for resource number 0x0000005a
dalvikvm(9724): threadid=1: thread exiting with uncaught exception (group=0x41fdf700)
AndroidRuntime(9724): FATAL EXCEPTION: main
AndroidRuntime(9724): android.content.res.Resources$NotFoundException: String resource ID #0x5a
AndroidRuntime(9724): at android.content.res.Resources.getText(Resources.java:239)
AndroidRuntime(9724): at android.widget.TextView.setText(TextView.java:3837)
AndroidRuntime(9724): at com.example.calllogproject.MainActivity$MainHandler.handleMessage(MainActivity.java:30)
AndroidRuntime(9724): at android.os.Handler.dispatchMessage(Handler.java:99)
AndroidRuntime(9724): at android.os.Looper.loop(Looper.java:137)
AndroidRuntime(9724): at android.app.ActivityThread.main(ActivityThread.java:5103)
AndroidRuntime(9724): at java.lang.reflect.Method.invokeNative(Native Method)
AndroidRuntime(9724): at java.lang.reflect.Method.invoke(Method.java:525)
AndroidRuntime(9724): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:737)
AndroidRuntime(9724): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
AndroidRuntime(9724): at dalvik.system.NativeStart.main(Native Method)
Try this class:
class MainHandler extends Handler
{
#Override
public void handleMessage(Message msg)
{
switch(msg.what)
{
case MSG_ORIENTATION:
if(tv!=null)
tv.setText(String.valueOf(msg.arg1));
break;
default:
if(tv!=null)
tv.setText("Nothing to see here");
}
}
}
I've changed
tv.setText(msg.arg1);
into
tv.setText(String.valueOf(msg.arg1));
In the app control panel I found an error report that not only I can't reproduce, but also it make no sense to me.
This is the stacktrace:
java.lang.ClassCastException: java.lang.Object[] cannot be cast to ohm.quickdice.entity.RollResult[]
at ohm.quickdice.activity.QuickDiceActivity.setupRollMenu(QuickDiceActivity.java:575)
at ohm.quickdice.activity.QuickDiceActivity.onCreateContextMenu(QuickDiceActivity.java:459)
at android.view.View.createContextMenu(View.java:6229)
at com.android.internal.view.menu.ContextMenuBuilder.show(ContextMenuBuilder.java:81)
at com.android.internal.policy.impl.PhoneWindow$DecorView.showContextMenuForChild(PhoneWindow.java:2292)
at android.view.ViewGroup.showContextMenuForChild(ViewGroup.java:564)
at android.view.ViewGroup.showContextMenuForChild(ViewGroup.java:564)
at android.view.ViewGroup.showContextMenuForChild(ViewGroup.java:564)
at android.view.ViewGroup.showContextMenuForChild(ViewGroup.java:564)
at android.widget.AbsListView.performLongPress(AbsListView.java:2772)
at android.widget.AbsListView$CheckForLongPress.run(AbsListView.java:2717)
at android.os.Handler.handleCallback(Handler.java:605)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4514)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:790)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:557)
at dalvik.system.NativeStart.main(Native Method)
An this is the code where the exception occour:
ArrayList<RollResult[]> resultList;
RollResult[] lastResult;
...
protected void setupRollMenu(int index, ContextMenu menu) {
RollResult[] rollItem;
RollResult[] nextItem;
RollResult mergedRoll;
if (index < 0) {
rollItem = lastResult;
} else {
rollItem = resultList.get(index);
}
if (index + 1 < resultList.size()) {
nextItem = resultList.get(index + 1); //This is row 575
} else {
nextItem = null;
}
...
I wonder how the instruction "nextItem = resultList.get(int);" can raise this exception since resultList is defined as ArrayList and nextItem is an object of type RollResult[]...
It may depend on how Android serialize and deserialize instance state data to bundles?
Here how the serialization is done:
#Override
protected void onSaveInstanceState(Bundle outState) {
outState.putSerializable(KEY_LAST_ROLL, lastResult);
outState.putSerializable(KEY_ROLL_LIST, resultList);
super.onSaveInstanceState(outState);
}
and this is the deserialization:
#SuppressWarnings("unchecked")
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState != null) {
Serializable tmp;
tmp = savedInstanceState.getSerializable(KEY_LAST_ROLL);
if (tmp instanceof RollResult[]) {
lastResult = (RollResult[])tmp;
}
tmp = savedInstanceState.getSerializable(KEY_ROLL_LIST);
if (tmp instanceof ArrayList<?>) {
resultList = (ArrayList<RollResult[]>)tmp;
}
}
if (lastResult == null) {
lastResult = new RollResult[0];
}
if (resultList == null) {
resultList = new ArrayList<RollResult[]>();
}
}
Thanks.