Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
507 views
in Technique[技术] by (71.8m points)

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

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, "

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...