通过服务更新 Android 小部件,即执行 http 请求

Posted

技术标签:

【中文标题】通过服务更新 Android 小部件,即执行 http 请求【英文标题】:Android widget update via service, that is doing http requests 【发布时间】:2015-01-25 03:07:14 【问题描述】:

以下场景的最佳策略是什么:

我的应用程序将定期向服务器运行 php 脚本发送和接收 http 请求。 我尝试了由 AlarmManager 触发的服务或直接单击其小部件。设备上的直接操作工作正常(如随机数,请参阅http://www.vogella.com/tutorials/androidWidgets/article.html) 当涉及到请求时,这些应该在异步任务中完成。我试图从异步任务的 postexecute 部分更新小部件(remoteView),但它不起作用。

谁能给我一些提示或者sn-ps?

提前谢谢你

更新:

具有异步任务的小部件提供程序类:

public class MyWidgetProvider extends AppWidgetProvider 

private static final String ACTION_CLICK = "ACTION_CLICK";
long ddd;
String dddd;
RemoteViews remoteViews;
TextView tvUpdate;


  private static final String LOG = "de.vogella.android.widget.example";

  @Override
  public void onUpdate(Context context, AppWidgetManager appWidgetManager,
      int[] appWidgetIds) 

    Log.w(LOG, "onUpdate method called");
    // Get all ids
    ComponentName thisWidget = new ComponentName(context,
        MyWidgetProvider.class);
    int[] allWidgetIds = appWidgetManager.getAppWidgetIds(thisWidget);

    // Build the intent to call the service
    Intent intent = new Intent(context.getApplicationContext(),
        UpdateWidgetService.class);
    intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, allWidgetIds);

    // Update the widgets via the service
    context.startService(intent);
  
 

具有异步任务的服务类对网站进行 ping 操作(仅用于测试目的,以后的请求将在那里完成) 目的是在小部件中显示 ping:

public class UpdateWidgetService extends Service 
private static final String LOG = "de.vogella.android.widget.example";
long ddd;
String dddd;
RemoteViews remoteViews;
TextView tvUpdate;

@Override
public void onStart(Intent intent, int startId) 
    Log.i(LOG, "Called");
    // create some random data

    AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(this
            .getApplicationContext());

    int[] allWidgetIds = intent
            .getIntArrayExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS);

    ComponentName thisWidget = new ComponentName(getApplicationContext(),
            MyWidgetProvider.class);
    int[] allWidgetIds2 = appWidgetManager.getAppWidgetIds(thisWidget);
    Log.w(LOG, "From Intent" + String.valueOf(allWidgetIds.length));
    Log.w(LOG, "Direct" + String.valueOf(allWidgetIds2.length));

    for (int widgetId : allWidgetIds) 
        // create some random data
        int number = (new Random().nextInt(100));

        remoteViews = new RemoteViews(this
                .getApplicationContext().getPackageName(),
                R.layout.widget_layout);
        Log.w("WidgetExample", String.valueOf(number));
        if (dddd!=null)Log.w("dddd -", dddd);
        new LongOperation().execute("");
        if (dddd!=null)Log.w("dddd +", dddd);
        // Set the text
        remoteViews.setTextViewText(R.id.update,
                "Random: " + String.valueOf(number));

        // Register an onClickListener
        Intent clickIntent = new Intent(this.getApplicationContext(),
                MyWidgetProvider.class);

        clickIntent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
        clickIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS,
                allWidgetIds);

        PendingIntent pendingIntent = PendingIntent.getBroadcast(
                getApplicationContext(), 0, clickIntent,
                PendingIntent.FLAG_UPDATE_CURRENT);
        remoteViews.setOnClickPendingIntent(R.id.update, pendingIntent);
        appWidgetManager.updateAppWidget(widgetId, remoteViews);
        AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
        Calendar cal = Calendar.getInstance();
        cal.setTimeInMillis(System.currentTimeMillis());
        cal.add(Calendar.SECOND, 5);
        alarmManager.setRepeating(AlarmManager.RTC_WAKEUP,
                cal.getTimeInMillis(), 5 * 1000, pendingIntent);

    
    stopSelf();

    super.onStart(intent, startId);


@Override
public IBinder onBind(Intent intent) 
    return null;


private class LongOperation extends AsyncTask<String, Void, String> 
    @Override
    protected void onPreExecute() 
        // TODO Auto-generated method stub
        super.onPreExecute();
    

    @Override
    protected String doInBackground(String... params) 
        // TODO Auto-generated method stub
        ddd = MainActivity.isURLReachable();

        Log.e("ddd", ddd + "");
        dddd = ddd + " ms";
        Log.e("dddd", dddd);

        return null;
    

    @Override
    protected void onPostExecute(String result) 
        // TODO Auto-generated method stub
        super.onPostExecute(result);
        Log.e("POST dddd", dddd);
        remoteViews.setTextViewText(R.id.update, dddd);
    


问题是无法从执行后的异步任务访问小部件。

更新 2:

如何从 postexecute 方法中获取 WidgetID?

@Override
    protected void onPostExecute(String result) 
        // TODO Auto-generated method stub
        super.onPostExecute(result);
        AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(UpdateWidgetService.this
                .getApplicationContext());

        int[] allWidgetIds = intent
                .getIntArrayExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS);

        ComponentName thisWidget = new ComponentName(getApplicationContext(),
                MyWidgetProvider.class);
        int[] allWidgetIds2 = appWidgetManager.getAppWidgetIds(thisWidget);
        Log.w(LOG, "From Intent" + String.valueOf(allWidgetIds.length));
        Log.w(LOG, "Direct" + String.valueOf(allWidgetIds2.length));

        for (int widgetId : allWidgetIds) 
            // create some random data
            int number = (new Random().nextInt(100));

            remoteViews = new RemoteViews(UpdateWidgetService.this
                    .getApplicationContext().getPackageName(),
                    R.layout.widget_layout);
            Log.w("WidgetExample", String.valueOf(number));
            if (dddd!=null)Log.w("dddd -", dddd);
            new LongOperation().execute("");
            if (dddd!=null)Log.w("dddd +", dddd);
            // Set the text
            remoteViews.setTextViewText(R.id.update,
                    "Random: " + dddd);

            // Register an onClickListener
            Intent clickIntent = new     Intent(UpdateWidgetService.this.getApplicationContext(),
                        MyWidgetProvider.class);

            clickIntent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
            clickIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS,
                    allWidgetIds);

            PendingIntent pendingIntent = PendingIntent.getBroadcast(
                    getApplicationContext(), 0, clickIntent,
                    PendingIntent.FLAG_UPDATE_CURRENT);
            remoteViews.setOnClickPendingIntent(R.id.update, pendingIntent);
            appWidgetManager.updateAppWidget(widgetId, remoteViews);
        


    

【问题讨论】:

“它不起作用”——请完整准确地解释您的症状是什么。 “不工作”不是对您的症状非常有用的描述。除此之外,如果您不给我们“不工作”的代码来查看您的“不工作”代码,我们将无法帮助您。最后,服务不应该使用AsyncTask——也许你的服务应该是IntentService 谢谢你是对的,我提供了一些关于结构的细节。 【参考方案1】:

问题是无法从执行后的异步任务访问小部件。

不需要。 onPostExecute() 可以get an instance of AppWidgetManager via getInstance() 并调用updateAppWidget() 就可以了。

【讨论】:

谢谢,但我怎样才能访问小部件 ID?看编辑? int[] allWidgetIds = intent .getIntArrayExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS); @user1616685:将它们放入您的AsyncTask 的数据成员中。 这是一个很好的答案,但我会尝试实现 intentservice 以使其正确完成。

以上是关于通过服务更新 Android 小部件,即执行 http 请求的主要内容,如果未能解决你的问题,请参考以下文章

通过 remoteview Android 更新小部件

当 Android 中的 Activity 内容更改时,小部件不更新

屏幕打开/关闭时如何更新 Android 小部件?

强制 Android 小部件更新

如何在android中单击按钮时更新小部件的视图?

如何使用服务来监控 Android 中的方向变化