1. Nimm jetzt an unserem Uhans - 3. ADVENT - Gewinnspiel teil - Alle Informationen findest Du hier!

Countdown-Service für Activity und Widget

Dieses Thema im Forum "Android App Entwicklung" wurde erstellt von MrJack, 05.01.2012.

  1. MrJack, 05.01.2012 #1
    MrJack

    MrJack Threadstarter Android-Hilfe.de Mitglied

    Beiträge:
    67
    Erhaltene Danke:
    10
    Registriert seit:
    14.12.2011
    Phone:
    OnePlus One
    Hallo!

    Ich möchte folgendes implementieren:
    1) Ein Service, welches einen Countdown startet
    2) Eine Activity, die jede Sekunde (mittels BroadcastReceiver? die aktuelle Zeit bekommt und ins UI einträgt)
    3) Ein Widget, welches jede Minute die aktuelle Zeit bekommt und ins UI einträgt

    Leider weiß ich nicht genau, wie das umzusetzen ist.
    Folgendes habe ich schon:

    Service:
    Code:
    public class MyService extends Service
    {
        public static final String BROADCAST_ACTION = "myaction";
    
        @Override
        public void onCreate()
        {
            final Intent intent = new Intent( BROADCAST_ACTION );
            
            new CountDownTimer( 100000, 1000 )
            {
                @Override
                public void onTick( long millisUntilFinished )
                {
                    // Zeit entsprechend berechnen und in bestimmtes Format bringen (z.B. HH:mm:SS)
                    
                    intent.putExtra( "time", formattedString );
                    sendBroadcast( intent );
                }
                
                @Override
                public void onFinish()
                {
                }
            }.start();
        }
    
        @Override
        public IBinder onBind( Intent intent )
        {
            // TODO Auto-generated method stub
            return null;
        }
    }
    
    Hier ist meine Activity:
    Code:
    public class MyActivity extends Activity
    {
        private BroadcastReceiver broadcastReceiver = new BroadcastReceiver()
        {
            @Override
            public void onReceive( Context context, Intent intent )
            {
                String time = intent.getStringExtra( "time" );
                TextView tvTime= (TextView) findViewById( R.id.tvTime);
                tvTime.setText( time  );
            }
        };
    
        @Override
        public void onCreate( Bundle savedInstanceState )
        {
            super.onCreate( savedInstanceState );
            setContentView( R.layout.main );
            
            intent = new Intent( this, MyService.class );
            startService( intent );
            registerReceiver( broadcastReceiver, new IntentFilter( MyService.BROADCAST_ACTION ) );
        }
    }
    
    Bis hierhin funktioniert alles wunderbar.
    Problem ist jetzt: Wie erstelle ich das Widget, welches minütlich die Informationen vom Service bekommt?

    Zunächst brauche ich ja sowieso mal irgendein Workaround mittels AlarmManager, damit ich die Aktualisierungszeit auf 1 Minute verringen kann.
    Wie soll ich das umsetzen?

    Danke
     
  2. strider, 05.01.2012 #2
    strider

    strider Erfahrener Benutzer

    Beiträge:
    208
    Erhaltene Danke:
    45
    Registriert seit:
    30.09.2011
    Phone:
    Nexus S
  3. MrJack, 09.01.2012 #3
    MrJack

    MrJack Threadstarter Android-Hilfe.de Mitglied

    Beiträge:
    67
    Erhaltene Danke:
    10
    Registriert seit:
    14.12.2011
    Phone:
    OnePlus One
  4. MrJack, 09.01.2012 #4
    MrJack

    MrJack Threadstarter Android-Hilfe.de Mitglied

    Beiträge:
    67
    Erhaltene Danke:
    10
    Registriert seit:
    14.12.2011
    Phone:
    OnePlus One
    Also, hab mir das mal angesehen, hilft mir leider noch nicht ganz weiter.
    In diesen Beispielen wird nämlich das Widget direkt vom Service upgedatet.

    Ich habe aber vor, dass ich mich im Widget ans Service hänge und im Widget dann update, wenn das Service mir das sagt.

    Also eine Art Listener. Geht das nicht mit einem BroadcastReceiver?

    Ich will nämlich meine Funktionalität im Service halten -> dort wird der Countdown gestartet und jede Sekunde ein Broadcast gesendet.

    Und dann will ich in einer Activity UND einem Widget auf diesen Broadcast reagieren und erst in den entsprechenden Klassen das UI updaten.
     
  5. strider, 09.01.2012 #5
    strider

    strider Erfahrener Benutzer

    Beiträge:
    208
    Erhaltene Danke:
    45
    Registriert seit:
    30.09.2011
    Phone:
    Nexus S
    Hallo Du kannst im Service an der Stelle an der du den Countdown Broadcast verschickst das Widget direkt updaten. Was meinst du mit "im Widget ans Service hängen" ?
     
  6. MrJack, 10.01.2012 #6
    MrJack

    MrJack Threadstarter Android-Hilfe.de Mitglied

    Beiträge:
    67
    Erhaltene Danke:
    10
    Registriert seit:
    14.12.2011
    Phone:
    OnePlus One
    Danke für die Antwort.
    Es geht mir um folgendes Prinzip: Ich habe ein Service und verschiedene Activities bzw. Widgets (können ja mehrere sein), die sich an diesem Service "registieren" sollen. Wenn das Service dann jede Sekunde einen Broadcast ausschickt, sollten alle registrierten Activities / Widgets die Nachricht bekommen und entsprechend weiterbehandeln (d.h. ins UI eintragen). Einziger Unterschied sollte eben sein, dass die Activity jede Sekunde aktualisiert wird und das Widget jede Minute.

    Ich will das ganze so konzipieren, dass das Service nichts über die Activity oder das Widget weiß, sondern einfach nur den Broadcast aussendet.
    In den genannten Beispielen greife ich vom Service immer aufs Widget zu und update dieses. Was ist aber, wenn ich mehrere Widgets habe, die auf das Service reagieren sollen? Muss ich dann alle Widgets direkt im Service updaten?

    Wie ist hier die korrekte Vorgehensweise?
     
  7. strider, 10.01.2012 #7
    strider

    strider Erfahrener Benutzer

    Beiträge:
    208
    Erhaltene Danke:
    45
    Registriert seit:
    30.09.2011
    Phone:
    Nexus S
    Das Widget muss von aussen aktualisiert werden was meistens über einen Service geschieht oder über den AppWidgetProvider(ein getuneter BroadcastReceiver). Es hat leider eigenen code der sich and aktiv bei einem Service registrieren kann. Es wäre also vorteilhaft, wenn sowieso schon ein Service da ist der Broadcasts verschickt das Update gleich an der Stelle passieren zu lassen an dem der Broadcast verschickt wird in dem Service.
    Das erspart eine Menge Overhead.
    Wenn du die Widgets komplett abkoppeln willst um später z.B weitere Widgets nachzuliefern ohne das Projekt mit dem Service neu zu kompilieren, dann must du einen BroadcastReceiver erstellen diesem weist du im XML Manifest über einen Intent Filter das zu auf was er lauschen soll, der Receiver wiederum startet einen Service und der Service aktualisiert das Widget. Das Update des Widgets direkt im Broadcast Receiver ist nicht ratsam da der BroadcastReceiver nur für ein paar Milisekunden laufen darf. Wenn du die Widgets aber immer zusammen mit dem kompletten Projekt auslieferst und nicht getrennt davon, dann wäre das meiner Meinung nach eine unnötige verkomplizierung.
     
    MrJack bedankt sich.
  8. MrJack, 10.01.2012 #8
    MrJack

    MrJack Threadstarter Android-Hilfe.de Mitglied

    Beiträge:
    67
    Erhaltene Danke:
    10
    Registriert seit:
    14.12.2011
    Phone:
    OnePlus One
    Ok, danke nochmals, habs jetzt folgendermaßen gelöst:

    Service:
    Code:
    public class MyService extends Service
    {
        public static final String BROADCAST_ACTION = "myaction";
    
        @Override
        public void onCreate()
        {
            final Intent intent = new Intent( BROADCAST_ACTION );
            
            new CountDownTimer( 100000, 1000 )
            {
                @Override
                public void onTick( long millisUntilFinished )
                {
                    // Zeit entsprechend berechnen und in bestimmtes Format bringen (z.B. HH:mm:SS)
                    
                    intent.putExtra( "time", formattedString );
                    sendBroadcast( intent );
    
                    [B]updateWidgets( formattedString );[/B]
                }
                
                @Override
                public void onFinish()
                {
                }
            }.start();
        }
    
        @Override
        public IBinder onBind( Intent intent )
        {
            // TODO Auto-generated method stub
            return null;
        }
    [B]
        private void updateWidgets( String time )
        {
            AppWidgetManager appmanager = AppWidgetManager.getInstance( this );
            ComponentName cmpName = new ComponentName( this, MyWidget.class );
            int[] widgetIds = appmanager.getAppWidgetIds( cmpName );
            
            for ( int wid : widgetIds )
            {
                RemoteViews rView = new RemoteViews( getPackageName(), R.layout.widget_layout_4_1 );
                rView.setTextViewText( R.id.time, time );
                
                appmanager.updateAppWidget( wid, rView );
            }
        }
    }
    [/B]
    
    BroadcastReceiver:
    Code:
    public class MyReceiver extends BroadcastReceiver
    {
        @Override
        public void onReceive( Context context, Intent intent )
        {
            context.startService( new Intent( context, MyService.class ) );
        }
    }
    
    Widget:
    Code:
    public class MyWidget extends AppWidgetProvider
    {
        public static final int UPDATETIME = 1;
        
        @Override
        public void onUpdate( Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds )
        {
            context.startService( new Intent( context, MyService.class ) );
        }
        
        @Override
        public void onEnabled( Context context )
        {
            Intent intent = new Intent( MyService.BROADCAST_ACTION );
            PendingIntent pendingIntent = PendingIntent.getBroadcast( context, 234567, intent, 0 );
            AlarmManager alarmManager = (AlarmManager) context.getSystemService( Context.ALARM_SERVICE );
            alarmManager.setRepeating( AlarmManager.RTC, System.currentTimeMillis(), 1000 * 60 * UPDATETIME, pendingIntent );
        }
        
        @Override
        public void onDisabled( Context context )
        {
            Intent intent = new Intent( MyService.BROADCAST_ACTION );
            PendingIntent pendingIntent = PendingIntent.getBroadcast( context, 234567, intent, 0 );
            AlarmManager alarmManager = (AlarmManager) context.getSystemService( Context.ALARM_SERVICE );
            alarmManager.cancel( pendingIntent );
        }
    }
    
    Hier die relevanten Teile aus der AndroidManifest.xml:
    Code:
    <receiver android:name=".MyWidget">
    		    <intent-filter>
    		        <action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
    		    </intent-filter>
    		    <meta-data android:name="android.appwidget.provider" android:resource="@xml/widget_provider_4_1" />
    		</receiver>
    		<service android:name=".MyService"></service>
    		<receiver android:name=".MyReceiver">
    		    <intent-filter>
    		        <action android:name="myaction"/>
    		    </intent-filter>
    		</receiver>
    
    Danke für die Mithilfe!
    Sollte mein Code nicht optimal sein, bitte ich um Verbesserungsvorschläge.
     

Diese Seite empfehlen