如何从 HomeScreen Widget 调用 Activity 中的函数
Posted
技术标签:
【中文标题】如何从 HomeScreen Widget 调用 Activity 中的函数【英文标题】:How to call function in Activity from HomeScreen Widget 【发布时间】:2017-01-20 16:55:59 【问题描述】:从位于主屏幕上的小部件调用我的应用程序Activity
中的函数的正确方法是什么?对于我的示例,我有一个在我的 Activity 类中初始化的后台线程,并且希望能够从主屏幕按下小部件以调用特定函数来启动/停止线程,而无需进入应用程序。
以下是我正在使用的 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()
与从小部件发送的 Intent 一起使用,并且添加一个字符串来说明是否根据线程的状态调用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”中的特定函数。
【问题讨论】:
【参考方案1】:我不是小部件构建过程方面的专家,但我认为您需要更改:
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
收件人:
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, 0);
由于您需要提供与应用程序的一些交互,因此您无需将小部件附加到特定活动。取而代之的是,您需要使用这么说的消息传递机制。在 android 中是BroadcastReciever
。例如,您使用它与您的“启动”服务进行交互。你可以阅读here about simple example。
另外,根据this的回答,我们找到了解决方案,你需要在manifest中注册reciever:
然后在onRecieve
方法中,您可以解析您的意图并做任何您想做的事情。在您的情况下,我建议将背景工作从Activity
传输到Service
,因为可以关闭活动(好吧,Service
也可以,但它可以在没有屏幕的情况下恢复和运行)。在MyWidgetReciever.onReceive
中,您需要通过“停止”意图启动服务。
我不确定,但是,也许您可以直接在服务中捕获广播,而不是在外部接收器中,但可能是服务将被杀死的情况,因此它不会处理您的广播。
【讨论】:
【参考方案2】:在 Michael Spitsin 的回答和 the answer here 之间,我能够找到一种在单击主屏幕小部件按钮时执行特定方法的方法。正如迈克尔所说,getBroadcast
和 getActivity
之间是有区别的。对于这种情况,我能够使用getBroadcast
来广播一个意图,但我没有打算打开MainActivity
,而是使用this.class
,其中“this”是函数 updateAppWidget 所在的类.
这样做是向自己广播一个意图,并在同一类的onReceive(Context,Intent)
中捕获。确保在您发送的 Intent 上使用 addAction
以使您的意图与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
【讨论】:
以上是关于如何从 HomeScreen Widget 调用 Activity 中的函数的主要内容,如果未能解决你的问题,请参考以下文章
每个 Activity 中的 NavigationDrawer