📜  2017 年 Android 应用开发:挑战与解决方案

📅  最后修改于: 2021-10-21 06:03:51             🧑  作者: Mango

由于 Android 操作系统接管了世界,很难想象没有移动应用程序开发的外包利基市场。通常,启动应用程序是一个非常耗时的过程。当公司决定制作企业应用程序时,此时此地就需要它。这就是为什么为 Android 构建混合或本机应用程序的机制通常需要使用第三方库来加快进程。让我们来看看当今移动应用程序开发人员经常使用的前四名,并回顾它们最有趣的功能和可能性。

牛油刀

Butter Knife 是一个小型库,用于减少项目中的代码行数并使其清晰。该库不会影响最终的 apk 文件大小。 Butter Knife 使用注解将来自 xml 文件的对象与来自应用程序逻辑的对象绑定。此外,它将某些对象的操作(例如,您单击对象或从列表中选择一个项目)与应用程序的整体逻辑绑定在一起。
如果要在项目中包含此库,请在模块的 gradle 中写入:

compile 'com.jakewharton:butterknife:8.4.0' annotationProcessor
 'com.jakewharton:butterknife-compiler:8.4.0'

完成此操作后,Butter Knife 库就可以使用了。在下面的示例中,您可以看到如何使 Button 项与 TextView 项绑定,执行一个简单的活动:当用户单击按钮时,文本会发生变化。

@BindView(R.id.text_view)
TextView textView;
@BindView(R.id.button)
Button button;
  
@Override
protected void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    ButterKnife.bind(this);
}
  
@OnClick(R.id.button)
public void onButtonClick()
{
    textView.setText("On Button Click");
}

就如此容易。您不需要为每个视图项使用 findViewById,也不需要实现 onClickListener 和相应的 onClick 方法。
您还可以使用注释绑定预定义的资源。在我们的示例中,它将如下所示:

@BindView(R.id.button)
按钮按钮;
@BindString(R。字符串的.text)
字符串文本;

@OnClick(R.id.button)
公共无效 onButtonClick()
{
textView.setText(text);
}

现在我们的资源文件包含字符串值文本。如果我们需要为这个值添加多个翻译——我们可以多次复制资源文件,我们希望在应用程序中有多种语言,并将每个文件中所需的信息翻译成外语。

你可以在任何地方使用 ButterKnife.bind 否则你会放置 findViewById 调用。这意味着您可以在片段、视图持有者等中使用它。

这只是这个库可以做的一小部分。如果您对这个的其他可能性感兴趣,只需访问官方 Butter Knife 网页并阅读更多内容。

滑行

Glide 是一个专注于平滑滚动的 Android 图像加载和缓存库。如果您需要在应用程序中显示图像、视频静止图像或动画 GIF – 这个库适合您。为了在您的项目中包含这个库,您需要在模块的 gradle 中编写一行代码:

compile 'com.github.bumptech.glide:glide:3.7.0'
  
    // When you need to show an image, type-in this one:
  
    Glide
        .with(this)
        .load("http://goo.gl/gEgYUd")
        .into(imageView);

其中“http://goo.gl/gEgYUd”——我们图片的 URL,imageView——图片加载和显示的窗口。
Glide 不仅提供显示我们图像的函数。它还可以产生内存缓存和各种各样的转换。由于移动应用程序开发人员经常使用该功能而非常流行的函数是创建圆形图像视图。对于此解决方案,您需要创建一个自定义类扩展 BitmapTransformation 并覆盖方法转换:

public class CircleTransform extends BitmapTransformation {
    public CircleTransform(Context context)
    {
        super(context);
    }
  
    @Override
    protected Bitmap transform(BitmapPool pool, Bitmap toTransform,
                               int outWidth, int outHeight)
    {
        return circleCrop(pool, toTransform);
    }
  
    private static Bitmap circleCrop(BitmapPool pool, Bitmap source)
    {
        if (source == null)
            return null;
  
        int size = Math.min(source.getWidth(), source.getHeight());
        int x = (source.getWidth() - size) / 2;
        int y = (source.getHeight() - size) / 2;
  
        Bitmap squared = Bitmap.createBitmap(source, x, y, size, size);
        Bitmap result = pool.get(size, size, Bitmap.Config.ARGB_8888);
        if (result == null)
            result = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
  
        Canvas canvas = new Canvas(result);
        Paint paint = new Paint();
        paint.setShader(new BitmapShader(squared,
                                         BitmapShader.TileMode.CLAMP,
                                         BitmapShader.TileMode.CLAMP));
        paint.setAntiAlias(true);
        float r = size / 2f;
        canvas.drawCircle(r, r, r, paint);
        return result;
    }
  
    @Override
    public String getId()
    {
        return getClass().getName();
    }
  
    // Then we will add a small change to the way our image will be shown:
  
    Glide
        .with(this)
        .load("http://goo.gl/gEgYUd")
        .transform(new CircleTransform(context))
        .into(imageView);

最后,我们的图像将被四舍五入。在 Glide 库的帮助下,我们可以以如此简单的方式舍入我们需要的所有图像。

描述我们上面提到的这个库的第二个有用的功能,即兑现,我们可以提到 Glide 将调整大小的图像兑现到内存或磁盘。例如,服务器上有一个分辨率为 1000*1000 像素的图像,而您的应用程序具有分辨率为 100*100 像素的图像视图。该库会将下载的图像大小调整为 100*100 像素,并以这种分辨率兑现。如果您的应用程序需要再次显示此图像,它会自动从现金中获取此图像并立即显示。图书馆不需要再次调整图像大小,因为它已经以现金形式调整了大小。
您可以在 Glide 官方网页上阅读有关该库有用功能的更多信息。

改造

我们无法想象没有连接到网络服务器或一些信息网络源的应用程序。 Retrofit 是适用于 Android 和Java的类型安全 HTTP 客户端。我们使用这个库来创建对服务器的 HTTP 请求。
您只需要一行代码即可将库包含到当前项目中:

compile 'com.squareup.retrofit2:retrofit:2.1.0'

让我们用一个简单的例子来测试一下,我们将从 GitHub 收到一个表情符号列表。
首先,我们将以下行添加到我们的 gradle 文件中:

编译 ‘com.squareup.retrofit2:converter-gson:2.1.0’

我们在我们的项目中添加了 gson 转换器,允许库自动将请求的结果转换为自定义对象。
然后我们创建 ServiceGenerator 类:

public class ServiceGenerator {
    public static final String API_BASE_URL = "https://api.github.com";
  
    private static OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
  
    private static Retrofit.Builder builder = new Retrofit.Builder()
                                  .baseUrl(API_BASE_URL)
                                  .addConverterFactory(GsonConverterFactory.create());
  
    public static S createService(Class serviceClass)
    {
        Retrofit retrofit = builder.client(httpClient.build()).build();
        return retrofit.create(serviceClass);
    }
}

此类定义了一种为给定类/接口创建基本 REST 适配器的方法。
以下代码定义了 RestClient 和一个请求表情符号列表的方法。

公共接口 RestClient {
@GET(“/表情符号”)
呼叫<
地图>
getEmojis();
}

然后我们改变我们的 onButtonClick 方法:

@OnClick(R.id.button)
public void onButtonClick()
{
    textView.setText(text);
  
    RestClient restClient = ServiceGenerator.createService(RestClient.class);
  
    Call& lt;
    Map& gt;
    request = restClient.getEmojis();
    request.enqueue(new Callback& lt; Map& gt; () {
        @Override
        public void onResponse(Call & lt; Map & gt; call,
                                                    Response & lt;
                               Map & gt; response)
        {
            if (response != null & amp; & response.body() != null) {
                imageAdapter.setData(new ArrayList(response.body().values()));
            }
        }
  
        @Override
        public void onFailure(Call & lt; Map & gt; call, Throwable t)
        {
            t.printStackTrace();
        }
    });
}
  
// ImageAdapter is an adapter for GridView.
// Listening of method getView is located below:
  
@Override
public View getView(int i, View view, ViewGroup viewGroup)
{
    ImageView imageView;
    if (view == null) {
        imageView = new ImageView(context);
        imageView.setLayoutParams(new GridView.LayoutParams(200, 200));
        imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
        imageView.setPadding(8, 8, 8, 8);
    }
    else {
        imageView = (ImageView)view;
    }
  
    Glide
        .with(context)
        .load(imageUrls.get(i))
        .into(imageView);
  
    return imageView;
}

现在,当我们点击 Click Me 按钮时,我们将看到下面的表情符号列表。

Retrofit 是一个强大的库,因为它包含许多有用的功能。您可以通过以下链接阅读有关此工具包的更详细评论。

领域

Android Realm 数据库使用简单,但功能强大,因为其核心是用 C++ 编写的,并在本机代码中编译。对于 Realm,我们的模型也是我们数据库的模式/表。这个库是专门为移动开发而制作的,这意味着它只针对移动设备,这就是开发人员如此欣赏它的原因。您可以在本文中阅读有关如何将此库包含到您的项目中的详细评论。

为了向您介绍该库的一些功能,我们将更新上述示例。为了更快和更安全的应用程序性能,总是有两个数据库:主数据库(本地)和远程数据库。在将所有对象存储在本地 DB 中的同时,我们需要将它们复制到远程 DB 中。为此,我们需要复制已有的表情符号列表,并自动化从一个数据库向另一个数据库添加和删除对象的整个过程,我们需要编写代码片段,如下所述。

我们需要为我们的数据库创建对象结构(模式):

public class Emoji extends RealmObject {
    private String imageUrl;
    public Emoji() {}
    public String getImageUrl()
    {
        return imageUrl;
    }
    public void setImageUrl(String imageUrl)
    {
        this.imageUrl = imageUrl;
    }
}

接下来,我们需要更改我们的 ImageAdapter 类。我们添加了两个方法,它们允许删除和添加项目到列表中。

public void addItem(String imageUrl)
{
    if (this.imageUrls == null)
        this.imageUrls = new ArrayList();
  
    if (this.imageUrls.contains(imageUrl))
        return;
  
    this.imageUrls.add(imageUrl);
    notifyDataSetChanged();
}
  
public void deleteItem(String imageUrl)
{
    if (imageUrl == null || this.imageUrls == null)
        return;
  
    this.imageUrls.remove(imageUrl);
    notifyDataSetChanged();
}

在 MainActivity 中,我们创建了三个方法,它们与 emojis 对象一起操作:

private List getEmojiUrls(final RealmResults emojis)
{
    List result = new ArrayList();
    if (emojis.size() & gt; 0) {
        for (Emoji item : emojis) {
            result.add(item.getImageUrl());
        }
    }
  
    return result;
}
  
private void addEmojiToList(String imageUrl)
{
    final RealmResults existEmojis = realm
                                         .where(Emoji.class)
                                         .equalTo("imageUrl", imageUrl)
                                         .findAll();
    if (existEmojis.size() & gt; 0)
        return;
  
    realm.beginTransaction();
    Emoji emoji = realm.createObject(Emoji.class);
    emoji.setImageUrl(imageUrl);
    realm.commitTransaction();
  
    imageAdapter2.addItem(imageUrl);
}
  
private void removeEmojiFromList(String imageUrl)
{
    imageAdapter2.deleteItem(imageUrl);
  
    realm.beginTransaction();
    final RealmResults existEmojis = realm
                                         .where(Emoji.class)
                                         .equalTo("imageUrl", imageUrl)
                                         .findAll();
    if (existEmojis.size() == 0)
        return;
    existEmojis.deleteAllFromRealm();
  
    realm.commitTransaction();
}

最后,我们更改我们的 onCreate 方法。在这里,我们初始化我们的数据库并在我们的列表项上设置一个点击监听器。

@Override
protected void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    ButterKnife.bind(this);
  
    Realm.init(this);
    realm = Realm.getDefaultInstance();
  
    imageAdapter1 = new ImageAdapter(this);
    imageAdapter2 = new ImageAdapter(this,
                                     getEmojiUrls(realm.where(Emoji.class).findAll()));
  
    gridView1.setAdapter(imageAdapter1);
    gridView2.setAdapter(imageAdapter2);
  
    gridView1.setOnItemClickListener(new AdapterView.OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView adapterView, View view, int i, long l)
        {
            addEmojiToList(imageAdapter1.getItem(i).toString());
        }
    });
  
    gridView2.setOnItemClickListener(new AdapterView.OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView adapterView, View view, int i, long l)
        {
            removeEmojiFromList(imageAdapter2.getItem(i).toString());
        }
    });
}

现在我们的应用程序如下图所示:

应用开发挑战

您可以通过关注我们在 GitHub 上的页面来查看该应用程序的现成版本。

结论

总体而言,公司在决定构建移动应用程序时每天都面临着许多挑战。

  • 首先,公司通常对他们的产品应该是什么样子没有一个清晰的形象,但他们确定他们想要创建一个移动应用程序。
  • 其次,缺乏设计师和开发人员。
  • 第三,缺乏项目经理来掌控整个过程。

实际上还有更多的挑战需要提及,但我们可以肯定地说,每个挑战都有其解决方案,现在 IT 公司在全栈的基础上提供它们。创意的 UI/UX 设计师可以弥补创意的缺乏,他们将生成创意并由分析师评估其在市场上的潜力。在远程移动开发人员的帮助下,可以轻松解决员工短缺问题。在这项研究的帮助下,我们现在确信,如果开发人员使用第三方库进行编码,Android 移动应用程序开发会更容易、更省时。当然,这里只提到了其中的几个,但肯定还有更多,也值得使用。