为您的Android应用程序编码小部件:添加配置活动

应用程序小部件可让您的用户轻松访问应用程序最常用的功能,同时使应用程序出现在用户的主屏幕上。 通过将小部件添加到您的项目中,您可以提供更好的用户体验,同时鼓励用户继续使用您的应用程序,因为每当他们瞥一眼主屏幕时,就会看到您的小部件,显示您的应用程序中最有用和最有用的部分。有趣的内容。

在这个由三部分组成的系列文章中,我们将构建一个应用程序小部件,它具有几乎在每个 Android应用程序小部件中都可以找到的所有功能。

在第一篇文章中, 我们创建了一个小部件,该小部件可检索和显示数据并响应onClick事件执行唯一的操作。 然后在第二篇文章中, 我们扩展了小部件,以根据计划 响应用户交互 自动检索和显示新数据

我们从上次停下来的地方接机,因此,如果您没有我们在第一部分中创建的小部件的副本,则可以从GitHub下载它

通过配置活动增强小部件

尽管我们的窗口小部件具有开箱即用的功能,但是某些窗口小部件需要进行初始设置-例如,显示用户消息的窗口小部件将需要其电子邮件地址和密码。 您可能还希望使用户能够自定义窗口小部件,例如更改其颜色甚至修改其功能(例如窗口小部件更新的频率)。

如果您的窗口小部件是可自定义的或需要进行一些设置,则应包括一个配置Activity ,只要用户将窗口小部件放在其主屏幕上,该配置就会自动启动。

如果您对要包含在小部件中的信息和功能有很多想法,则配置活动也可能会派上用场。 您可以提供一个配置“活动”,用户在其中选择并选择对他们而言重要的内容,而不是将所有这些内容填充到一个复杂且可能引起混乱的布局中。

如果您确实包含配置Activity,那么不要气carried,因为在某些情况下选择会变成太多选择 。 设置小部件并不难,因此建议您将小部件限制为两个或三个配置选项。 如果您在努力不超过此限制,那么请考虑是否所有这些选择确实必要,或者是否只是在设置过程中增加了不必要的复杂性。

要创建配置活动,您需要执行以下步骤。

1.创建活动布局

这与构建常规Activity的布局完全相同,因此请创建一个新的布局资源文件,并照常添加所有UI元素。

配置活动是用户执行初始设置的地方,因此一旦完成此活动,他们就不太可能再次需要它。 由于小部件的布局已经比常规的“活动”布局小,因此您不应通过给用户一种直接从小部件布局重新启动配置“活动”的方式浪费宝贵的空间。

在这里,我正在创建一个简单的configuration_activity.xml布局资源文件,其中包含一个按钮,点击该按钮将创建应用程序小部件。

<?xml version="1.0" encoding="utf-8"?>
https://schemas.android.com/apk/res/android"
   android:layout_width="match_parent"
   android:layout_height="match_parent" >

   <Button
       android:id="@+id/setupWidget"
       android:layout_width="fill_parent"
       android:layout_height="wrap_content"
       android:layout_alignParentLeft="true"
       android:layout_marginTop="175dp"
       android:text="Create widget"
       android:textColor="#FFFFFF" />

   <TextView
       android:layout_width="fill_parent"
       android:layout_height="wrap_content"
       android:layout_alignBottom="@+id/setupWidget"
       android:layout_alignParentLeft="true"
       android:layout_marginBottom="67dp"
       android:text="Configuration options go here!" />
       
</RelativeLayout>

2.创建您的配置类

您的配置活动必须包含启动配置活动的Intent传递的应用程序小部件ID。

如果确实包含配置活动,则请注意,当用户创建窗口小部件实例时,不会调用onUpdate()方法,因为启动配置活动时不会发送ACTION_APPWIDGET_UPDATE广播。 配置活动的责任是直接从AppWidgetManager请求此第一次更新。 对于所有后续更新,将正常调用onUpdate()方法。

创建一个名为configActivity的新Java类,并添加以下内容:

import android.app.Activity;
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 extends Activity {

   @Override
   protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.configuration_activity);
       setResult(RESULT_CANCELED);
       Button setupWidget = (Button) findViewById(R.id.setupWidget);
       setupWidget.setOnClickListener(new OnClickListener() {

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

   }

   private void handleSetupWidget() {
       showAppWidget();

   }

   int appWidgetId;
   private void showAppWidget() {
       appWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID;

       //Retrieve the App Widget ID from the Intent that launched the Activity//

       Intent intent = getIntent();
       Bundle extras = intent.getExtras();
       if (extras != null) {
           appWidgetId = extras.getInt(
                   AppWidgetManager.EXTRA_APPWIDGET_ID,
                   AppWidgetManager.INVALID_APPWIDGET_ID);

           //If the intent doesn’t have a widget ID, then call finish()//

           if (appWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID) {
               finish();
           }

           //TO DO, Perform the configuration and get an instance of the AppWidgetManager//
...
...
...

//Create the return intent//

           Intent resultValue = new Intent();

//Pass the original appWidgetId//

           resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);

//Set the results from the configuration Activity//

           setResult(RESULT_OK, resultValue);

//Finish the Activity//

           finish();
       }
   }
}

3.在项目清单中声明配置活动

清单中声明配置活动时,需要指定它接受ACTION_APPWIDGET_CONFIGURE操作:

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

4.在您的AppWidgetProviderInfo文件中声明配置活动

由于配置活动是在包范围之外引用的,因此您需要使用完全限定的名称空间对其进行声明:

<?xml version="1.0" encoding="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="horizontal|vertical"
   android:updatePeriodMillis="1800000"
   android:widgetCategory="home_screen"

//Add the following line//

   android:configure="com.jessicathornsby.widget.configActivity">
</appwidget-provider>

现在,无论何时创建此窗口小部件的新实例,都会启动配置活动,并且需要在创建窗口小部件之前完成此活动中的所有选项。 在这种情况下,这仅意味着轻按“ 创建小部件”按钮。

Test the application widget configuration Activity

请记住,您可以从GitHub 下载完成的窗口小部件 ,其中包含配置活动。

应用程序小部件最佳实践

在整个系列中,我们一直在构建一个应用程序小部件,以演示几乎在每个Android应用程序小部件中都可以找到的所有核心功能。 至此,您知道如何创建一个小部件,该小部件可检索和显示数据,对onClick事件作出反应,根据计划并响应用户交互使用新信息进行更新,并具有自定义预览图像。

这些可能是Android应用程序小部件的基本构建块,但是创建仅能正常工作的东西是远远不够的-您还需要通过遵循最佳实践来确保小部件能够提供良好的用户体验。

在主线程上执行耗时的操作

小部件具有与普通广播接收器相同的运行时限制,因此它们有可能阻止Android的所有重要主UI线程。

Android具有一个默认情况下所有应用程序代码都在其中运行的线程,并且由于Android一次只能处理一个任务,因此很容易阻止此重要线程。 在主线程上执行任何长时间运行或密集的操作,在操作完成之前,您应用的用户界面将无响应。 在最坏的情况下,这可能会导致Android的Application Not RespondingANR )错误并导致应用程序崩溃。

如果窗口小部件确实需要执行任何耗时或劳动密集的任务,则应使用服务而不是主线程。 您可以正常创建服务,然后在AppWidgetProvider启动它。 例如,在这里我们使用服务来更新小部件:

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

创建灵活的布局

创建可适应各种屏幕配置的布局是针对Android开发的最重要规则之一,并且该规则还扩展到小部件。 就像常规活动一样,小部件的布局需要足够灵活以能够正确显示和正常工作,而与屏幕配置无关,但是还有其他一些原因使得小部件布局需要尽可能灵活。

首先,如果您的窗口小部件是可调整大小的,则用户可以手动增大和减小窗口小部件的大小,这是传统活动无需担心的事情。

其次,不能保证小部件的minWidthminHeight测量值将与特定设备的主屏幕网格完美对齐。 当窗口小部件不合适时,Android操作系统将水平和/或垂直拉伸该窗口小部件,以占用满足窗口小部件的minWidthminHeight约束所需的最小单元格数。 尽管这并不是一个明显的增长,但仍然值得一提的是,从一开始,您的小部件可能会占据比预期更多的空间。

创建灵活的小部件布局遵循与设计灵活的Activity布局相同的最佳实践。 关于此主题的信息已经很多,但是在创建窗口小部件布局时,需要牢记一些最重要的要点:

  • 避免使用绝对的度量单位,例如以像素为单位定义按钮。 由于屏幕密度不同,因此在每个设备上50像素的像素都不会转换为相同的物理尺寸。 因此,一个50px按钮将在低密度屏幕上显示较大,而在高密度屏幕上显示较小。 您应该始终以与密度无关的单位(dpi)指定布局的尺寸,并使用诸如wrap_contentmatch_parent类的灵活元素。
  • 提供针对不同屏幕密度优化的备用资源。 您还可以使用配置限定符(例如smallestWidthsw<N>dp ))提供针对不同屏幕尺寸进行了优化的布局。 别忘了提供每种资源的默认版本,因此,如果您的应用遇到遇到没有针对特定资源的特征的屏幕,那么您的应用就会有所依赖。 您应该为普通中等密度的屏幕设计这些默认资源。
  • 使用Android模拟器在尽可能多的屏幕上测试您的小部件。 创建AVD时,可以使用“ 配置此硬件配置文件”菜单中显示的“ 屏幕”控件来指定确切的屏幕尺寸和分辨率。 不要忘记测试如何在所有这些不同的屏幕上调整窗口小部件的大小!
使用模拟器在各种AVD上测试您的小部件

不要唤醒设备

更新小部件需要电池电量,并且Android操作系统对于唤醒睡眠设备以执行更新没有任何限制,这会放大小部件对设备电池的影响。

如果用户意识到您的小部件正在消耗电池电量,那么至少他们将要从其主屏幕删除该小部件。 在最坏的情况下,他们甚至可能会完全删除您的应用程序。

您应该始终以尽可能少地更新小部件为目标,同时仍显示及时且相关的信息。 但是,某些窗口小部件可能有需要频繁更新的正当理由-例如,如果窗口小部件包含高度时间敏感的内容。

在这种情况下,您可以根据不会唤醒睡眠设备的警报执行更新,从而减少这些频繁更新对电池寿命的影响。 如果在设备进入睡眠状态时此警报响起,则只有在设备下次唤醒时,更新才会传递。

要基于警报进行更新,您需要使用AlarmManager来设置AppWidgetProvider将接收到的Intent警报,然后将警报类型设置为ELAPSED_REALTIMERTC ,因为这些警报类型不会唤醒睡眠设备。 例如:

@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 = PendingIntent.getService(context, 0, i, PendingIntent.FLAG_CANCEL_CURRENT);
        }

        manager.setRepeating(AlarmManager.ELAPSED_REALTIME, 

//Set your update interval. 60000 milliseconds (60 seconds) is the minimum interval you can use//

SystemClock.elapsedRealtime(), 60000, service);

    }
}

如果确实使用了警报,请确保打开项目的AppWidgetProviderInfo文件( res / xml / new_app_widget_info.xml ),并将updatePeriodMillis设置为零(“ 0 ”)。 如果您忘记了此步骤,则updatePeriodMillis值将覆盖AlarmManager并且小部件仍将在每次需要更新时唤醒设备。

结论

在这个由三部分组成的系列文章中,我们创建了一个Android应用程序小部件,该小部件演示了如何实现应用程序小部件中所有最常见的功能。

如果您从一开始就一直遵循,那么到现在为止,您将构建一个可自动更新并响应用户输入的小部件,并且该小部件能够对onClick事件做出反应。 最后,我们研究了确保您的小部件提供良好的用户体验的一些最佳做法,并讨论了如何通过配置Activity来增强您的小部件。

翻译自: https://code.tutsplus.com/tutorials/code-a-widget-for-your-android-app-updating-the-widget-continued--cms-30669

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值