Dificultate: IntermediateLength: MediumLanguages:

Widgeturile pentru aplicatii ofera utilizatorilor dvs. acces usor la cele mai utilizate functii ale aplicatiei dvs., oferind in acelasi timp aplicatiei dvs. o prezenta pe ecranul de pornire al utilizatorului. Prin adaugarea unui widget la proiectul dvs., puteti oferi o experienta de utilizator mai buna, incurajand in acelasi timp utilizatorii sa ramana angajati cu aplicatia dvs., deoarece de fiecare data cand se uita la ecranul lor de pornire, va vor vedea widgetul, afisand unele dintre cele mai utile aplicatii ale dvs. continut interesant.

In aceasta serie in trei parti, construim un widget de aplicatii care are toate functionalitatile pe care le veti gasi in aproape  fiecare  widget de aplicatii Android. 

In prima postare, am creat un widget care preia si afiseaza date si efectueaza o actiune unica ca raspuns la evenimentele onClick. Apoi, in a doua postare, ne-am extins widgetul pentru a prelua si afisa date noi automat pe baza unui program  si  ca raspuns la interactiunea utilizatorului.

Ridicam locul unde ne-am lasat, asa ca daca nu aveti o copie a widgetului creat de noi in prima parte, il puteti descarca de pe GitHub.

Imbunatatirea widget-ului cu o activitate de configurare 

Although our widget functions out of the box, some widgets require initial setup—for example, a widget that displays the user’s messages will require their email address and password. You might also want to give your users the ability to customize the widget, such as changing its colour or even modifying its functionality, like how often the widget updates. 

If your widget is customisable or requires some setup, then you should include a configuration Activity, which will launch automatically as soon as the user places the widget on their homescreen.

Configuration Activities may also come in handy if you have lots of ideas about the information and features that you want to include in your widget. Rather than cramming all this content into a complex and potentially confusing layout, you could provide a configuration Activity where users pick and choose the content that matters to them. 

If you do include a configuration Activity, then don’t get carried away, as there’s a point where choice becomes too much choice. Setting up a widget shouldn’t feel difficult, so it’s recommended that you limit your widget to two or three configuration options. If you’re struggling not to exceed this limit, then consider whether all this choice is really necessary, or whether it’s just adding unnecessary complexity to the setup process.

To create a configuration Activity, you’ll need to follow the following steps.

1. Create the Activity Layout

This is exactly the same as building the layout for a regular Activity, so create a new layout resource file and add all your UI elements as normal. 

A configuration Activity is where the user performs initial setup, so once they’ve completed this Activity they’re unlikely to need it again. Since a widget’s layout is already smaller than a regular Activity layout, you shouldn’t waste valuable space by giving users a way to relaunch the configuration Activity directly from the widget layout.

Here I’m creating a simple configuration_activity.xml layout resource file containing a button that, when tapped, will create the application widget. 

<? xml version = “1.0” coding = “utf-8”?> https://schemas.android.com/apk/res/android “android: layout_width =” match_parent “android: layout_height =” match_parent “> <Buton android: id = “@ + id / setupWidget” android: layout_width = “fill_parent” android: layout_height = “wrap_content” android: layout_alignParentLeft = “adevarat” android: layout_marginTop = “175dp” android: text = “Creeaza widget” android: textColor = “# FFFFFF” /> <TextView android: layout_width = android “fill_parent”: layout_height = “wrap_content” android: layout_alignBottom = “@ + id / setupWidget” android: layout_alignParentLeft = “adevarat” android: layout_marginBottom = “67dp” android: text = “Optiunile de configurare merg aici!”/> </RelativeLayout>

2. Create Your Configuration Class 

Your configuration Activity must include the App Widget ID passed by the Intent that launched the configuration Activity. 

If you do include a configuration Activity, then note that the onUpdate() method won’t be called when the user creates a widget instance, as the ACTION_APPWIDGET_UPDATE broadcast isn’t sent when a configuration Activity is launched. It’s the configuration Activity’s responsibility to request this first update directly from the AppWidgetManager. The onUpdate() method will be called as normal for all subsequent updates.

Create a new Java class named configActivity and add the following: 

import Android.app.Activitate; import Android.appwidget.AppWidgetManager; import Android.os.Bundle; import Android.widget.Button; import android.content.Intent; import Android.view.View; import Android.view.View.OnClickListener; public class configActivity extinde Activitatea {@Override protected void onCreate (Bundle savedInstanceState) {super.onCreate (salvatInstanceState); setContentView (R.layout.configuration_activity); setResult (RESULT_CANCELED); Buton setupWidget = (Buton) findViewById (R.id.setupWidget); setupWidget.setOnClickListener (nou OnClickListener () {@Override public void onClick (View v) {handleSetupWidget ();}}); } private void handleSetupWidget () {showAppWidget (); } int appWidgetId; private void showAppWidget () {appWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID; // Obtineti ID-ul Widget-ului din Aplicatie care a lansat Activitatea // Intentia intentie = getIntent (); Bundle extras = intent.getExtras (); if (extras! = null) {appWidgetId = extras.getInt (AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID); // Daca intentia nu are un ID de widget, atunci suna la finalizare () // if (appWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID) {finish (); } // DO DO, Realizati configuratia si obtineti o instanta a AppWidgetManager // … … … // Creati intentia de returnare // Intent resultValue = new Intent (); // Treceti aplicatia initialaWidgetId // rezultatValue.putExtra (AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId); // Setati rezultatele din configuratia Activitate // setResult (RESULT_OK, rezultatValue); // Finalizati activitatea // terminati (); }}} Bundle extras = intent.getExtras (); if (extras! = null) {appWidgetId = extras.getInt (AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID); // Daca intentia nu are un ID de widget, atunci apelati finish () // if (appWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID) {finish (); } // DO DO, Realizati configuratia si obtineti o instanta a AppWidgetManager // … … … // Creati intentia de returnare // Intent resultValue = new Intent (); // Treceti aplicatia initialaWidgetId // rezultatValue.putExtra (AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId); // Setati rezultatele din configuratia Activitate // setResult (RESULT_OK, rezultatValue); // Finalizati activitatea // terminati (); }}} Bundle extras = intent.getExtras (); if (extras! = null) {appWidgetId = extras.getInt (AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID); // Daca intentia nu are un ID de widget, atunci apelati finish () // if (appWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID) {finish (); } // DO DO, Realizati configuratia si obtineti o instanta a AppWidgetManager // … … … // Creati intentia de returnare // Intent resultValue = new Intent (); // Treceti aplicatia originalaWidgetId // rezultatValue.putExtra (AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId); // Setati rezultatele din configuratia Activitate // setResult (RESULT_OK, rezultatValue); // Finalizati activitatea // terminati (); }}} AppWidgetManager.INVALID_APPWIDGET_ID); // Daca intentia nu are un ID de widget, atunci apelati finish () // if (appWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID) {finish (); } // DO DO, Realizati configuratia si obtineti o instanta a AppWidgetManager // … … … // Creati intentia de returnare // Intent resultValue = new Intent (); // Treceti aplicatia originalaWidgetId // rezultatValue.putExtra (AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId); // Setati rezultatele din configuratia Activitate // setResult (RESULT_OK, rezultatValue); // Finalizati activitatea // terminati (); }}} AppWidgetManager.INVALID_APPWIDGET_ID); // Daca intentia nu are un ID de widget, atunci apelati finish () // if (appWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID) {finish (); } // DO DO, Realizati configuratia si obtineti o instanta a AppWidgetManager // … … … // Creati intentia de returnare // Intent resultValue = new Intent (); // Treceti aplicatia originalaWidgetId // rezultatValue.putExtra (AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId); // Setati rezultatele din configuratia Activitate // setResult (RESULT_OK, rezultatValue); // Finalizati activitatea // terminati (); }}} Efectuati configuratia si obtineti o instanta a AppWidgetManager // … … … // Creati intentia de returnare // Rezultatul intentieiValue = new Intent (); // Treceti aplicatia originalaWidgetId // rezultatValue.putExtra (AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId); // Setati rezultatele din configuratia Activitate // setResult (RESULT_OK, rezultatValue); // Finalizati activitatea // terminati (); }}} Efectuati configuratia si obtineti o instanta a AppWidgetManager // … … … // Creati intentia de returnare // Rezultatul intentieiValue = new Intent (); // Treceti aplicatia originalaWidgetId // rezultatValue.putExtra (AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId); // Setati rezultatele din configuratia Activitate // setResult (RESULT_OK, rezultatValue); // Finalizati activitatea // terminati (); }}}

3. Declarati activitatea de configurare din manifestul proiectului dvs.

Cand declarati activitatea dvs.

filme porno gay http://christianpeyton.com/__media__/js/netsoltrademark.php?d=adult66.net/
comedii porno http://iprepcoop.com/__media__/js/netsoltrademark.php?d=adult66.net/
filme porno asa akira http://slickwrap.info/__media__/js/netsoltrademark.php?d=adult66.net/
porno vide http://lossmitigation.biz/__media__/js/netsoltrademark.php?d=adult66.net/filme-porno/amatori
filme porno scoala http://upsavings.com/__media__/js/netsoltrademark.php?d=adult66.net/filme-porno/anal
gimnaste porno http://xe-services.net/__media__/js/netsoltrademark.php?d=adult66.net/filme-porno/asiatice
filme porno hard core http://pierrepeladeau.biz/__media__/js/netsoltrademark.php?d=adult66.net/filme-porno/beeg
filme porno anii 80 http://mjpetersonmarketing.com/__media__/js/netsoltrademark.php?d=adult66.net/filme-porno/blonde
porno tata si fica http://accordingtomom.com/__media__/js/netsoltrademark.php?d=adult66.net/filme-porno/brazzers
ingyen porno filmek http://josephinsurance.com/__media__/js/netsoltrademark.php?d=adult66.net/filme-porno/brunete
zoofilia porno http://guiltyornot.com/__media__/js/netsoltrademark.php?d=adult66.net/filme-porno/chaturbate
filme porno cu mama si fiul http://madeforbusiness.org/__media__/js/netsoltrademark.php?d=adult66.net/fututa-in-pozitii-ciudate-dupa-care-e-spermata-pe-fata
filme online traduse porno http://fteen.net/__media__/js/netsoltrademark.php?d=adult66.net/o-blonda-cu-silicoane-si-corp-senzual-e-fututa-rau-ca-in-filmele-porno
jennifer lopez porno http://collincountydivorce.net/__media__/js/netsoltrademark.php?d=adult66.net/doi-amatori-isi-filmeaza-partida-de-sex-apoi-au-orgasm-intens
nagyik porno http://kahite.org/__media__/js/netsoltrademark.php?d=adult66.net/minora-surprinsa-in-timp-ce-se-masturbeaza-pe-terasa-din-fata-casei
porno free tube http://nchina.com/__media__/js/netsoltrademark.php?d=adult66.net/scolarita-fututa-tare-pe-la-spate-de-fratele-mai-mare-in-timp-ce-isi-facea-temele
filme porno xnx http://valuestorecatalog.com/__media__/js/netsoltrademark.php?d=adult66.net/tanara-virgina-face-prietenului-sex-oral-pentru-prima-oara
filme porno cu tatoase http://nissan-v-up.com/__media__/js/netsoltrademark.php?d=adult66.net/sex-fierbinte-pe-podeaua-din-sufragerie-cu-un-cuplu-de-amatori-excitati
porno x http://mbsantafe.com/__media__/js/netsoltrademark.php?d=adult66.net/cea-mai-sexy-blonda-e-fututa-salbatic-de-un-animal-de-barbat
filme porno cu surori http://outdooridol.com/__media__/js/netsoltrademark.php?d=adult66.net/pustoaica-in-lenjerie-sexy-se-masturbeaza-intens-in-dormitorul-ei

de configurare in Manifest, trebuie sa specificati ca accepta actiunea ACTION_APPWIDGET_CONFIGURE: 

<activitate android: name = “. configActivity”> <intent-filter> <action android: name = “android.appwidget.action.APPWIDGET_CONFIGURE” /> </intent-filter> </activity>

4. Declarati activitatea de configurare din fisierul dvs. AppWidgetProviderInfo 

Intrucat Activitatea de configurare este facuta referinta in afara domeniului de aplicare al pachetului, trebuie sa o declarati folosind spatiul de nume complet calificat: 

<? xml version = “1.0” coding = “utf-8”?> http://schemas.android.com/apk/res/android “android: initialKeyguardLayout =” @ layout / new_app_widget “android: initialLayout =” @ layout / new_app_widget “android: minHeight =” 40dp “android: minWidth =” 40dp “android: previewImage =” @ drawable / example_appwidget_preview “android: resizeMode =” orizontal | vertical “android: updatePeriodMillis =” 1800000 “android: widgetCategory =” home_screen ” // Adaugati urmatoarea linie // android: configure = “com.jessicathornsby.widget.configActivity”> </appwidget-provider>

Now, whenever you create a new instance of this widget, the configuration Activity will launch, and you’ll need to complete all the options in this Activity before your widget is created. In this instance, that simply means giving the Create Widget button a tap. 

Remember, you can download the finished widget, complete with configuration Activity, from GitHub. 

Application Widget Best Practices

Throughout this series, we’ve been building an application widget that demonstrates all the core features you’ll find in pretty much every Android application widget. By this point, you know how to create a widget that retrieves and displays data, reacts to onClick events,  updates with new information based on a schedule and in response to user interaction, and has a custom preview image. 

These may be the fundamental building blocks of Android application widgets, but creating something that just works is never enough—you also need to ensure your widget is providing a good user experience, by following best practices. 

Perform Time-Consuming Operations Off the Main Thread

Widgets have the same runtime restrictions as normal broadcast receivers, so they have the potential to block Android’s all-important main UI thread. 

Android has a single thread where all your application code runs by default, and since Android can only process one task at a time, it’s easy to block this important thread. Perform any kind of long-running or intensive operation on the main thread, and your app’s user interface will be unresponsive until the operation completes. In the worst-case scenario, this can result in Android’s Application Not Responding (ANR) error and the application crashes. 

If your widget does need to perform any time-consuming or labour-intensive tasks, then you should use a service rather than the main thread. You can create the service as normal and then start it in your AppWidgetProvider. For example, here we’re using a service to update our widget:

@Override public void onUpdate (Context context, AppWidgetManager appWidgetManager, int [] appWidgetIds) {context.startService (noua intentie (context, AppWidgetService.class)); }}

Creati un aspect flexibil

Crearea unui layout care se poate adapta la o serie de configuratii de ecran este una dintre cele mai importante reguli de dezvoltare pentru Android si este o regula care se extinde si la widget-uri. La fel ca activitatile obisnuite, aspectul widgetului trebuie sa fie suficient de flexibil pentru a fi afisat si functionat corect, indiferent de configuratia ecranului, dar exista cateva motive suplimentare pentru care aspectele de widget trebuie sa fie cat mai flexibile. 

In primul rand, daca widget-ul dvs. poate fi redimensionat, atunci utilizatorul poate creste si micsora manual dimensiunea widget-ului dvs., lucru care nu trebuie sa va faceti griji cu activitatile traditionale.

Secondly, there’s no guarantee that your widget’s minWidth and minHeight measurements will perfectly align with a particular device’s homescreen grid. When a widget isn’t a perfect fit, the Android operating system will stretch that widget horizontally and/or vertically to occupy the minimum number of cells required to satisfy the widget’s minWidth and minHeight constraints. While this shouldn’t be a significant increase, it’s still worth noting that right from the start your widget may be occupying more space than you’d anticipated. 

Creating a flexible widget layout follows the same best practices as designing a flexible Activity layout. There’s already plenty of information available on this topic, but here are some of the most important points to bear in mind when creating your widget layouts: 

  • Avoid absolute units of measure, such as defining a button in pixels. Due to varying screen densities, 50 pixels doesn’t translate to the same physical size on every device. So a 50px button is going to appear larger on low-density screens and smaller on high-density screens. You should always specify your layout’s dimensions in density-independent units (dpi) and use flexible elements such as wrap_content and match_parent.
  • Provide alternate resources that are optimised for different screen densities. You can also provide layouts that are optimised for different screen sizes, using configuration qualifiers such as smallestWidth (sw<N>dp). Don’t forget to provide a default version of every resource, so your app has something to fall back on if it ever encounters a screen with characteristics that it doesn’t have a specific resource for. You should design these default resources for normal, medium-density screens. 
  • Test your widget across as many screens as possible, using the Android emulator. When creating an AVD, you can specify an exact screen size and resolution, using the Screen controls that appear in the Configure this hardware profile menu. Don’t forget to test how your widget handles being resized across all these different screens!

Don’t Wake the Device

Updating a widget requires battery power, and the Android operating system has no qualms about waking a sleeping device in order to perform an update, which amplifies the impact your widget has on the device’s battery. 

If the user realises that your widget is draining their battery, then at the very least they’re going to delete that widget from their homescreen. In the worst-case scenario, they may even delete your app entirely. 

You should always aim to update your widget as infrequently as possible while still displaying timely and relevant information. However, some widgets may have a legitimate reason for requiring frequent updates—for example, if the widget includes highly time-sensitive content. 

In this scenario, you can reduce the impact these frequent updates have on battery life, by performing updates based on an alarm that won’t wake a sleeping device. If this alarm goes off while the device is asleep, then the update won’t be delivered until the next time the device wakes up.

To update based on an alarm, you need to use the AlarmManager to set an alarm with an Intent that your AppWidgetProvider will receive, and then set the alarm type to either ELAPSED_REALTIME or RTC, as these alarm types won’t wake a sleeping device. For example:

@Override public void onUpdate (Context context, AppWidgetManager appWidgetManager, int [] appWidgetIds) {final AlarmManager manager = (AlarmManager) context.getSystemService (Context.ALARM_SERVICE); final Intent i = new Intent (context, WidgetService.class); if (service == null) {service = PendantIntent.getService (context, 0, i, PendantIntent.FLAG_CANCEL_CURRENT); } manager.setRepeating (AlarmManager.ELAPSED_REALTIME, // Setati-va intervalul de actualizare. 60000 milisecunde (60 secunde) este intervalul minim pe care il puteti utiliza // SystemClock.elapsedRealtime (), 60000, service); }}

If you do use an alarm, then make sure you open your project’s AppWidgetProviderInfo file (res/xml/new_app_widget_info.xml) and set the updatePeriodMillis to zero (“0”). If you forget this step, the updatePeriodMillis value will override the AlarmManager and your widget will still wake the device every single time it requires an update. 

Conclusion

In this three-part series, we’ve created an Android application widget that demonstrates how to implement all the most common features found in app widgets. 

If you’ve been following along since the beginning, then by this point you’ll have built a widget that updates automatically and in response to user input, and that’s capable of reacting to onClick events. Finally, we looked at some best practices for ensuring your widget provides a good user experience, and discussed how to enhance your widget with a configuration Activity.

Thanks for reading, and while you’re here, check out some of our other great posts on Android app development!