Hämta data från MainApp via Widget

Diskussion i 'Frågor, support och diskussion' startad av Jompis, 14 dec 2010.

  1. Jompis

    Jompis Teen Droid Medlem

    Blev medlem:
    10 apr 2010
    Inlägg:
    369
    Mottagna gillanden:
    27

    MINA ENHETER

    Hejsan!
    Jag har gjort en "Dagens Lunch"-app till en bekant. Mest för att jag skulle komma igång med Android. Den hämtar maträtter från ett webbgränssnitt med XML och skriver detta till en databas på Android-enheten.

    Jag ville självfallet lära mig att göra widget också.
    Så det blev en widget där man kan bläddra mellan dagens olika lunch-alternativ.
    Problemet är att den hänger sig lite då och då. Händer först efter flera dagar.
    Jag misstänker att den på något sätt tappar kontakten med min MainApp och crashar när den försöker använda MainAppens funktioner för att hämta data.
    Det är dock bara en teori. Jag har precis lagt in en lite kod som sparar ner "undantag" som inträffar i en log-fil på telefonen. Det jag har sett hittils pekar just på att den inte hämtar data riktigt. Det är inga problem överhuvudtaget med min MainApp. Så det borde vara en koppling därimellan som krånglar.

    Hur har ni andra gjort när ni gör widget? Skriver ni nya funktioner i widgeten? Eller ska det vara smärtfritt att använda MainAppens funktioner rakt av?
     
  2. Kaj

    Kaj Senior Droid Medlem

    Blev medlem:
    12 jun 2009
    Inlägg:
    1 768
    Mottagna gillanden:
    44

    MINA ENHETER

    Bör inte vara några problem med att använda din vanliga kod från en widget. Det jag skulle göra om jag vore dig är att lägga till loggning av både vanliga spåret samt i dina catch-block. Sedan är det bara att köra log collector när din widget slutat funka.
     
  3. woody

    woody Teen Droid Medlem

    Blev medlem:
    3 sept 2009
    Inlägg:
    319
    Mottagna gillanden:
    19

    MINA ENHETER

    Jag antar att du hämtar data från någon webbtjänst och om du gör det i onUpdate så lär det ju kunna ta för lång tid så satt systemet tycker att din widget inte fungerar.
     
  4. Jompis

    Jompis Teen Droid Medlem

    Blev medlem:
    10 apr 2010
    Inlägg:
    369
    Mottagna gillanden:
    27

    MINA ENHETER

    Kaj: Har lagt in LogCollector faktiskt. Har dock glömt att kolla den på ett tag.

    Woody: Om det inte finns något att inskrivet i databasen skrivs ett meddelande ut att de ska klicka på widgeten för att öppna MainAppen, som då uppdateras automatiskt, och sedan uppdaterar widgeten när datan är inskriven i databasen. Så det borde inte vara problemet.

    Jag återkommer när jag har loggfilerna. Det hände som sagt bara efter några dagar, om jag inte kan framkalla det med lite datum-byte lite snabbare.
     
  5. Jompis

    Jompis Teen Droid Medlem

    Blev medlem:
    10 apr 2010
    Inlägg:
    369
    Mottagna gillanden:
    27

    MINA ENHETER

    Jag har kollat flertalet loggar nu och rättat till saker som jag inte hade räknat med. Huvudproblemet har dock inte haft något med dessa att göra.

    Kod:
    remoteViews.setTextViewText( R.id.widget_category_dark, getFormatedWidgetData("category"));
    Jag får en "java.lang.NullPointerException" på den raden. Tyvärr förtäljer den inte om det är "remoteViews" eller "R.id.widget_category_dark" som är Null.
    Jag sätter mina pengar på "remoteViews". Men det är väldigt illa isåfall, eftersom den uppdaterar datan i widgeten. Hade det vart "getFormatedWidgetData("category")" borde jag ha fått ett fel i själva funktionen, inte på return-värdet, eller har jag fel?

    Finns det något sätt att få den att uppdatera sig själv snabbare än 6 timmar? Heltkasst att felsöka när jag måste vänta 6 timmar mellan försöken. Den händer nämligen bara efter att jag har ställt fram datumet en vecka och väntat 6 timmar på att den ska uppdatera sig själv.

    Hela loggen:
    Bli medlem eller för att visa innehållet!
     
    Last edited: 15 dec 2010
  6. ozp

    ozp Teen Droid Medlem

    Blev medlem:
    6 maj 2010
    Inlägg:
    250
    Mottagna gillanden:
    31

    MINA ENHETER

    R.id.widget_category_dark kan inte vara null eftersom det är en int.
    Det kan inte heller vara getFormatedWidgetData("category") eftersom inget objekt används. Hade det varit i funktionen hade den synts i stacktracen.

    Så det är remoteViews som inte är initierad. Skapar du inte den i onUpdate i AppWidgetProvidern?

    Du bestämmer uppdateringsintervallet i widget-provider-xml-filen.
    Attributet heter UpdatePeriodMillis och är millisekunder mellan uppdateringarna.
     
  7. Kaj

    Kaj Senior Droid Medlem

    Blev medlem:
    12 jun 2009
    Inlägg:
    1 768
    Mottagna gillanden:
    44

    MINA ENHETER

    Är det där rad 160 i WidgetDark.java?

    Raden du postade kan endast ge NullPointerException om remoteViews är null.

    Edit: Hur hanterar du din livscykel? Det kan hända att remoteViews blir satt till null.
     
  8. Jompis

    Jompis Teen Droid Medlem

    Blev medlem:
    10 apr 2010
    Inlägg:
    369
    Mottagna gillanden:
    27

    MINA ENHETER

    remoteViews skapas precis som du förutser i OnUpdate.

    Kod:
    remoteViews = new RemoteViews( context.getPackageName(), R.layout.widget_dark );
    Vad kan felet vara? Kan den "glömma" bort värdet på en variabel? Kan det hjälpa om jag skickar den igenom funktionerna istället för att ha den "global"?

    Edit: Det är min första och enda widget. Så det kan mycket väl vara taffligt programmerat.
    Det är egentligen mer ett proof-of-I-really-made-it-concept ;) Kan bifoga hela källkoden om ni vill se.
     
    Last edited: 15 dec 2010
  9. Jompis

    Jompis Teen Droid Medlem

    Blev medlem:
    10 apr 2010
    Inlägg:
    369
    Mottagna gillanden:
    27

    MINA ENHETER

    Ja, precis. Det måste vara så. Frågan är bara varför.
     
  10. Kaj

    Kaj Senior Droid Medlem

    Blev medlem:
    12 jun 2009
    Inlägg:
    1 768
    Mottagna gillanden:
    44

    MINA ENHETER

    När skapar du din remote view? Vanligen skapar man den i sin onUpdate. Din AppWidgetProvider instans kan är inte garanterad att alltid finnas, så jag har inga klassvariabler i mina instanser.

    Edit: Såg nu ditt tidigare inlägg där du skriver att den är global. Ja, det är ditt fel.
     
  11. Jompis

    Jompis Teen Droid Medlem

    Blev medlem:
    10 apr 2010
    Inlägg:
    369
    Mottagna gillanden:
    27

    MINA ENHETER

    Okej, då är jag med. Widgeten fungerar så att man kan man blädrra mellan dagens maträtter. Den får bara plats en åt gången. Så det sitter två pilar man bläddrar med.

    Om det nu är så att den tappar instansen, hur ska jag kunna uppdatera texten i widgeten så att nästa maträtt visas?
    Går det att skapa en ny instans vid behov själv? Eller måste den skapas via onUpdate?
    Kan jag på något sätt göra så att den alltid garanteras vara kvar?
    Eller går det att få den att byta maträtt på något annat sätt än att använda instansen internt i widgeten? Eller måste allt som händer i widgeten ske via en remoteView?
     
    Last edited: 15 dec 2010
  12. Jompis

    Jompis Teen Droid Medlem

    Blev medlem:
    10 apr 2010
    Inlägg:
    369
    Mottagna gillanden:
    27

    MINA ENHETER

    Den har minst 6 timmar som en nedre gräns för att inte sluka batteri. Vill man ha mindre måste man ha en timer på något vis. Rätta mig om jag har fel.
     
  13. Kaj

    Kaj Senior Droid Medlem

    Blev medlem:
    12 jun 2009
    Inlägg:
    1 768
    Mottagna gillanden:
    44

    MINA ENHETER

    Varje widget har ett id, du kan lagra information i t.ex en databas, SharedPreferences eller något liknandes. Använd widget id som nyckel. I onUpdate skapar du en ny RemoteView och visar det som är associerat med din nyckel.
     
  14. Jompis

    Jompis Teen Droid Medlem

    Blev medlem:
    10 apr 2010
    Inlägg:
    369
    Mottagna gillanden:
    27

    MINA ENHETER

    Problemet verkar dock inte ligga i uppdateringen. För den första maträtter visas alltid. Oavsett om programmet kommer att krascha eller inte när jag bläddrar.

    Så remoteView fungerar uppenbarligen vid uppdatering och X antal timmar/minuter senare. När jag sedan bläddrar använder den som sagt en global remoteView, som verkar tappa sitt värde. Något med instansen bla.bla.

    När jag sen trycker på bläddra-knapparna kör följande:

    Kod:
    remoteViews.setTextViewText( R.id.widget_category_dark, getFormatedWidgetData("category"));
    remoteViews.setTextViewText( R.id.widget_dish_dark, getFormatedWidgetData("dish"));
    remoteViews.setTextViewText( R.id.widget_date_dark, date_name);
    currentAppWidgetManager.updateAppWidget( myWidget, remoteViews );
    
    myWidget och remoteView är globala variabler som jag sätter i onUpdate.

    Kod:
    @Override
    public void onUpdate( Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds )
    {
    remoteViews = new RemoteViews( context.getPackageName(), R.layout.widget_dark );
    myWidget = new ComponentName( context, WidgetDark.class );
    currentContext = context;
    }
    
    Om de nu har tappat sina värden när jag bläddrar fram en ny lunch. Hur gör jag för att definiera dom på nytt?

    Om widgeten tappar dessa två variablers värden, så tappar den säkerligen min globala "currentContext" också. Det gör att databas-kopplingen också kraschar. Och jag skulle även chansa på att min globala array med dagens maträtter( de ligger i en array för att de inte ska läsas in varje bläddring) också töms. Det snurrar verkligen i min skalle. Jag vet inte ens vad jag ska fråga. Lättare om ni kikar på det och rättar felet på min fråga innan jag har ställt den.
     
  15. Kaj

    Kaj Senior Droid Medlem

    Blev medlem:
    12 jun 2009
    Inlägg:
    1 768
    Mottagna gillanden:
    44

    MINA ENHETER

    Det är för att din remote view mer eller mindre är en död bild. Om ditt program smäller efter 6 timmar kommer du inte se något iom att "bilden" är kvar.

    Det finns inget som säger när OS:et kommer kasta bort din instans. Det är bara dokumenterat att det kan hända, och en ny kommer sedan skapas när något skall köras.
     
  16. Jompis

    Jompis Teen Droid Medlem

    Blev medlem:
    10 apr 2010
    Inlägg:
    369
    Mottagna gillanden:
    27

    MINA ENHETER

    Okej, då är jag med. Så lösningen är att upprätta en ny remoteView på något vis.
    Jag ska undersöka saken vidare!
    Tack så länge.

    Edit: Eftersom det följer med en context när jag trycker på knapparna använder jag den för att köra följande om remoteView är null när jag trycker på en knapp:

    Kod:
    remoteViews = new RemoteViews( context.getPackageName(), R.layout.widget_dark );
    myWidget = new ComponentName( context, WidgetDark.class );
    
    Nu återstår det bara att se hur "appWidgetManager" hanteras. Den följer bara med onUpdate.
    Men om den är intakt borde allt vara lugnt. Eftersom det verkar gå att göra nya remoteViews.
    Det tar som sagt dock massa timmar innan jag vet. Riktigt jobbig felsökning.


    Edit: Okej, efter ytterligare lite googlande har jag gjort mig oberoende av alla globala variabler som är kritiska.

    Slutreslutatet:
    Kod:
    public static void setWidgetData(Context context) {
    		
    	try {
    		RemoteViews remoteViews = new RemoteViews( context.getPackageName(), R.layout.widget_dark );
    		ComponentName myWidget = new ComponentName( context, WidgetDark.class );
    			
    		remoteViews.setTextViewText( R.id.widget_category_dark, getFormatedWidgetData(context, "category"));
    		remoteViews.setTextViewText( R.id.widget_dish_dark, getFormatedWidgetData(context,"dish"));
    		remoteViews.setTextViewText( R.id.widget_date_dark, date_name);
    			
    		AppWidgetManager.getInstance(context).updateAppWidget( myWidget, remoteViews );
    			
    	} catch (Exception e) {
    		Toast.makeText(context, "Kunde inte uppdatera widgeten. Starta om din telefon om du vill vara säker på att lösa problemet.", Toast.LENGTH_LONG).show();
    	}
    }
    
     
    Last edited: 16 dec 2010
  17. Kaj

    Kaj Senior Droid Medlem

    Blev medlem:
    12 jun 2009
    Inlägg:
    1 768
    Mottagna gillanden:
    44

    MINA ENHETER

    Notera att du hade rätt i ditt antagande att din array med luncher också kan bli null. Nu kommer du väl smälla i det fallet? Persistera dina menyer, och ladda dem om arrayen är null.
     
  18. Jompis

    Jompis Teen Droid Medlem

    Blev medlem:
    10 apr 2010
    Inlägg:
    369
    Mottagna gillanden:
    27

    MINA ENHETER

    Sant, det glömde jag bort! Tack så mycket för påpekandet! :)
     
  19. Jompis

    Jompis Teen Droid Medlem

    Blev medlem:
    10 apr 2010
    Inlägg:
    369
    Mottagna gillanden:
    27

    MINA ENHETER

    Okej, det visade sig att min remoteView gör sig bäst som global, eftersom jag har sätter knapparna och värden i olika funktioner och det är viktigt att det är samma view.
    Däremot lade jag in att om den är null så görs en ny och knapparna initieras på nytt. Borde fungera.
    Samma med maträtterna. Är den tom hämtas den på nytt bara. Ska bli spännande att se framöver hur det artar sig. Har iaf LogCollector nu. Så jag kommer att se vad som krånglar om det krånglar.
     
    Last edited: 16 dec 2010