请不要将此问题标记为重复,因为此问题是针对androidx的,而不是针对android8的。大家好,我正在尝试使用谷歌运输跟踪器演示应用程序。链接-https://github.com/googlemaps/transport-tracker/tree/master/android 由于该项目是在较低的版本,我把它迁移到androidx。我得到了关于谷歌api客户端的问题。我已经试过其他的问题,但对我来说不太管用。
当我在我的设备上安装应用程序时,它会崩溃,错误如下
Bad notification for startForeground: java.lang.RuntimeException: invalid channel for service notification
mGoogleApiClient = new GoogleApiClient.Builder is showing as Depricated
构建.gradle
apply plugin: 'com.android.application'
android {
compileSdkVersion 28
buildToolsVersion "28"
defaultConfig {
applicationId "com.google.transporttracker"
minSdkVersion 23
targetSdkVersion 28
versionCode 1
versionName "1.0"
resValue "string", "build_transport_id", (project.findProperty("build_transport_id") ?: "")
resValue "string", "build_email", (project.findProperty("build_email") ?: "")
resValue "string", "build_password", (project.findProperty("build_password") ?: "")
}
packagingOptions {
exclude 'META-INF/LICENSE'
exclude 'META-INF/LICENSE-FIREBASE.txt'
exclude 'META-INF/NOTICE'
}
}
ext {
support = '29'
playServices = '10.2.4'
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'com.google.android.gms:play-services-maps:17.0.0'
testImplementation 'junit:junit:4.12'
implementation 'androidx.appcompat:appcompat:1.0.0'
implementation 'androidx.cardview:cardview:1.0.0'
implementation 'com.google.android.material:material:1.0.0'
implementation "com.google.android.gms:play-services-gcm:17.0.0"
implementation "com.google.android.gms:play-services-location:17.0.0"
implementation "com.google.firebase:firebase-auth:19.3.2"
implementation "com.google.firebase:firebase-config:19.2.0"
implementation "com.google.firebase:firebase-database:19.3.1"
implementation 'com.android.support:design:28.0.0-alpha3'
implementation 'com.google.android.gms:play-services-location:17.0.0'
implementation "com.google.android.gms:play-services-base:17.0.0"
}
apply plugin: 'com.google.gms.google-services'
trackerservice.java文件
package com.google.transporttracker;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.gcm.GcmNetworkManager;
import com.google.android.gms.gcm.OneoffTask;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.OnSuccessListener;
import com.google.android.gms.tasks.Task;
import com.google.firebase.analytics.FirebaseAnalytics;
import com.google.firebase.auth.AuthResult;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.ValueEventListener;
import com.google.firebase.remoteconfig.FirebaseRemoteConfig;
import com.google.firebase.remoteconfig.FirebaseRemoteConfigSettings;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.location.Location;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.BatteryManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.IBinder;
import android.os.PowerManager;
import androidx.core.app.NotificationCompat;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import android.util.Log;
import android.widget.Toast;
import java.io.File;
import java.io.FileWriter;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.LinkedList;
public class TrackerService extends Service implements LocationListener {
private static final String TAG = TrackerService.class.getSimpleName();
public static final String STATUS_INTENT = "status";
private static final int NOTIFICATION_ID = 1;
private static final int FOREGROUND_SERVICE_ID = 1;
private static final int CONFIG_CACHE_EXPIRY = 600; // 10 minutes.
private GoogleApiClient mGoogleApiClient;
private DatabaseReference mFirebaseTransportRef;
private FirebaseRemoteConfig mFirebaseRemoteConfig;
private LinkedList<Map<String, Object>> mTransportStatuses = new LinkedList<>();
private NotificationManager mNotificationManager;
private NotificationCompat.Builder mNotificationBuilder;
private PowerManager.WakeLock mWakelock;
private SharedPreferences mPrefs;
public TrackerService() {
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
buildNotification();
else
startForeground(1, new Notification());
setStatusMessage(R.string.connecting);
mFirebaseRemoteConfig = FirebaseRemoteConfig.getInstance();
FirebaseRemoteConfigSettings configSettings = new FirebaseRemoteConfigSettings.Builder()
.setDeveloperModeEnabled(BuildConfig.DEBUG)
.build();
mFirebaseRemoteConfig.setConfigSettings(configSettings);
mFirebaseRemoteConfig.setDefaults(R.xml.remote_config_defaults);
mPrefs = getSharedPreferences(getString(R.string.prefs), MODE_PRIVATE);
String email = mPrefs.getString(getString(R.string.email), "");
String password = mPrefs.getString(getString(R.string.password), "");
authenticate(email, password);
}
@Override
public void onDestroy() {
// Set activity title to not tracking.
setStatusMessage(R.string.not_tracking);
// Stop the persistent notification.
mNotificationManager.cancel(NOTIFICATION_ID);
// Stop receiving location updates.
if (mGoogleApiClient != null) {
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient,
TrackerService.this);
}
// Release the wakelock
if (mWakelock != null) {
mWakelock.release();
}
super.onDestroy();
}
private void authenticate(String email, String password) {
final FirebaseAuth mAuth = FirebaseAuth.getInstance();
mAuth.signInWithEmailAndPassword(email, password)
.addOnCompleteListener(new OnCompleteListener<AuthResult>(){
@Override
public void onComplete(Task<AuthResult> task) {
Log.i(TAG, "authenticate: " + task.isSuccessful());
if (task.isSuccessful()) {
fetchRemoteConfig();
loadPreviousStatuses();
} else {
Toast.makeText(TrackerService.this, R.string.auth_failed,
Toast.LENGTH_SHORT).show();
stopSelf();
}
}
});
}
private void fetchRemoteConfig() {
long cacheExpiration = CONFIG_CACHE_EXPIRY;
if (mFirebaseRemoteConfig.getInfo().getConfigSettings().isDeveloperModeEnabled()) {
cacheExpiration = 0;
}
mFirebaseRemoteConfig.fetch(cacheExpiration)
.addOnSuccessListener(new OnSuccessListener<Void>() {
@Override
public void onSuccess(Void aVoid) {
Log.i(TAG, "Remote config fetched");
mFirebaseRemoteConfig.activateFetched();
}
});
}
/**
* Loads previously stored statuses from Firebase, and once retrieved,
* start location tracking.
*/
private void loadPreviousStatuses() {
String transportId = mPrefs.getString(getString(R.string.transport_id), "");
FirebaseAnalytics.getInstance(this).setUserProperty("transportID", transportId);
String path = getString(R.string.firebase_path) + transportId;
mFirebaseTransportRef = FirebaseDatabase.getInstance().getReference(path);
mFirebaseTransportRef.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot snapshot) {
if (snapshot != null) {
for (DataSnapshot transportStatus : snapshot.getChildren()) {
mTransportStatuses.add(Integer.parseInt(transportStatus.getKey()),
(Map<String, Object>) transportStatus.getValue());
}
}
startLocationTracking();
}
@Override
public void onCancelled(DatabaseError error) {
// TODO: Handle gracefully
}
});
}
private GoogleApiClient.ConnectionCallbacks mLocationRequestCallback = new GoogleApiClient
.ConnectionCallbacks() {
@Override
public void onConnected(Bundle bundle) {
LocationRequest request = new LocationRequest();
request.setInterval(mFirebaseRemoteConfig.getLong("LOCATION_REQUEST_INTERVAL"));
request.setFastestInterval(mFirebaseRemoteConfig.getLong
("LOCATION_REQUEST_INTERVAL_FASTEST"));
request.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient,
request, TrackerService.this);
setStatusMessage(R.string.tracking);
// Hold a partial wake lock to keep CPU awake when the we're tracking location.
PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
mWakelock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyWakelockTag");
mWakelock.acquire();
}
@Override
public void onConnectionSuspended(int reason) {
// TODO: Handle gracefully
}
};
/**
* Starts location tracking by creating a Google API client, and
* requesting location updates.
*/
private void startLocationTracking() {
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(mLocationRequestCallback)
.addApi(LocationServices.API)
.build();
startForegroundService()
mGoogleApiClient.connect();
}
/**
* Determines if the current location is approximately the same as the location
* for a particular status. Used to check if we'll add a new status, or
* update the most recent status of we're stationary.
*/
private boolean locationIsAtStatus(Location location, int statusIndex) {
if (mTransportStatuses.size() <= statusIndex) {
return false;
}
Map<String, Object> status = mTransportStatuses.get(statusIndex);
Location locationForStatus = new Location("");
locationForStatus.setLatitude((double) status.get("lat"));
locationForStatus.setLongitude((double) status.get("lng"));
float distance = location.distanceTo(locationForStatus);
Log.d(TAG, String.format("Distance from status %s is %sm", statusIndex, distance));
return distance < mFirebaseRemoteConfig.getLong("LOCATION_MIN_DISTANCE_CHANGED");
}
private float getBatteryLevel() {
Intent batteryStatus = registerReceiver(null,
new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
int batteryLevel = -1;
int batteryScale = 1;
if (batteryStatus != null) {
batteryLevel = batteryStatus.getIntExtra(BatteryManager.EXTRA_LEVEL, batteryLevel);
batteryScale = batteryStatus.getIntExtra(BatteryManager.EXTRA_SCALE, batteryScale);
}
return batteryLevel / (float) batteryScale * 100;
}
private void logStatusToStorage(Map<String, Object> transportStatus) {
try {
File path = new File(Environment.getExternalStoragePublicDirectory(""),
"transport-tracker-log.txt");
if (!path.exists()) {
path.createNewFile();
}
FileWriter logFile = new FileWriter(path.getAbsolutePath(), true);
logFile.append(transportStatus.toString() + "\n");
logFile.close();
} catch (Exception e) {
Log.e(TAG, "Log file error", e);
}
}
private void shutdownAndScheduleStartup(int when) {
Log.i(TAG, "overnight shutdown, seconds to startup: " + when);
com.google.android.gms.gcm.Task task = new OneoffTask.Builder()
.setService(TrackerTaskService.class)
.setExecutionWindow(when, when + 60)
.setUpdateCurrent(true)
.setTag(TrackerTaskService.TAG)
.setRequiredNetwork(com.google.android.gms.gcm.Task.NETWORK_STATE_ANY)
.setRequiresCharging(false)
.build();
GcmNetworkManager.getInstance(this).schedule(task);
stopSelf();
}
/**
* Pushes a new status to Firebase when location changes.
*/
@Override
public void onLocationChanged(Location location) {
fetchRemoteConfig();
long hour = Calendar.getInstance().get(Calendar.HOUR_OF_DAY);
int startupSeconds = (int) (mFirebaseRemoteConfig.getDouble("SLEEP_HOURS_DURATION") * 3600);
if (hour == mFirebaseRemoteConfig.getLong("SLEEP_HOUR_OF_DAY")) {
shutdownAndScheduleStartup(startupSeconds);
return;
}
Map<String, Object> transportStatus = new HashMap<>();
transportStatus.put("lat", location.getLatitude());
transportStatus.put("lng", location.getLongitude());
transportStatus.put("time", new Date().getTime());
transportStatus.put("power", getBatteryLevel());
if (locationIsAtStatus(location, 1) && locationIsAtStatus(location, 0)) {
// If the most recent two statuses are approximately at the same
// location as the new current location, rather than adding the new
// location, we update the latest status with the current. Two statuses
// are kept when the locations are the same, the earlier representing
// the time the location was arrived at, and the latest representing the
// current time.
mTransportStatuses.set(0, transportStatus);
// Only need to update 0th status, so we can save bandwidth.
mFirebaseTransportRef.child("0").setValue(transportStatus);
} else {
// Maintain a fixed number of previous statuses.
while (mTransportStatuses.size() >= mFirebaseRemoteConfig.getLong("MAX_STATUSES")) {
mTransportStatuses.removeLast();
}
mTransportStatuses.addFirst(transportStatus);
// We push the entire list at once since each key/index changes, to
// minimize network requests.
mFirebaseTransportRef.setValue(mTransportStatuses);
}
if (BuildConfig.DEBUG) {
logStatusToStorage(transportStatus);
}
NetworkInfo info = ((ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE))
.getActiveNetworkInfo();
boolean connected = info != null && info.isConnectedOrConnecting();
setStatusMessage(connected ? R.string.tracking : R.string.not_tracking);
}
private void buildNotification() {
String NOTIFICATION_CHANNEL_ID = "com.google.transporttracker";
String channelName = "My Background Service";
String channelId = "1";
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
{
NotificationChannel channel = new NotificationChannel(channelId, "LOGIPACE", NotificationManager.IMPORTANCE_DEFAULT);
mNotificationManager.createNotificationChannel(channel);
}
mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
PendingIntent resultPendingIntent = PendingIntent.getActivity(this, 0,
new Intent(this, TrackerActivity.class), PendingIntent.FLAG_UPDATE_CURRENT);
mNotificationBuilder = new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.bus_white)
.setColor(getColor(R.color.colorPrimary))
.setContentTitle(getString(R.string.app_name))
.setOngoing(true)
.setContentIntent(resultPendingIntent);
startForeground(FOREGROUND_SERVICE_ID, mNotificationBuilder.build());
}
/**
* Sets the current status message (connecting/tracking/not tracking).
*/
private void setStatusMessage(int stringId) {
mNotificationBuilder.setContentText(getString(stringId));
mNotificationManager.notify(NOTIFICATION_ID, mNotificationBuilder.build());
// Also display the status message in the activity.
Intent intent = new Intent(STATUS_INTENT);
intent.putExtra(getString(R.string.status), stringId);
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
}
请帮助我解决任何问题。谢谢您的帮助。。
1条答案
按热度按时间i7uaboj41#
在buildnotification()函数中,您使用mnotificationmanager来创建频道,但是管理器的作用如下3行。
因此,当您尝试创建通道时,管理器为空,并且永远不会创建通道。
你应该把
mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
sdk版本测试前的说明。