Android Widget - Click for action, update under 30 minutes, separate instances

∥☆過路亽.° 提交于 2019-12-29 08:23:33

问题


I've tried to create a widget that, on click calls a routine on Configuration activity, on update calls another routine on Configuration activity, update must be under 30 minutes and all the instance created must work separately (in onUpdate and in onClick).

The code below: Click doesn't work (Can't See Toast Message and other function) Update works fine for first instance but with multiple widget instance it works bad: If i create 2 instances between 10 seconds (and refresh is set to 20 seconds) all will update every 10 seconds.

That's my Manifest:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="it.fraschi.controllogiardinowg"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
       android:targetSdkVersion="17" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="it.fraschi.controllogiardinowg.Configurazione"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.appwidget.action.APPWIDGET_CONFIGURE"/>
            </intent-filter>
        </activity>
        <receiver android:name="it.fraschi.controllogiardinowg.ControlloWidget" android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
            </intent-filter>
            <intent-filter> 
                <action android:name="it.fraschi.controllogiardinowg.ControlloWidget.ACTION_WIDGET_CLICKED"/>
            </intent-filter>
            <intent-filter>
                    <action android:name="it.fraschi.controllogiardinowg.ControlloWidget.MY_OWN_WIDGET_UPDATE" />
                </intent-filter>
            <meta-data android:name="android.appwidget.provider" android:resource="@xml/widget_provider" />
        </receiver>
    </application>
</manifest>

That's my Configuration:

package it.fraschi.controllogiardinowg;




import java.util.Calendar;
import java.util.Random;

import android.os.Bundle;
import android.app.Activity;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.EditText;
import android.widget.RemoteViews;
import android.widget.Spinner;
import android.widget.Toast;
import android.widget.AdapterView.OnItemSelectedListener;

public class Configurazione extends Activity {

private static final String PREFS_NAME  = "it.fraschi.android.ControlloGiardinoWG";

    public static final String NOME  = "nome_";
    private static long millis = 60000;


    private int mAppWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID;
    private int selectedTextColor;
    private int selectedBackgroundColor;

     public Configurazione() {
            super();
        }

     @Override
        public void onCreate(Bundle icicle) {
            super.onCreate(icicle);

            // Set the result to CANCELED.  This will cause the widget host to cancel
            // out of the widget placement if they press the back button.
            setResult(RESULT_CANCELED);

            // Set the view layout resource to use.
            setContentView(R.layout.activity_configurazione);

            // Find the widget id from the intent. 
            Intent intent = getIntent();
            Bundle extras = intent.getExtras();
            if (extras != null) {
                mAppWidgetId = extras.getInt(
                        AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);
            }

            // If they gave us an intent without the widget id, just bail.
            if (mAppWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID) {
                finish();
            }



            //final Spinner backgroundColorSelector = (Spinner)findViewById(R.id.backgroundColor);
            final Button    saveButton = (Button)findViewById(R.id.btnSalva);
            final Button    cancelButton = (Button)findViewById(R.id.btnCancel);
            final EditText  editNome = (EditText)findViewById(R.id.editNome);
            /*textColorSelector.setOnItemSelectedListener(new OnItemSelectedListener() {
                @Override
                public void onItemSelected(AdapterView<?> parentView, View selectedItemView, int position, long id) {
                    selectedTextColor = Integer.parseInt(getResources().getStringArray(R.array.textColorsValues)[textColorSelector.getSelectedItemPosition()]);
                }

                @Override
                public void onNothingSelected(AdapterView<?> parentView) {}

            });*/



            saveButton.setOnClickListener(new OnClickListener() {

                @Override
                public void onClick(View v) {
                    final Context context = Configurazione.this;

                    //prepare Alarm Service to trigger Widget
                       Intent intent = new Intent(ControlloWidget.MY_WIDGET_UPDATE);
                       PendingIntent pendingIntent = PendingIntent.getBroadcast(Configurazione.this, mAppWidgetId, intent, 0);
                       AlarmManager alarmManager = (AlarmManager)getSystemService(ALARM_SERVICE);
                       Calendar calendar = Calendar.getInstance();
                       calendar.setTimeInMillis(System.currentTimeMillis());
                       calendar.add(Calendar.SECOND, 30);
                       alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), millis, pendingIntent);
                       //ControlloWidget.SaveAlarmManager(alarmManager, pendingIntent);
                    ///


                    SharedPreferences.Editor prefs = context.getSharedPreferences(PREFS_NAME, 0).edit();
                    prefs.putString(NOME + mAppWidgetId, editNome.getText().toString());

                    prefs.commit();

                 // Push widget update to surface with newly set prefix
                    AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
                    ControlloWidget.updateAppWidget(context, appWidgetManager, mAppWidgetId);

                    // Make sure we pass back the original appWidgetId
                    Intent resultValue = new Intent();
                    resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId);
                    setResult(RESULT_OK, resultValue);
                    finish();
                }
            });

            cancelButton.setOnClickListener(new OnClickListener() {

                @Override
                public void onClick(View v) {
                    finish();
                }
            });

     }
    /*@Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.configurazione, menu);
        return true;
    }*/
     static String getName(Context context, String prefKey ,int appWidgetId) {
            SharedPreferences prefs = context.getSharedPreferences(PREFS_NAME, 0);
            String valuename = prefs.getString(prefKey + appWidgetId, "Non Trovato");

            return valuename;
        }
     static String getColor(Context context, String prefKey, int appWidgetId){
            ///Test
            SharedPreferences prefs = context.getSharedPreferences(PREFS_NAME, 0);
            String nome = prefs.getString(prefKey + appWidgetId, "Non Trovato");
            ///
            int number = (new Random().nextInt(100));
            String color = "DaConf"+Integer.toString(number)+nome;
            Toast.makeText(context, "ESEGUITO", Toast.LENGTH_LONG).show();
            return color;
     }


}

That's my Widget:

        import java.text.DateFormat;
        import java.text.SimpleDateFormat;
        import java.util.Date;
        import java.util.Random;

        import android.app.AlarmManager;
        import android.app.PendingIntent;
        import android.appwidget.AppWidgetManager;
        import android.appwidget.AppWidgetProvider;
        import android.content.ComponentName;
        import android.content.Context;
        import android.content.Intent;
        import android.os.Bundle;
        import android.os.Environment;
        import android.os.StatFs;

        import android.widget.RemoteViews;
        import android.widget.Toast;

        public class ControlloWidget extends AppWidgetProvider {
            public static String ACTION_WIDGET_CLICKED = "it.fraschi.controllogiardinowg.ESEGUI";
            public static String MY_WIDGET_UPDATE = "it.fraschi.controllogiardinowg.ControlloWidget.MY_OWN_WIDGET_UPDATE";
            static String strWidgetText = "";
            public static Boolean choice = false;


                @Override

                public void onReceive(Context context, Intent intent) {
                    // TODO Auto-generated method stub
                    //super.onReceive(context, intent);
                    String currentDateTimeString = DateFormat.getDateTimeInstance().format(new Date()); 
                    if(MY_WIDGET_UPDATE.equals(intent.getAction())){
                        Bundle extras = intent.getExtras();
                           if(extras!=null) {
                            AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
                            ComponentName thisAppWidget = new ComponentName(context.getPackageName(),
    ControlloWidget.class.getName());
                            int[] appWidgetIds = appWidgetManager.getAppWidgetIds(thisAppWidget);
                            choice=false;
                            onUpdate(context, appWidgetManager, appWidgetIds);
                           }
                        Toast.makeText(context, "WIDGET UPDATE" +currentDateTimeString, Toast.LENGTH_LONG).show();
                    }
                    //Test Click
                    if(ACTION_WIDGET_CLICKED.equals(intent.getAction())){
                        Bundle extras = intent.getExtras();
                           if(extras!=null) {
                            AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
                            ComponentName thisAppWidget = new ComponentName(context.getPackageName(),
    ControlloWidget.class.getName());
                            int[] appWidgetIds = appWidgetManager.getAppWidgetIds(thisAppWidget);
                            choice=true;
                            onUpdate(context, appWidgetManager, appWidgetIds);
                           }
                        Toast.makeText(context, "WIDGET PREMUTO", Toast.LENGTH_LONG).show();
                    }
                    //TestClick
                }

                @Override
                public void onEnabled(Context context) {
                    // TODO Auto-generated method stub
                    //super.onEnabled(context);

                    Toast.makeText(context, "onEnabled()", Toast.LENGTH_LONG).show();
                }

                @Override
                public void onUpdate(Context context, AppWidgetManager appWidgetManager,int[] appWidgetIds) {
                    // TODO Auto-generated method stub
                    //super.onUpdate(context, appWidgetManager, appWidgetIds);

                    final int N = appWidgetIds.length;
                    for (int i=0; i<N; i++) {
                        int appWidgetId = appWidgetIds[i];
                        // Create an Intent to launch ExampleActivity
                        Intent intent = new Intent(context, ControlloWidget.class);
                        intent.setAction(ACTION_WIDGET_CLICKED);
                        intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
                        PendingIntent pendingIntent = PendingIntent.getBroadcast(context, appWidgetId, intent,
                                PendingIntent.FLAG_UPDATE_CURRENT);

                        // Get the layout for the App Widget and attach an on-click listener
                        // to the button
                        RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget);
                        views.setOnClickPendingIntent(R.id.btnEsegui, pendingIntent);
                        // Tell the AppWidgetManager to perform an update on the current app widget
                        appWidgetManager.updateAppWidget(appWidgetId, views);
                        //updateAppWidget(context, appWidgetManager, appWidgetId);

                        //Toast.makeText(context, "onUpdate(): " + String.valueOf(i) + " : " +  String.valueOf(appWidgetId), Toast.LENGTH_LONG).show();
                    }
                     RemoteViews remoteWidget = new RemoteViews(context.getPackageName(),R.layout.widget);


                }



                public static void updateAppWidget(Context context, AppWidgetManager appWidgetManager,int appWidgetId){
                        //TestOnClick
                       RemoteViews remoteWidget = new RemoteViews(context.getPackageName(),R.layout.widget);
                       ///
                       Intent esegui = new Intent(context, ControlloWidget.class);
                       esegui.setAction(ACTION_WIDGET_CLICKED);
                       //Intent esegui = new Intent(ControlloWidget.ACTION_WIDGET_CLICKED);
                       PendingIntent pendingEsegui = PendingIntent.getBroadcast(context, appWidgetId, esegui, 0);
                       remoteWidget.setOnClickPendingIntent(R.id.btnEsegui, pendingEsegui);
                    //

                        //
                        if (choice){
                            RemoteViews updateViews = new RemoteViews(context.getPackageName(), R.layout.widget);
                            updateViews.setTextViewText(R.id.btnEsegui, "[" + String.valueOf(appWidgetId) + "]" + strWidgetText +
    Configurazione.getColor(context, Configurazione.NOME, appWidgetId));
                            appWidgetManager.updateAppWidget(appWidgetId, updateViews);

                            Toast.makeText(context, "onClick(): " + String.valueOf(appWidgetId) + "\n" + strWidgetText,
    Toast.LENGTH_LONG).show();

                        }else{
                                int number = (new Random().nextInt(100));
                                strWidgetText = Integer.toString(number);

                                RemoteViews updateViews = new RemoteViews(context.getPackageName(), R.layout.widget);
                                updateViews.setTextViewText(R.id.btnEsegui, "[" + String.valueOf(appWidgetId) + "]" + strWidgetText +
    Configurazione.getName(context, Configurazione.NOME, appWidgetId));
                                appWidgetManager.updateAppWidget(appWidgetId, updateViews);

                                Toast.makeText(context, "updateAppWidget(): " + String.valueOf(appWidgetId) + "\n" + strWidgetText,
    Toast.LENGTH_LONG).show();
                            }
                }
                static AlarmManager myAlarmManager;
                static PendingIntent myPendingIntent;


                @Override
                public void onDeleted(Context context, int[] appWidgetIds) {
                    // TODO Auto-generated method stub
                    //super.onDeleted(context, appWidgetIds);
                    myAlarmManager.cancel(myPendingIntent);
                    Toast.makeText(context, "onDeleted()", Toast.LENGTH_LONG).show();
                }
                static void SaveAlarmManager(AlarmManager tAlarmManager, PendingIntent tPendingIntent){
                    myAlarmManager = tAlarmManager;
                    myPendingIntent = tPendingIntent;
                }
        }

*


回答1:


For Timing under 30 mins and multiple instances i've decided to use only one timer for all instances.

Below the code onCreate of Configuration Class:

private static long millis = 20000;

SharedPreferences read = context.getSharedPreferences(PREFS_NAME, 0);
String firstinstance = read.getString("FirstInstance", "KO");
if (firstinstance.equals("KO")) {
    SharedPreferences.Editor write = context.getSharedPreferences(
            PREFS_NAME, 0).edit();
    write.putString("FirstInstance", "OK");
    write.commit();
    Intent intent = new Intent(ControlloWidget.MY_WIDGET_UPDATE);
    PendingIntent pendingIntent = PendingIntent.getBroadcast(
            Configurazione.this, 0, intent, 0);
    AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
    Calendar calendar = Calendar.getInstance();
    calendar.setTimeInMillis(System.currentTimeMillis());
    calendar.add(Calendar.SECOND, 10);
    alarmManager.setRepeating(AlarmManager.RTC_WAKEUP,
            calendar.getTimeInMillis(), millis, pendingIntent);
    ControlloWidget.SaveAlarmManager(alarmManager, pendingIntent);
}

revert that process onDisabled of WidgetClass:

@Override
public void onDisabled(Context context) {
    // TODO Auto-generated method stub
    //super.onDisabled(context);
    SharedPreferences.Editor write = context.getSharedPreferences(PREFS_NAME, 0).edit();    
    write.putString("FirstInstance", "KO" );    
    write.commit();
    myAlarmManager.cancel(myPendingIntent);
}
static void SaveAlarmManager(AlarmManager tAlarmManager, PendingIntent tPendingIntent){
    myAlarmManager = tAlarmManager;
    myPendingIntent = tPendingIntent;
}

Now, setting up button Action and My Own Update: Class declaration:

public static String ACTION_WIDGET_CLICKED = "your.packagename.ACTION_WIDGET_CLICKED";
public static String MY_WIDGET_UPDATE = "your.packagename.MY_WIDGET_UPDATE";

onReceive method:

@Override
public void onReceive(Context context, Intent intent) {
    // TODO Auto-generated method stub
    super.onReceive(context, intent);
    choice = false;
    // ////Toast.makeText(context, intent.getAction(),
    // ////Toast.LENGTH_LONG).show();
    // choice=false;

    Bundle extras = intent.getExtras();

    if (MY_WIDGET_UPDATE.equals(intent.getAction())) {
        choice = false;

        AppWidgetManager appWidgetManager = AppWidgetManager
                .getInstance(context);
        ComponentName thisAppWidget = new ComponentName(
                context.getPackageName(), ControlloWidget.class.getName());
        int[] appWidgetIds = appWidgetManager
                .getAppWidgetIds(thisAppWidget);

        onUpdate(context, appWidgetManager, appWidgetIds);
        // ////Toast.makeText(context, "AUTOUPDATE",
        // ////Toast.LENGTH_LONG).show();
    } else

    if (ACTION_WIDGET_CLICKED.equals(intent.getAction())) {
        // choice =true;
        AppWidgetManager appWidgetManager = AppWidgetManager
                .getInstance(context);
        ComponentName thisAppWidget = new ComponentName(
                context.getPackageName(), ControlloWidget.class.getName());
        int[] appWidgetIds = appWidgetManager
                .getAppWidgetIds(thisAppWidget);
        int appWidgetId = intent.getIntExtra(
                AppWidgetManager.EXTRA_APPWIDGET_ID, -1);
        // ////////
        RemoteViews remoteViews = new RemoteViews(context.getPackageName(),
                R.layout.widget);
        remoteViews.setTextViewText(R.id.btnEsegui,
                Configurazione.getName(context, "nome", appWidgetId));

        // ACTION CODE HERE
        appWidgetManager.updateAppWidget(appWidgetId, remoteViews);
        Log.d("LOG_Esecuzione",
                "Log Esecuzione, Widget n." + String.valueOf(appWidgetId));

    }

}

Then onUpdate and updateAppWidget Method:

@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
        int[] appWidgetIds) {
    // TODO Auto-generated method stub
    // super.onUpdate(context, appWidgetManager, appWidgetIds);
    final int N = appWidgetIds.length;
    for (int i = 0; i < N; i++) {
        int appWidgetId = appWidgetIds[i];
        updateAppWidget(context, appWidgetManager, appWidgetId);
    }
}

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

    RemoteViews remoteViews = new RemoteViews(context.getPackageName(),R.layout.widget);
    Intent myIntent = new Intent(context, ControlloWidget.class);
    myIntent.setAction(ACTION_WIDGET_CLICKED);
    myIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
    PendingIntent pendingIntent = PendingIntent.getBroadcast(context,appWidgetId,
            myIntent, 0);
    remoteViews.setOnClickPendingIntent(R.id.btnEsegui, pendingIntent);
    remoteViews.setTextViewText(R.id.btnEsegui,Configurazione.getName(context, "nome", appWidgetId));
    //On Update Code, Requested Action when onUpdate is called (for all widget), it also refresh pending intent                     

    appWidgetManager.updateAppWidget(appWidgetId, remoteViews);
    Log.d("LOG_UPDATE", "Log Update, Widget n."+String.valueOf(appWidgetId));
                                }
    appWidgetManager.updateAppWidget(appWidgetId, remoteViews);
}

For separate instances is necessary:

On intentcreation:(on updateAppWidget)

RemoteViews remoteViews = new RemoteViews(context.getPackageName(),R.layout.widget);
Intent myIntent = new Intent(context, ControlloWidget.class);
myIntent.setAction(ACTION_WIDGET_CLICKED);
            //The line below is the appWidgetId Specification
myIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context,appWidgetId,
        myIntent, 0);
remoteViews.setOnClickPendingIntent(R.id.btnEsegui, pendingIntent);

On receiving broadcast: (on onReceive)

if (ACTION_WIDGET_CLICKED.equals(intent.getAction())){
    //Commented are not used on that example
    //AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
    //ComponentName thisAppWidget = new ComponentName(context.getPackageName(), ControlloWidget.class.getName());
    //int[] appWidgetIds = appWidgetManager.getAppWidgetIds(thisAppWidget);
    int appWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1);

now we could call any routine everywhere passing appWidgetId and Context to function... Example:

Action.SomeAction(context,appWidgetId);

For UPDATE TIMER, is also possible (without using preferences): Like the other intent could use putExtra then on broadcast: retrieve the int on broadcast receive

int appWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1);

BUT now we don't call onUpdate method but directly updateAppWidget with that alternative solution every widget has his own time refresh (maybe configurable) I've preferred to have only one timer process active at same time and get all the widget updated at first instance widget update time



来源:https://stackoverflow.com/questions/15824817/android-widget-click-for-action-update-under-30-minutes-separate-instances

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!