`你好,我是一个新手编码器,我尝试在 android studio 上编写这个移动应用程序,跟踪你当前的位置,然后在单击“开始旅程”按钮时将其发送到 sqlite 数据库。 (位置和时间戳将被发送过来)。 “结束旅程”按钮也是如此。 然而,我现在遇到的错误是,每当我单击“开始旅程”按钮时,移动应用程序都会自动退出。如果我检查 android studio 中设备资源管理器下的 /data/data//databases 目录,也不会创建任何数据库。 可能是什么问题?
尝试过chatgpt,但没有得到太多有用的信息,因此在这里询问。 下面是我的 mainactivity.java 、 Activity_main.xml 和 DatabaseHelper.java
超出最大字数限制,因此我删除了导入**,只是假设我拥有所有必要的导入。
Mainactivity.java :
package com.verdefy;
import com.verdefy.DatabaseHelper;
public class MainActivity extends AppCompatActivity
implements OnMapReadyCallback {
private static final String TAG = MainActivity.class.getSimpleName();
private GoogleMap map;
private CameraPosition cameraPosition;
// The entry point to the Places API.
private PlacesClient placesClient;
// The entry point to the Fused Location Provider.
private FusedLocationProviderClient fusedLocationProviderClient;
// A default location (Singapore) and default zoom to use when location permission is
// not granted.
private final LatLng defaultLocation = new LatLng(1.3521, 103.8198);
private static final int DEFAULT_ZOOM = 15;
private static final int PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION = 1;
private boolean locationPermissionGranted;
// The geographical location where the device is currently located. That is, the last-known
// location retrieved by the Fused Location Provider.
private Location lastKnownLocation;
// Keys for storing activity state.
private static final String KEY_LOCATION = "location";
// Used for selecting the current place.
private static final int M_MAX_ENTRIES = 5;
private String[] likelyPlaceNames;
private String[] likelyPlaceAddresses;
private List[] likelyPlaceAttributions;
private LatLng[] likelyPlaceLatLngs;
// Variables for location tracking
private FusedLocationProviderClient fusedLocationClient;
private LocationCallback locationCallback;
private Location lastLocation;
private float totalDistance = 0;
private SendDataToDatabase sendDataToDatabase;
private LocationRequest locationRequest;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
sendDataToDatabase = new SendDataToDatabase();
// Retrieve location and camera position from saved instance state.
if (savedInstanceState != null) {
lastKnownLocation = savedInstanceState.getParcelable(KEY_LOCATION);
cameraPosition = savedInstanceState.getParcelable(KEY_CAMERA_POSITION);
}
// [END maps_current_place_on_create_save_instance_state]
// [END_EXCLUDE]
// Retrieve the content view that renders the map.
setContentView(R.layout.activity_main);
// Construct a PlacesClient; Initializes Places SDK for android with the API key
//stored in the buildconfig class
Places.initialize(getApplicationContext(), BuildConfig.PLACES_API_KEY);
placesClient = Places.createClient(this);
// Construct a FusedLocationProviderClient.
fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this);
//Build the map and start it
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
//end
//initialize updateDistanceTextView
// Initialize locationCallback
locationCallback = new LocationCallback() {
// Define the method inside your class (e.g., MainActivity)
private void updateDistanceTextView(float distance) {
// Assuming you have a TextView named distanceTextView
TextView distanceTextView = findViewById(R.id.distanceTextView);
if (distanceTextView != null) {
distanceTextView.setText("Distance: " + distance + " meters");
}
}
@Override
public void onLocationResult(LocationResult locationResult) {
super.onLocationResult(locationResult); //Call superclass method if needed
if (locationResult == null) {
return;
}
for (Location location : locationResult.getLocations()) {
if (lastLocation != null) {
float distance = lastLocation.distanceTo(location);
totalDistance += distance;
updateDistanceTextView(totalDistance);
}
lastLocation = location;
}
}
};
// Inside onCreate() or any appropriate method
locationRequest = LocationRequest.create();
locationRequest.setInterval(10000); // Update interval in milliseconds
locationRequest.setFastestInterval(5000); // Fastest update interval in milliseconds
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); // Set priority
// [END maps_current_place_on_create]
}
// Start location updates
@SuppressLint("MissingPermission")
private void startLocationUpdates() {
fusedLocationProviderClient.requestLocationUpdates(locationRequest,
locationCallback,
Looper.getMainLooper());
}
/**
* Saves the state of the map when the activity is paused.
*/
// [START maps_current_place_on_save_instance_state]
@Override
protected void onSaveInstanceState(Bundle outState) {
if (map != null && lastKnownLocation!= null) {
outState.putParcelable(KEY_LOCATION, lastKnownLocation);
}
super.onSaveInstanceState(outState);
}
// [END maps_current_place_on_save_instance_state]
/**
* Sets up the options menu.
*
* @param menu The options menu.
* @return Boolean.
*/
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.current_place_menu, menu);
return true;
}
/**
* Handles a click on the menu option to get a place.
*
* @param item The menu item to handle.
* @return Boolean.
*/
// [START maps_current_place_on_options_item_selected]
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == R.id.option_get_place) {
showCurrentPlace();
}
return true;
}
// [END maps_current_place_on_options_item_selected]
/**
* Manipulates the map when it's available.
* This callback is triggered when the map is ready to be used.
*/
// [START maps_current_place_on_map_ready]
@Override
public void onMapReady(GoogleMap map) {
this.map = map;
// [START_EXCLUDE]
// [START map_current_place_set_info_window_adapter]
// Use a custom info window adapter to handle multiple lines of text in the
// info window contents.
this.map.setInfoWindowAdapter(new GoogleMap.InfoWindowAdapter() {
@Override
// Return null here, so that getInfoContents() is called next.
public View getInfoWindow(Marker arg0) {
return null;
}
@Override
public View getInfoContents(Marker marker) {
// Inflate the layouts for the info window, title and snippet.
View infoWindow = getLayoutInflater().inflate(R.layout.custom_info_contents,
(FrameLayout) findViewById(R.id.map), false);
TextView title = infoWindow.findViewById(R.id.title);
title.setText(marker.getTitle());
TextView snippet = infoWindow.findViewById(R.id.snippet);
snippet.setText(marker.getSnippet());
return infoWindow;
}
});
// [END map_current_place_set_info_window_adapter]
// Prompt the user for permission.
getLocationPermission();
// [END_EXCLUDE]
// Turn on the My Location layer and the related control on the map.
updateLocationUI();
// Get the current location of the device and set the position of the map.
getDeviceLocation();
}
// [END maps_current_place_on_map_ready]
/**
* Gets the current location of the device, and positions the map's camera.
*/
// [START maps_current_place_get_device_location]
private void getDeviceLocation() {
/*
* Get the best and most recent location of the device, which may be null in rare
* cases when a location is not available.
*/
try {
if (locationPermissionGranted) {
Task<Location> locationResult = fusedLocationProviderClient.getLastLocation();
locationResult.addOnCompleteListener(this, new OnCompleteListener<Location>() {
@Override
public void onComplete(@NonNull Task<Location> task) {
if (task.isSuccessful()) {
// Set the map's camera position to the current location of the device.
lastKnownLocation = task.getResult();
if (lastKnownLocation != null) {
map.moveCamera(CameraUpdateFactory.newLatLngZoom(
new LatLng(lastKnownLocation.getLatitude(),
lastKnownLocation.getLongitude()), DEFAULT_ZOOM));
}
} else {
Log.d(TAG, "Current location is null. Using defaults.");
Log.e(TAG, "Exception: %s", task.getException());
map.moveCamera(CameraUpdateFactory
.newLatLngZoom(defaultLocation, DEFAULT_ZOOM));
map.getUiSettings().setMyLocationButtonEnabled(false);
}
}
});
}
} catch (SecurityException e) {
Log.e("Exception: %s", e.getMessage(), e);
}
}
// [END maps_current_place_get_device_location]
/**
* Prompts the user for permission to use the device location.
*/
// [START maps_current_place_location_permission]
private void getLocationPermission() {
/*
* Request location permission, so that we can get the location of the
* device. The result of the permission request is handled by a callback,
* onRequestPermissionsResult.
*/
if (ContextCompat.checkSelfPermission(this.getApplicationContext(),
android.Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
locationPermissionGranted = true;
} else {
ActivityCompat.requestPermissions(this,
new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION},
PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION);
}
}
// [END maps_current_place_location_permission]
/**
* Handles the result of the request for location permissions.
*/
// [START maps_current_place_on_request_permissions_result]
@Override
public void onRequestPermissionsResult(int requestCode,
@NonNull String[] permissions,
@NonNull int[] grantResults) {
locationPermissionGranted = false;
if (requestCode
== PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION) {// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
locationPermissionGranted = true;
}
} else {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
updateLocationUI();
}
// [END maps_current_place_on_request_permissions_result]
/**
* Prompts the user to select the current place from a list of likely places, and shows the
* current place on the map - provided the user has granted location permission.
*/
// [START maps_current_place_show_current_place]
private void showCurrentPlace() {
if (map == null) {
return;
}
if (locationPermissionGranted) {
// Use fields to define the data types to return.
List<Place.Field> placeFields = Arrays.asList(Place.Field.NAME, Place.Field.ADDRESS,
Place.Field.LAT_LNG);
// Use the builder to create a FindCurrentPlaceRequest.
FindCurrentPlaceRequest request =
FindCurrentPlaceRequest.newInstance(placeFields);
// Get the likely places - that is, the businesses and other points of interest that
// are the best match for the device's current location.
@SuppressWarnings("MissingPermission") final Task<FindCurrentPlaceResponse> placeResult =
placesClient.findCurrentPlace(request);
placeResult.addOnCompleteListener(new OnCompleteListener<FindCurrentPlaceResponse>() {
@Override
public void onComplete(@NonNull Task<FindCurrentPlaceResponse> task) {
if (task.isSuccessful() && task.getResult() != null) {
FindCurrentPlaceResponse likelyPlaces = task.getResult();
// Set the count, handling cases where less than 5 entries are returned.
int count;
if (likelyPlaces.getPlaceLikelihoods().size() < M_MAX_ENTRIES) {
count = likelyPlaces.getPlaceLikelihoods().size();
} else {
count = M_MAX_ENTRIES;
}
int i = 0;
likelyPlaceNames = new String[count];
likelyPlaceAddresses = new String[count];
likelyPlaceAttributions = new List[count];
likelyPlaceLatLngs = new LatLng[count];
for (PlaceLikelihood placeLikelihood : likelyPlaces.getPlaceLikelihoods()) {
// Build a list of likely places to show the user.
likelyPlaceNames[i] = placeLikelihood.getPlace().getName();
likelyPlaceAddresses[i] = placeLikelihood.getPlace().getAddress();
likelyPlaceAttributions[i] = placeLikelihood.getPlace()
.getAttributions();
likelyPlaceLatLngs[i] = placeLikelihood.getPlace().getLatLng();
i++;
if (i > (count - 1)) {
break;
}
}
// Show a dialog offering the user the list of likely places, and add a
// marker at the selected place.
MainActivity.this.openPlacesDialog();
} else {
Log.e(TAG, "Exception: %s", task.getException());
}
}
});
} else {
// The user has not granted permission.
Log.i(TAG, "The user did not grant location permission.");
// Add a default marker, because the user hasn't selected a place.
map.addMarker(new MarkerOptions()
.title(getString(R.string.default_info_title))
.position(defaultLocation)
.snippet(getString(R.string.default_info_snippet)));
// Prompt the user for permission.
getLocationPermission();
}
}
// [END maps_current_place_show_current_place]
/**
* Displays a form allowing the user to select a place from a list of likely places.
*/
// [START maps_current_place_open_places_dialog]
private void openPlacesDialog() {
// Ask the user to choose the place where they are now.
DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// The "which" argument contains the position of the selected item.
LatLng markerLatLng = likelyPlaceLatLngs[which];
String markerSnippet = likelyPlaceAddresses[which];
if (likelyPlaceAttributions[which] != null) {
markerSnippet = markerSnippet + "\n" + likelyPlaceAttributions[which];
}
// Add a marker for the selected place, with an info window
// showing information about that place.
map.addMarker(new MarkerOptions()
.title(likelyPlaceNames[which])
.position(markerLatLng)
.snippet(markerSnippet));
// Position the map's camera at the location of the marker.
map.moveCamera(CameraUpdateFactory.newLatLngZoom(markerLatLng,
DEFAULT_ZOOM));
}
};
// Display the dialog.
AlertDialog dialog = new AlertDialog.Builder(this)
.setTitle(R.string.pick_place)
.setItems(likelyPlaceNames, listener)
.show();
}
// [END maps_current_place_open_places_dialog]
/**
* Updates the map's UI settings based on whether the user has granted location permission.
*/
// [START maps_current_place_update_location_ui]
private void updateLocationUI() {
if (map == null) {
return;
}
try {
if (locationPermissionGranted) {
map.setMyLocationEnabled(true);
map.getUiSettings().setMyLocationButtonEnabled(true);
} else {
map.setMyLocationEnabled(false);
map.getUiSettings().setMyLocationButtonEnabled(false);
lastKnownLocation = null;
getLocationPermission();
}
} catch (SecurityException e) {
Log.e("Exception: %s", e.getMessage());
}
}
// [END maps_current_place_update_location_ui]
private String getLocationName(double latitude, double longitude) {
// Your implementation to get the location name based on latitude and longitude
// This method should return the name of the location based on the provided coordinates
// You may use geocoding or reverse geocoding to achieve this
Geocoder geocoder = new Geocoder(MainActivity.this, Locale.getDefault());
try {
List<Address> addresses = geocoder.getFromLocation(latitude, longitude, 1);
if (addresses != null && addresses.size() > 0) {
Address address = addresses.get(0);
return address.getAddressLine(0); // You can customize this as per your requirements
}
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
private String getCurrentTimestamp() {
// Get current timestamp
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String timestamp = sdf.format(new Date());
return timestamp;
}
// Your class definition
public class SendDataToDatabase {
// Your other methods
//START a journey and start tracking
// Send location and timestamp to the database
// Start tracking user's location
// You can use the Google Maps Directions API to calculate distance and carbon emission
// Start a timer or capture the start time for duration calculation
public void startJourney(View view) {
// Get current location and timestamp
if (lastKnownLocation != null) {
String startLocation = getLocationName(lastKnownLocation.getLatitude(), lastKnownLocation.getLongitude());
String startTimeStamp = getCurrentTimestamp();
// Assuming addTravelData is a method of DatabaseHelper class
DatabaseHelper dbHelper = new DatabaseHelper(MainActivity.this); // Assuming this is your activity context
dbHelper.addTravelData(startLocation, startTimeStamp,null, null);
}
}
// END A JOURNEY, stop all tracking
public void endJourney(View view) {
// Stop tracking user's location
if (lastKnownLocation != null) {
String endLocation = getLocationName(lastKnownLocation.getLatitude(), lastKnownLocation.getLongitude());
String endTimeStamp = getCurrentTimestamp();
DatabaseHelper dbHelper = new DatabaseHelper(MainActivity.this);
// Save end location and timestamp to the database
dbHelper.addTravelData(null,null, endLocation, endTimeStamp);
}
// Calculate distance travelled
// Calculate time duration
// Calculate carbon emission if possible
// Send all captured data (distance, duration, type of vehicle, etc.) to the database
}
// Method to handle start journey button click
public void onStartJourneyButtonClick(View view) {
sendDataToDatabase.startJourney(view);
}
// Method to handle end journey button click
public void onEndJourneyButtonClick(View view) {
sendDataToDatabase.endJourney(view);
}
}
}
2) Activity_main.xml :
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/dark_green"
tools:context=".MainActivity">
<TextView
android:id="@+id/NewJourneyTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/jua"
android:text="Start a New Journey"
android:textColor="@color/white"
android:textSize="25sp"
android:textStyle="bold"
app:layout_constraintBottom_toTopOf="@+id/map"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.178" />
<Button
android:id="@+id/startButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="44dp"
android:layout_marginBottom="72dp"
android:onClick="onStartJourneyButtonClick"
android:text="Start Journey"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
tools:ignore="MissingConstraints" />
<Button
android:id="@+id/EndButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="44dp"
android:layout_marginBottom="72dp"
android:onClick="onEndJourneyButtonClick"
android:text="End Journey"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
tools:ignore="MissingConstraints" />
<fragment
android:id="@+id/map"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="322dp"
android:layout_height="444dp"
android:layout_marginBottom="144dp"
android:background="@drawable/rounded_corners"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.494"
app:layout_constraintStart_toStartOf="parent" />
<TextView
android:id="@+id/distanceTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="100dp"
android:layout_marginTop="104dp"
android:padding="8dp"
android:text="Distance: "
android:textSize="16sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
3)DatabaseHelper.java
package com.verdefy;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.content.ContentValues;
// Create the database
public class DatabaseHelper extends SQLiteOpenHelper {
private static final String DATABASENAME = "VERDEFY";
private static final int DATABASE_VERSION = 1;
public static final String TABLE_TRAVELDATA = "travel_data";
public static final String COLUMN_ID = "_id";
public static final String COLUMN_STARTLOCATION = "startLocation";
public static final String COLUMN_ENDLOCATION = "endLocation";
public static final String COLUMN_STARTTIMESTAMP = "startTimeStamp";
public static final String COLUMN_ENDTIMESTAMP = "endTimeStamp";
private static final String TABLE_CREATE =
"CREATE TABLE " + TABLE_TRAVELDATA + " (" +
COLUMN_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
COLUMN_STARTLOCATION + " TEXT, " +
COLUMN_ENDLOCATION + " TEXT, " +
COLUMN_STARTTIMESTAMP + " DATETIME DEFAULT CURRENT_TIMESTAMP, " +
COLUMN_ENDTIMESTAMP + " DATETIME DEFAULT CURRENT_TIMESTAMP)";
public DatabaseHelper(Context context) {
super(context, DATABASENAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(TABLE_CREATE);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS " + TABLE_TRAVELDATA);
onCreate(db);
}
// Add this method to your DatabaseHelper class
public void addTravelData(String startLocation, String startTimeStamp, String endLocation, String endTimeStamp) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(COLUMN_STARTLOCATION, startLocation);
values.put(COLUMN_STARTTIMESTAMP, startTimeStamp);
values.put(COLUMN_ENDLOCATION, endLocation);
values.put(COLUMN_ENDTIMESTAMP, endTimeStamp);
db.insert(TABLE_TRAVELDATA, null, values);
db.close();
}
}
数据库代码没有任何问题,例如使用您的 DatabaseHelper 类,复制 asis,然后复制以下活动代码:-
public class MainActivity extends AppCompatActivity {
DatabaseHelper dbh;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
dbh = new DatabaseHelper(this);
dbh.addTravelData("Here",String.valueOf(System.currentTimeMillis()),"There",String.valueOf(System.currentTimeMillis()));
Cursor csr = dbh.getWritableDatabase().rawQuery("SELECT * FROM " + DatabaseHelper.TABLE_TRAVELDATA,null);
DatabaseUtils.dumpCursor(csr);
csr.close();
}
}
然后日志包括:-
2024-02-27 05:37:11.428 I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@d598771
2024-02-27 05:37:11.428 I/System.out: 0 {
2024-02-27 05:37:11.428 I/System.out: _id=1
2024-02-27 05:37:11.429 I/System.out: startLocation=Here
2024-02-27 05:37:11.429 I/System.out: endLocation=There
2024-02-27 05:37:11.429 I/System.out: startTimeStamp=1708972631288
2024-02-27 05:37:11.429 I/System.out: endTimeStamp=1708972631288
2024-02-27 05:37:11.429 I/System.out: }
2024-02-27 05:37:11.429 I/System.out: <<<<<
使用应用程序检查显示:-
因此,假设问题出在数据库上的情况很可能并非如此。
您有大量似乎需要库的代码。简而言之,这个问题并未根据 StackOverflow 指南提出。
更重要的是,当您说:-
时,表明您在调试问题方面几乎没有尝试过但是我现在遇到的错误是,每当我单击“开始旅程”按钮时,移动应用程序就会自动退出。
首先要做的是查看日志,这将有一个异常,它会指出发生故障的位置。
猜测您的问题很可能是这样的:-
2024-02-27 06:19:46.237 26545-26545/a.a.so78062371javasqlitedb E/AndroidRuntime: FATAL EXCEPTION: main
Process: a.a.so78062371javasqlitedb, PID: 26545
java.lang.IllegalStateException: Could not find method onStartJourneyButtonClick(View) in a parent or ancestor Context for android:onClick attribute defined on view class com.google.android.material.button.MaterialButton with id 'startButton'
at androidx.appcompat.app.AppCompatViewInflater$DeclaredOnClickListener.resolveMethod(AppCompatViewInflater.java:506)
at androidx.appcompat.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:464)
at android.view.View.performClick(View.java:6597)
at com.google.android.material.button.MaterialButton.performClick(MaterialButton.java:1218)
at android.view.View.performClickInternal(View.java:6574)
at android.view.View.access$3100(View.java:778)
at android.view.View$PerformClick.run(View.java:25885)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
如果是这种情况,则问题出在按钮及其 onClick 处理上。
使用 activty_main.xml 的子集添加两个按钮,如下所示:-
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/startButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="44dp"
android:layout_marginBottom="72dp"
android:text="Start Journey"
android:onClick="onStartJourneyButtonClick"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
tools:ignore="MissingConstraints,OnClick" />
<Button
android:id="@+id/EndButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="44dp"
android:layout_marginBottom="72dp"
android:text="End Journey"
android:onClick="onEndJourneyButtonClick"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
tools:ignore="MissingConstraints,OnClick" />
</androidx.constraintlayout.widget.ConstraintLayout>
然后运行应用程序,然后单击任一按钮都会导致上述异常。
修改主活动代码以实际将按钮分配给相应的变量并包含 SendDataToDatabase 类(修改为仅添加一些数据),如下所示:-
public class MainActivity extends AppCompatActivity {
Button startButton,endButton;
SendDataToDatabase sendDataToDatabase;
DatabaseHelper dbh;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
sendDataToDatabase = new SendDataToDatabase();
startButton = this.findViewById(R.id.startButton);
endButton = this.findViewById(R.id.EndButton);
dbh = new DatabaseHelper(this);
dbh.addTravelData("Here",String.valueOf(System.currentTimeMillis()),"There",String.valueOf(System.currentTimeMillis()));
Cursor csr = dbh.getWritableDatabase().rawQuery("SELECT * FROM " + DatabaseHelper.TABLE_TRAVELDATA,null);
DatabaseUtils.dumpCursor(csr);
csr.close();
}
public class SendDataToDatabase {
// Your other methods
//START a journey and start tracking
// Send location and timestamp to the database
// Start tracking user's location
// You can use the Google Maps Directions API to calculate distance and carbon emission
// Start a timer or capture the start time for duration calculation
public void startJourney(View view) {
// Get current location and timestamp
/*
if (lastKnownLocation != null) {
String startLocation = getLocationName(lastKnownLocation.getLatitude(), lastKnownLocation.getLongitude());
String startTimeStamp = getCurrentTimestamp();
// Assuming addTravelData is a method of DatabaseHelper class
DatabaseHelper dbHelper = new DatabaseHelper(MainActivity.this); // Assuming this is your activity context
dbHelper.addTravelData(startLocation, startTimeStamp,null, null);
}
*/
DatabaseHelper dbHelper = new DatabaseHelper((MainActivity.this));
dbHelper.addTravelData(null,null, "AHere" + System.currentTimeMillis(), "AThere" + System.currentTimeMillis());
}
// END A JOURNEY, stop all tracking
public void endJourney(View view) {
// Stop tracking user's location
/*
if (lastKnownLocation != null) {
String endLocation = getLocationName(lastKnownLocation.getLatitude(), lastKnownLocation.getLongitude());
String endTimeStamp = getCurrentTimestamp();
DatabaseHelper dbHelper = new DatabaseHelper(MainActivity.this);
// Save end location and timestamp to the database
dbHelper.addTravelData(null,null, endLocation, endTimeStamp);
}
*/
// Calculate distance travelled
// Calculate time duration
// Calculate carbon emission if possible
// Send all captured data (distance, duration, type of vehicle, etc.) to the database
DatabaseHelper dbHelper = new DatabaseHelper((MainActivity.this));
dbHelper.addTravelData(null,null, "EHere" + System.currentTimeMillis(), "EThere" + System.currentTimeMillis());
}
// Method to handle start journey button click
public void onStartJourneyButtonClick(View view) {
sendDataToDatabase.startJourney(view);
}
// Method to handle end journey button click
public void onEndJourneyButtonClick(View view) {
sendDataToDatabase.endJourney(view);
}
}
}
再次导致相同的异常(单击任一按钮时)。
但是如果使用以下方式设置 onClick 侦听器:-
startButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
sendDataToDatabase.startJourney(view);
}
});
endButton = this.findViewById(R.id.EndButton);
endButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
sendDataToDatabase.endJourney(view);
}
});
然后,当应用程序启动时:-
应用程序检查显示:-
单击“开始旅程”按钮不存在,然后“应用程序检查”显示:-
单击“结束旅程”按钮喜欢作品,应用程序检查显示:-
因此,根据代码的精简版本,您的问题很可能在于按钮的处理。您可能希望在 MainActivity 的
onCreate
方法中包含以下代码:-
startButton = this.findViewById(R.id.startButton);
startButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
sendDataToDatabase.startJourney(view);
}
});
endButton = this.findViewById(R.id.EndButton);
endButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
sendDataToDatabase.endJourney(view);
}
});