如何从 HomeScreen Widget 调用 Activity 中的函数

How to call function in Activity from HomeScreen Widget

从位于主屏幕上的小部件调用我的应用程序 Activity 中的函数的正确方法是什么?对于我的示例,我有一个在 Activity class 中初始化的后台线程,并且希望能够从主屏幕按下小部件以调用特定功能 start/stop线程而无需进入应用程序。

下面是我正在使用的 Activity 的精简准系统版本:

public class MainActivity extends AppCompatActivity {
    private Thread thread;
    private Runnable runner;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        startThread();
    }

    private void startThread() {
        //start/restart the thread
    }

    public void stopThread() {
        //interupt the thread
    }   
}

以下是主屏幕小部件的准系统代码:

static void updateAppWidget(Context context, AppWidgetManager appWidgetManager, int appWidgetId) {

    Intent intent = new Intent(context, MainActivity.class);

    intent.putExtra("Goal","Stop");
    PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);

    RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.speed_widget);
    views.setOnClickPendingIntent(R.id.widgetButton, pendingIntent);

    appWidgetManager.updateAppWidget(appWidgetId, views);
}

这是我目前最好的解决方案:从我迄今为止所做的研究来看,我似乎需要继续使用 putExtra() 然后 getExtra() 的意图是从小部件发送,并添加一个字符串来说明是否根据线程的状态调用 startThread()stopThread()。目前的目标是这样使用它:

    String intentGoal = getIntent().getExtras().getString("Goal");
    if(intentGoal.compareTo("Stop")==0){
        stopThread();
    }else if(intentGoal.compareTo("Start")==0){
        startThread();
    }

而且它很可能 运行 在 onNewIntent() 的重载版本中。但是,从小部件发送的意图也会导致对 onCreate() 的调用,我不希望发生这种情况,因为它会重新启动线程,并且我拥有的各种其他初始化代码将被重新 运行 还有。我尝试将 launchMode 设置为 singleTask,但它仍然会调用 onCreate() 而不仅仅是 onNewIntent()。回顾一下,我希望能够按下主屏幕小部件,然后启动或停止线程,或者更一般地调用现有“MainActivity”中的特定函数。

我不是 Widget-building-process 方面的专家,但我认为您需要更改:

PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);

收件人:

PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, 0);

由于您需要提供一些与应用程序的交互,因此您不需要将小部件附加到特定的 activity。相反,您需要使用 so to say 消息传递机制。在 Android 中是 BroadcastReciever。例如,您使用它与您的 "start" 服务进行交互。你可以阅读 here about simple example.

此外,根据 this 的回答,我们得出了解决方案,您需要在清单中注册接收者:

然后在onRecieve方法中你可以解析你的意图并做任何你想做的事。在你的情况下,我建议将背景工作从 Activity 传输到 Service,因为 Activity 可以关闭(好的,Service 也是,但它可以恢复和运行 无屏幕)。在 MyWidgetReciever.onReceive 中,您需要通过传递 "stop" 意图来启动服务。

我不确定,但是,也许你可以直接在服务中捕获广播,而不是在外部接收器中,但可能是服务被终止的情况,所以它不会处理你的广播。

在 Michael Spitsin 的回答和 the answer here 之间,我找到了一种在单击主屏幕小部件按钮时执行特定方法的方法。正如 Michael 所说,getBroadcastgetActivity 是有区别的。对于这种情况,我能够使用 getBroadcast 来广播一个意图,但我没有将意图打开 MainActivity,而是使用了 this.class,其中 "this" 是class 函数 updateAppWidget 所在的

它所做的是向自己广播一个意图,并在同一个 class 中被捕获在 onReceive(Context,Intent) 中。确保在你发送的 Intent 上使用 addAction 来让你的 Intent 有别于被 onReceive 捕获的其他 Intent 你只需要用你自己的实现重载该方法我链接到的其他答案是这样做的。下面是我让小部件工作的精简版本:

public class MyWidget extends AppWidgetProvider {
    public static String YOUR_ACTION = "YourAction";

    static void updateAppWidget(Context context, AppWidgetManager appWidgetManager, int appWidgetId) {

        Intent intent = new Intent(context, SpeedWidget.class);
        intent.setAction(YOUR_ACTION);

        PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, 0);
        RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.speed_widget);
        views.setOnClickPendingIntent(R.id.widgetButton, pendingIntent);

        appWidgetManager.updateAppWidget(appWidgetId, views);

    }

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

        if (intent.getAction().equals(YOUR_ACTION)) {
                //THIS IS WHERE YOUR CODE WILL BE EXECUTED
            }
        }
    }
}