从主屏幕上的小部件调用应用程序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”中的特定功能。
答案 0 :(得分:1)
我不是Widget-building-process的专家,但我认为你需要改变:
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
要:
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, 0);
由于您需要与应用程序进行一些交互,因此您无需将窗口小部件附加到特定活动。而不是你需要使用这样说消息传递机制。在Android中它是BroadcastReciever
。例如,您使用它与您的"开始"服务。您可以阅读here about simple example。
另外,根据this回答我们解决了,你需要在清单中注册接收者:
然后在onRecieve
方法中,您可以解析您的意图并做任何您想做的事情。在您的情况下,我建议您使用Activity
到Service
的后台进行传输,因为Activity可以关闭(okey,Service
,但它可以在没有屏幕的情况下恢复和运行) 。在MyWidgetReciever.onReceive
中,你需要通过传递"停止"意图。
我不确定,但是,可能你可以直接在服务中接收广播,而不是外部接收器,但可能是服务被杀死的情况,因此它不会处理你的广播。
答案 1 :(得分:0)
在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
}
}
}
}