android - 使用 Gluon-mobile 中的 ALARM_SERVICE 服务在 Android 中安排任务

标签 android javafx alarmmanager gluon gluon-mobile

到目前为止,我已经引用了这个 link 并尝试了这段代码。但是我不知道要在 gluon-mobile 中实现这段代码。我打算做的是我想开始一个在特定时间在后台执行某些作业的缩进。我的问题是我不了解 gluon-mobile 的行为方式。所以请帮助我完成它。

package com.application;

import java.util.Calendar;

import android.app.AlarmManager; 
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import javafxports.android.FXActivity;

 public class Schedular {

AlarmManager manager=null;
FXActivity activity=null;
  public Schedular()
{
 manager=(AlarmManager) FXActivity.getInstance().getSystemService(Context.ALARM_SERVICE);
  activity=FXActivity.getInstance();
}

public void schedule()
{

    Intent indent = new Intent(activity,Alarm.class);
    PendingIntent pIntent = PendingIntent.getBroadcast(activity, 0, indent, 0);

manager.set(AlarmManager.RTC_WAKEUP, SystemClock.elapsedRealtime()+2*1000,indent);  //This is Where I went Wrong

}
}

我想在运行时用户指定的特定时间安排任务,这就是函数 public void schedule(Calendar calendar,boolean flag) 所做的。

Alarm.class

 public class Alarm extends BroadcastReceiver
 {

 @Override
 public void onReceive(Context context, Intent intent)
 {

     // Your code to execute when the alarm triggers
     // and the broadcast is received.   
    new bluetooth.turnOn();  
 }

我已经将 Alarm.class 添加到 AndroidManifest.xml 中

 <?xml version="1.0" encoding="UTF-8"?>
 <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.application" android:versionCode="1" android:versionName="1.0">
    <supports-screens android:xlargeScreens="true"/>

    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />

    <uses-sdk android:minSdkVersion="3" android:targetSdkVersion="26"/>


    <application android:label="Wifischeduler" android:name="android.support.multidex.MultiDexApplication" android:icon="@mipmap/ic_launcher">

            <activity android:name="javafxports.android.FXActivity" android:label="Wifischeduler" android:configChanges="orientation|screenSize">
                    <meta-data android:name="main.class" android:value="com.application.Main"/>
                    <meta-data android:name="debug.port" android:value="0"/>
                    <intent-filter>
                            <action android:name="android.intent.action.MAIN"/>
                            <category android:name="android.intent.category.LAUNCHER"/>
                    </intent-filter>
            </activity>

        <activity android:name="com.gluonhq.impl.charm.down.plugins.android.NotificationActivity"
                       android:parentActivityName="javafxports.android.FXActivity">
           <meta-data android:name="android.support.PARENT_ACTIVITY" 
                 android:value="javafxports.android.FXActivity"/>
     </activity>

 <activity android:name="com.application.AndroidPlatform$PermissionRequestActivity" />

<receiver android:name="com.application.Alarm"  />  // this is where I have included the Alarm.class

<receiver android:name="com.gluonhq.impl.charm.down.plugins.android.AlarmReceiver" />


    </application>

当调用 schedule 方法时,应用程序退出... 我已经运行了 adb logcat -v threadtime 并在 cmd 上得到了这个输出

--------- beginning of crash
07-22 09:21:44.878 13516 13516 E AndroidRuntime: FATAL EXCEPTION: main
07-22 09:21:44.878 13516 13516 E AndroidRuntime: Process:    com.application, PID: 13516
07-22 09:21:44.878 13516 13516 E AndroidRuntime: java.lang.RuntimeException: Unable to instantiate receiver com.application.Alarm: java.lang.IllegalAccessException: java.lang.Class<com.application.Alarm> is not accessible from java.lang.Class<android.app.ActivityThread>
 07-22 09:21:44.878 13516 13516 E AndroidRuntime:        at android.app.ActivityThread.handleReceiver(ActivityThread.java:2739)
 07-22 09:21:44.878 13516 13516 E AndroidRuntime:        at android.app.ActivityThread.access$1900(ActivityThread.java:153)
 07-22 09:21:44.878 13516 13516 E AndroidRuntime:        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1452)
 07-22 09:21:44.878 13516 13516 E AndroidRuntime:        at android.os.Handler.dispatchMessage(Handler.java:102)
 07-22 09:21:44.878 13516 13516 E AndroidRuntime:        at android.os.Looper.loop(Looper.java:154)
07-22 09:21:44.878 13516 13516 E AndroidRuntime:        at android.app.ActivityThread.main(ActivityThread.java:5529)
07-22 09:21:44.878 13516 13516 E AndroidRuntime:        at java.lang.reflect.Method.invoke(Native Method)
07-22 09:21:44.878 13516 13516 E AndroidRuntime:        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:739)
07-22 09:21:44.878 13516 13516 E AndroidRuntime:        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:629)
07-22 09:21:44.878 13516 13516 E AndroidRuntime: Caused by: java.lang.IllegalAccessException: java.lang.Class<com.application.Alarm> is not accessible from java.lang.Class<android.app.ActivityThread>
07-22 09:21:44.878 13516 13516 E AndroidRuntime:        at java.lang.Class.newInstance(Native Method)
07-22 09:21:44.878 13516 13516 E AndroidRuntime:        at android.app.ActivityThread.handleReceiver(ActivityThread.java:2734)
07-22 09:21:44.878 13516 13516 E AndroidRuntime:        ... 8 more
07-22 09:21:44.885  1804  3742 D StatusBar: onNotificationPosted:  Key: 0|com.application|123456|charm://down/Id/abcd12340|10276 GroupKey: 0|com.application|123456|charm://down/Id/abcd12340|10276 Connected: true
07-22 09:21:44.885  1804  1804 D StatusBar:  GroupChild: false  GroupsContainsKey: false  IsUpdate: false IsGroupSummary: false hasIcon: true
07-22 09:21:44.886  1804  1804 D PhoneStatusBar: addNotification pkg=com.application;basepkg=com.application;id=123456
07-22 09:21:44.888  3047 10359 I GCoreUlr: Successfully inserted 1 locations
07-22 09:21:44.922  1804  1804 W ProgressBarDelegate: Unknown Drawable subclass, src=android.graphics.drawable.ScaleDrawable@eb9196
07-22 09:21:44.922  1804  1804 W ProgressBarDelegate: Unknown Drawable subclass, src=android.graphics.drawable.ScaleDrawable@aace117
07-22 09:21:44.932  3451  3518 I octvm_klo: klo lock

我不知道为什么我不能实例化一个接收器(Alarm.class),

@FXML void start()
{

    try{

    Schedule schedule =(Schedule) Class.forName("com.application.Schedular").newInstance();


    schedule.schedule();

    }

最佳答案

您的代码并不完全适合我:我必须将 schedule() 中的 intent 更改为 pIntent,然后我将 Java 实现上的 Schedule 更改为 Class(您如何导入它?)。除此之外,它对我来说运行良好(使用 Android target 25),我没有任何异常。

我将发布初始解决方案(基于您的方法),然后发布更好的解决方案。

初步解决方案

虽然添加平台特定代码的首选方法是遵循 Charm Down 设计模式(请参阅 https://bitbucket.org/gluon-oss/charm-down ),但让 Android 代码正常工作的一种非常快速且肮脏的方法是:

安卓

Scheduler.java

package com.gluonhq.scheduler.android;

import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.SystemClock;
import javafxports.android.FXActivity;

public class Scheduler {

    private final AlarmManager manager;

    public Scheduler() {
        manager = (AlarmManager) FXActivity.getInstance().getSystemService(Context.ALARM_SERVICE);
        Intent indent = new Intent(FXActivity.getInstance(), AlarmReceiver.class);
        PendingIntent pIntent = PendingIntent.getBroadcast(FXActivity.getInstance(), 0, indent, 0);

        manager.set(AlarmManager.RTC_WAKEUP, SystemClock.elapsedRealtime() + 2000, pIntent); 
    }
}

AlarmReceiver.java

package com.gluonhq.scheduler.android;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;

public class AlarmReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context, "Alarm ON", Toast.LENGTH_LONG).show();
    }

}

AndroidManifest.xml

<?xml version="1.0" encoding="UTF-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.gluonhq.scheduler" android:versionCode="1" android:versionName="1.0">
        <supports-screens android:xlargeScreens="true"/>
        <uses-permission android:name="android.permission.INTERNET"/>
        <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
        <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
        <uses-sdk android:minSdkVersion="4" android:targetSdkVersion="25"/>
        <application android:label="GluonScheduler" android:name="android.support.multidex.MultiDexApplication" android:icon="@mipmap/ic_launcher">
                <activity android:name="javafxports.android.FXActivity" android:label="GluonScheduler" android:configChanges="orientation|screenSize">
                        <meta-data android:name="main.class" android:value="com.gluonhq.scheduler.GluonScheduler"/>
                        <meta-data android:name="debug.port" android:value="0"/>
                        <intent-filter>
                                <action android:name="android.intent.action.MAIN"/>
                                <category android:name="android.intent.category.LAUNCHER"/>
                        </intent-filter>
                </activity>
                <receiver android:name="com.gluonhq.scheduler.android.AlarmReceiver" />
        </application>
</manifest

主要/Java

这是使用 Gluon IDE 插件的单一 View 模板项目的基本 View :

GluonScheduler.java

package com.gluonhq.scheduler;

import com.gluonhq.charm.glisten.application.MobileApplication;
import com.gluonhq.charm.glisten.visual.Swatch;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.stage.Stage;

public class GluonScheduler extends MobileApplication {

    public static final String BASIC_VIEW = HOME_VIEW;

    @Override
    public void init() {
        addViewFactory(BASIC_VIEW, () -> new BasicView(BASIC_VIEW));
    }

    @Override
    public void postInit(Scene scene) {
        Swatch.BLUE.assignTo(scene);

        ((Stage) scene.getWindow()).getIcons().add(new Image(GluonScheduler.class.getResourceAsStream("/icon.png")));
    }
}

BasicView.java

package com.gluonhq.scheduler;

import com.gluonhq.charm.glisten.control.AppBar;
import com.gluonhq.charm.glisten.control.Icon;
import com.gluonhq.charm.glisten.mvc.View;
import com.gluonhq.charm.glisten.visual.MaterialDesignIcon;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.geometry.Pos;
import javafx.scene.control.Button;
import javafx.scene.layout.VBox;

public class BasicView extends View {

    public BasicView(String name) {
        super(name);

        Button button = new Button("Schedule task");
        button.setGraphic(new Icon(MaterialDesignIcon.ALARM_ON));
        button.setOnAction(e -> {

            try {
                Class c = Class.forName("com.gluonhq.scheduler.android.Scheduler");
                c.newInstance();
            } catch (ClassNotFoundException | InstantiationException | IllegalAccessException ex) {
                Logger.getLogger(BasicView.class.getName()).log(Level.SEVERE, null, ex);
            }

        });

        VBox controls = new VBox(button);
        controls.setAlignment(Pos.CENTER);

        setCenter(controls);
    }

    @Override
    protected void updateAppBar(AppBar appBar) {
        appBar.setNavIcon(MaterialDesignIcon.MENU.button(e -> System.out.println("Menu")));
        appBar.setTitleText("Basic View");
    }
}

build.gradle

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'org.javafxports:jfxmobile-plugin:1.3.6'
    }
}

apply plugin: 'org.javafxports.jfxmobile'

repositories {
    jcenter()
    maven {
        url 'http://nexus.gluonhq.com/nexus/content/repositories/releases'
    }
}

mainClassName = 'com.gluonhq.scheduler.GluonScheduler'

dependencies {
    compile 'com.gluonhq:charm:4.3.5'
}

jfxmobile {
    downConfig {
        version = '3.3.0'
        // Do not edit the line below. Use Gluon Mobile Settings in your project context menu instead
        plugins 'display', 'lifecycle', 'statusbar', 'storage'
    }
    android {
        manifest = 'src/android/AndroidManifest.xml'
    }
    ios {
        infoPList = file('src/ios/Default-Info.plist')
        forceLinkClasses = [
                'com.gluonhq.**.*',
                'javax.annotations.**.*',
                'javax.inject.**.*',
                'javax.json.**.*',
                'org.glassfish.json.**.*'
        ]
    }
}

部署到您的 Android 设备 (./gradlew androidInstall) 并运行。按下按钮,两秒钟后您将看到 toast :

首选方案

报警服务

虽然上面的代码可以工作,但是使用Class.forName 不是很方便。

按照 Charm Down 服务(例如 LocalNotification),我将改为这样做(您必须保持相同的包名称):

Java

AlarmService.java

package com.gluonhq.charm.down.plugins;

public interface AlarmService {
    public void schedule();
}

AlarmServiceFactory.java

package com.gluonhq.charm.down.plugins;

import com.gluonhq.charm.down.DefaultServiceFactory;

public class AlarmServiceFactory extends DefaultServiceFactory<AlarmService> {

    public AlarmServiceFactory() {
        super(AlarmService.class);
    }

}

安卓

AndroidAlarmService.java

package com.gluonhq.charm.down.plugins.android;

import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.SystemClock;
import com.gluonhq.charm.down.plugins.AlarmService;
import com.gluonhq.scheduler.android.AlarmReceiver;
import javafxports.android.FXActivity;

public class AndroidAlarmService implements AlarmService {

    private final AlarmManager manager;
    private final FXActivity activity;

    public AndroidAlarmService() {
        activity = FXActivity.getInstance();
        manager = (AlarmManager) activity.getSystemService(Context.ALARM_SERVICE);
    }
    @Override
    public void schedule() {
        Intent indent = new Intent(activity, AlarmReceiver.class);
        PendingIntent pIntent = PendingIntent.getBroadcast(activity, 0, indent, 0);

        manager.set(AlarmManager.RTC_WAKEUP, SystemClock.elapsedRealtime() + 2000, pIntent); 
    }

}

(保持与上面相同的 AlarmReceiver 类)。

最后,关于您的看法:

BasicView.java

button.setOnAction(e -> 
        Services.get(AlarmService.class).ifPresent(AlarmService::schedule));

现在可以再次部署运行,结果还是一样的。但显然,这种首选方式具有更多优势。

  • 使用该服务,您还可以在桌面上运行或部署到 iOS:该应用程序将运行(单击按钮时它不会执行任何操作)。
  • 如果需要,您可以为桌面和 iOS 实现解决方案。
  • 您可以通过界面轻松添加更多功能。

关于android - 使用 Gluon-mobile 中的 ALARM_SERVICE 服务在 Android 中安排任务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45197207/

相关文章:

java - 在 javafx 中创建自动完成搜索表单

java - TableView编辑列JAVA FX

java - 安装了无限强度 jar 的非法 key 大小或默认参数

java - 如何知道服务是否正在运行

android - AlarmManager 不适用于时间选择器

android - 如何在android中的特定时间安排长时间运行的网络任务?

android - flutter :- Inside the PageView Image is not setting to fit the screen on width?

android - 自定义 ListView 和上下文菜单。如何得到它?

android - 如何在启动应用程序后立即启动二维码扫描器?

Android如何安装存储在 Assets 文件夹中的apk文件