Ch4*_*t4r 13 android android-service android-8.0-oreo
首先:我知道ConnectivityManager.CONNECTIVITY_ACTION已被弃用,我知道如何使用connectivityManager.registerNetworkCallback.如果阅读JobScheduler,但我不完全确定我是否正确.
我的问题是,当手机与网络连接/断开连接时,我想执行一些代码.这应该在应用程序也在后台时发生.从Android OI开始,如果我想在后台运行我想要避免的服务,则必须显示通知.
我尝试获取有关手机何时使用JobScheduler/JobServiceAPI 连接/断开连接的信息,但它只会在我安排它时执行.对我来说,似乎在这样的事件发生时我无法运行代码.有没有办法实现这个目标?我可能只需要稍微调整一下我的代码吗?
我的JobService:
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public class ConnectivityBackgroundServiceAPI21 extends JobService {
@Override
public boolean onStartJob(JobParameters jobParameters) {
LogFactory.writeMessage(this, LOG_TAG, "Job was started");
ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetwork = connectivityManager.getActiveNetworkInfo();
if (activeNetwork == null) {
LogFactory.writeMessage(this, LOG_TAG, "No active network.");
}else{
// Here is some logic consuming whether the device is connected to a network (and to which type)
}
LogFactory.writeMessage(this, LOG_TAG, "Job is done. ");
return false;
}
}
@Override
public boolean onStopJob(JobParameters jobParameters) {
LogFactory.writeMessage(this, LOG_TAG, "Job was stopped");
return true;
}
Run Code Online (Sandbox Code Playgroud)
我这样启动服务:
JobScheduler jobScheduler = (JobScheduler)context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
ComponentName service = new ComponentName(context, ConnectivityBackgroundServiceAPI21.class);
JobInfo.Builder builder = new JobInfo.Builder(1, service).setPersisted(true)
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY).setRequiresCharging(false);
jobScheduler.schedule(builder.build());
jobScheduler.schedule(builder.build()); //It runs when I call this - but doesn't re-run if the network changes
Run Code Online (Sandbox Code Playgroud)
清单(摘要):
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />
<uses-permission android:name="android.permission.VIBRATE" />
<application>
<service
android:name=".services.ConnectivityBackgroundServiceAPI21"
android:exported="true"
android:permission="android.permission.BIND_JOB_SERVICE" />
</application>
</manifest>
Run Code Online (Sandbox Code Playgroud)
我想必须有一个简单的解决方案,但我无法找到它.
Ch4*_*t4r 11
第二次编辑:我现在正在使用firebase的JobDispatcher,它在所有平台上都很完美(感谢@cutiko).这是基本结构:
public class ConnectivityJob extends JobService{
@Override
public boolean onStartJob(JobParameters job) {
LogFactory.writeMessage(this, LOG_TAG, "Job created");
connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
connectivityManager.registerNetworkCallback(new NetworkRequest.Builder().build(), networkCallback = new ConnectivityManager.NetworkCallback(){
// -Snip-
});
}else{
registerReceiver(connectivityChange = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
handleConnectivityChange(!intent.hasExtra("noConnectivity"), intent.getIntExtra("networkType", -1));
}
}, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
}
NetworkInfo activeNetwork = connectivityManager.getActiveNetworkInfo();
if (activeNetwork == null) {
LogFactory.writeMessage(this, LOG_TAG, "No active network.");
}else{
// Some logic..
}
LogFactory.writeMessage(this, LOG_TAG, "Done with onStartJob");
return true;
}
@Override
public boolean onStopJob(JobParameters job) {
if(networkCallback != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)connectivityManager.unregisterNetworkCallback(networkCallback);
else if(connectivityChange != null)unregisterReceiver(connectivityChange);
return true;
}
private void handleConnectivityChange(NetworkInfo networkInfo){
// Calls handleConnectivityChange(boolean connected, int type)
}
private void handleConnectivityChange(boolean connected, int type){
// Calls handleConnectivityChange(boolean connected, ConnectionType connectionType)
}
private void handleConnectivityChange(boolean connected, ConnectionType connectionType){
// Logic based on the new connection
}
private enum ConnectionType{
MOBILE,WIFI,VPN,OTHER;
}
}
Run Code Online (Sandbox Code Playgroud)
我这样称呼(在我的启动接收器中):
Job job = dispatcher.newJobBuilder().setService(ConnectivityJob.class)
.setTag("connectivity-job").setLifetime(Lifetime.FOREVER).setRetryStrategy(RetryStrategy.DEFAULT_LINEAR)
.setRecurring(true).setReplaceCurrent(true).setTrigger(Trigger.executionWindow(0, 0)).build();
Run Code Online (Sandbox Code Playgroud)
编辑:我找到了一个hacky方式.真的很难说.它有效,但我不会用它:
stopForeground在此之后使用,用户将看不到通知,但Android将其注册为处于前台startService onTaskRemoved它继续运行.实际上,这将启动前台服务,该服务启动后台服务然后终止.第二项服务比第一项服务更长.我不确定这是否是预期的行为(也许应该提交错误报告?)但这是一种解决方法(再次,一个糟糕的行为!).
看起来连接发生变化时无法收到通知:
CONNECTIVITY_ACTION在清单中声明的Android 7.0 接收器将不会接收广播.另外,如果接收器在主线程上注册,则以编程方式声明的接收器仅接收广播(因此使用服务将不起作用).如果您仍想在后台接收更新,则可以使用connectivityManager.registerNetworkCallback 所有这些都允许这些解决方案:
这是不可能的:
connectivityManager.registerNetworkCallback(NetworkInfo, PendingIntent)因为PendingIntent在满足条件时立即执行动作,所以无法使用; 它只被叫一次
因为我已经有其中在前景模式下运行(并且因此显示一个通知)一个VPNService我实施了检查连通性服务在前台运行,如果VPNService不和反之亦然.这始终显示通知,但只显示一个.
总而言之,我发现8.0更新非常不满意,似乎我要么使用不可靠的解决方案(重复JobService),要么通过永久通知中断我的用户.用户应该能够将应用程序列入白名单(仅此一项事实就是存在隐藏"XX正在后台运行"通知的应用程序应该说得足够多).非常适合偏离主题
随意扩展我的解决方案或向我显示任何错误,但这些是我的发现.
| 归档时间: |
|
| 查看次数: |
8059 次 |
| 最近记录: |