Kanye West和软件开发有什么共同点……

Heard ’Em Say something about a REST API?

听过'Em对REST API说些什么?

That’s right! There’s a REST API called “kanye.rest” (https://kanye.rest/) that provides randomised quotes from Kanye West. In this story, you will learn how to interact with the API and how to integrate it into your Android apps!

那就对了! 有一个称为“ kanye.rest”( https://kanye.rest/ )的REST API,它提供来自Kanye West的随机报价。 在这个故事中,您将学习如何与API交互以及如何将其集成到Android应用中!

Image for post
(Left photo) Photo by Chase Fade on Unsplash (Right photo) Photo by Shahadat Rahman on Unsplash
(左图) Chase FadeUnsplash上的 照片 (右图) Shahadat RahmanUnsplash上的 照片

什么是REST API? (What is a REST API?)

A REST API is a Representational State Transfer Application Programming Interface… are you still reading this story? Awesome… I appreciate that was a lengthy abbreviation!

REST API是代表性状态转移应用程序编程接口……您还在阅读这个故事吗? 太棒了...我很欣赏那是一个冗长的缩写!

REST is a software architecture that defines rules in order for systems to communicate over the web.

REST是一种软件体系结构,它定义规则以使系统通过Web进行通信。

An API is a way for multiple software systems to communicate. For example, if you wanted to integrate Facebook features into your app (e.g. allowing the user of your app to login with their Facebook account), you would interact with the Facebook API to send/receive data to/from your app.

API是多个软件系统进行通信的一种方式。 例如,如果您想将Facebook功能集成到您的应用程序中(例如,允许应用程序的用户使用其Facebook帐户登录),则可以与Facebook API进行交互以向/从您的应用程序发送/接收数据。

使用Kanye REST API (Using the Kanye REST API)

The Kanye REST API that I used was https://api.kayne.rest

我使用的Kanye REST API是https://api.kayne.rest

More info can be found at: https://kanye.rest/

可以在以下位置找到更多信息: https : //kanye.rest/

设置项目(作为Android应用) (Setting up the Project (as an Android app))

This project walk through will be using the Android platform. You can communicate with this API via other technologies as well.

该项目的演练将使用Android平台 。 您也可以通过其他技术与此API通信。

I called my project “KayneRestAPI”, set the language to “Java” and the Minimum SDK to “API 23”.

我将我的项目命名为“ KayneRestAPI”,将语言设置为“ Java”,将最低SDK设置为“ API 23”。

We also need to allow INTERNET permissions in the AndroidManifest.xml file. If you do not include this, your app will simply crash when it runs.

我们还需要在AndroidManifest.xml文件中允许INTERNET权限。 如果不包括此选项,则您的应用程序将在运行时崩溃。

Include the following code in AndroidManifest.xml to enable this (within the “manifest ” tags/angled brackets but before the “application” opening tag/angled bracket:

在AndroidManifest.xml中包含以下代码以启用此功能(在“ 清单 ”标签/尖括号中,但在“ 应用程序 ”打开标签/尖括号之前:

<uses-permission android:name="android.permission.INTERNET"></uses-permission>

实施应用程序的UI /前端 (Implementing the UI/front-end of the app)

Go to “activity_main.xml” which is located at res → layout. If you cannot find this on the left side on Android Studio, select “Android” if you have “Project” or something else selected at the top left of Android Studio.

转到位于res→布局的“ activity_main.xml”。 如果您无法在Android Studio的左侧找到此图标,请选择“ Android”(如果您在Android Studio的左上方选择了“项目”或其他选项)。

Add the following code to “activity_main.xml” to setup the UI:

将以下代码添加到“ activity_main.xml”以设置UI:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">


    <TextView
        android:id="@+id/kayneSaysTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Kayne Says:"
        android:textSize="24dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />


    <TextView
        android:id="@+id/kayneQuoteTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="..."
        android:textSize="25dp"
        android:textAlignment="center"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/kayneSaysTextView" />
</androidx.constraintlayout.widget.ConstraintLayout>

I will explain this code and not let this story be a copy & paste exercise…

我将解释此代码,而不是让这个故事成为复制粘贴活动……

the “<androidx.constraintlayout…>” uses the constraint layout (more info here: https://developer.android.com/reference/androidx/constraintlayout/widget/ConstraintLayout).

“ <androidx.constraintlayout…>”使用约束布局 (更多信息在这里: https : //developer.android.com/reference/androidx/constraintlayout/widget/ConstraintLayout )。

This layout achieves the same and more than the Relative Layout so is a good choice… especially for a very simplified UI in this app.

此布局与“相对布局”实现的效果相同且更多,因此是一个不错的选择……尤其是对于此应用程序中非常简化的UI。

The Constraint Layout adds constraints to different views based upon other views, e.g. including constraints of the first TextView with the ID: “kayneSaysTextView” relative to it’s parent, i.e. the entire screen/view. This is shown below by the directions of the 3 arrows/constraints:

约束布局基于其他视图向不同的视图添加约束,例如,包括相对于其父对象(即整个屏幕/视图)的ID为“ kayneSaysTextView ”的第一个TextView的约束。 这通过3个箭头/约束的方向在下面显示:

Image for post

The “kayneSaysTextView” simply shows the text “Kayne Says:”. The content of this view is static so won’t change at any point when the app runs.

“ kayneSaysTextView”仅显示文本“ Kayne Says:”。 该视图的内容是静态的,因此在应用运行时不会随时更改。

The last TextView: “kayneQuoteTextView” shows the dynamic (changes each time the app is restarted) displays the JSON data fetched from the API.

最后一个TextView :“ kayneQuoteTextView”显示动态(每次重新启动应用程序时都会更改)显示从API提取的JSON数据。

Just to clarify how the API works, the data or Kayne quote provided by the API returns a randomised value/quote each time an API call is made.

只是为了阐明API的工作原理 ,每次进行API调用时,API提供的数据或Kayne引用都会返回随机值/引用。

实施应用程序的逻辑/后端 (Implementing the logic/backend of the app)

Navigate to the “MainActivity” java file which is located at java → com → {your_name} → {project_name} folder

导航到位于Java→com→{您的名字}→{project_name}文件夹中的“ MainActivity” java文件。

Include the following code in the MainActivity class:

在MainActivity类中包含以下代码:

import androidx.appcompat.app.AppCompatActivity;


import android.os.Bundle;
import android.widget.TextView;


public class MainActivity extends AppCompatActivity implements FetchDataTask.OnTaskFinishedListener {


    final String URL = "https://api.kanye.rest";
    String kayneQuote;


    TextView kayneSaysTextView, kayneQuoteTextView;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


        kayneSaysTextView = findViewById(R.id.kayneSaysTextView);
        kayneQuoteTextView = findViewById(R.id.kayneQuoteTextView);


        FetchDataTask fetchDataTask = new FetchDataTask(this);
        fetchDataTask.execute(URL);
    }


    @Override
    public void OnTaskFinished(String kayneQuote) {
        if (kayneQuote != null) {
            this.kayneQuote = kayneQuote;
            kayneQuoteTextView.setText(this.kayneQuote);
        }
    }
}

Code explanation

代码说明

The imports will make sure there are no errors with the TextView, etc code.

导入将确保TextView等代码没有错误。

“implements” is included as we want to implement the interface defined in the FetchDataTask class in order to define the behaviour/code to run when the fetching API data task finishes. Don’t worry, we will create this class in a minute.

包含“实现”是因为我们要实现FetchDataTask类中定义的接口 ,以便定义在获取API数据任务完成时要运行的行为/代码。 不用担心,我们将在一分钟内创建此类。

The “URL” variable simply holds the URL/API endpoint that we want to send a GET request to. The “kayneQuote” variable stores the kayne quote value returned from the API. The 2 TextViews represent the TextViews defined in the UI section. These variables are then linked to the backend of the app in the “onCreate()” method on the findViewById line.

“ URL”变量仅包含我们要向其发送GET请求的URL / API端点。 “ kayneQuote”变量存储从API返回的kayne报价值。 2个TextView表示在UI部分中定义的TextView。 然后,这些变量在findViewById行的“ onCreate()”方法中链接到应用程序的后端。

On line 21, an instance of the FetchDataTask class is created, passing in the MainActivity as the reference for the onTaskFinishedListener variable in the FetchDataTask. Line 22 then starts the asynchronous request via calling execute(URL), where “URL” is the variable, therefore passes the API endpoint URL to the method.

在第21行,创建了FetchDataTask类的实例,并传入MainActivity作为FetchDataTask中onTaskFinishedListener变量的引用 。 然后,第22行通过调用execute(URL)来启动异步请求,其中“ URL”是变量,因此将API端点URL传递给该方法。

The code explanation for this class is nearly done… :)

该类的代码解释几乎完成了... :)

“onTaskFinished” implements the method defined in the interface (which is located in the FetchDataTask class). This method checks if the value of the “kayneQuote” parameter is null. If not, the parameter is assigned to the local “kayneQuote” variable (hence this.kayneQuote). The TextView is then updated to show this quote provided from the API.

“ onTaskFinished” 实现接口 (位于FetchDataTask类中)中定义的方法。 此方法检查“ kayneQuote”参数的值是否为空。 如果不是,则将参数分配给本地“ kayneQuote”变量(因此this.kayneQuote)。 然后更新TextView以显示API提供的报价。

Now, this is where we create the FetchDataTask class. Create a new class called… yep FetchDataTask. You can do this by right clicking on the {project_name} on the left → New → Java Class.

现在,我们在这里创建FetchDataTask类。 创建一个名为… yep FetchDataTask的新类。 您可以通过右键单击左侧的{project_name}→新建→Java类来实现。

Once you have created the class, the boilerplate code (basic necessary code to represent the newly created class) will be shown.

创建类后,将显示样板代码(代表新创建的类的基本必要代码)。

Below is the code I have written for the FetchDataTask:

以下是我为FetchDataTask编写的代码:

import android.os.AsyncTask;


import org.json.JSONObject;


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;


/**
 * This class handles asynchronous calls to the API endpoint, in addition for parsing and deserialising
 * the returned JSON data into a Java Object, in this specific case into a String called kayneQuote.
 *
 * @author Andreas Ward
 */
public class FetchDataTask extends AsyncTask<String, String, String> {
    private String jsonData;
    private OnTaskFinishedListener onTaskFinishedListener;
    private String kayneQuote;


    public FetchDataTask(OnTaskFinishedListener onTaskFinishedListener)
    {
        this.onTaskFinishedListener = onTaskFinishedListener;
    }


    @Override
    protected void onPreExecute() { //method for preparing any data before call to API endpoint.
        super.onPreExecute();
    }
    @Override
    protected String doInBackground(String... strings) { //method executed on background thread.


        getJsonData(strings); //gets the returned JSON data
        parseJsonToKayneQuote(); //parses the returned JSON data and stored in a String called kayneQuote


        return jsonData;
    }
    @Override
    protected void onPostExecute(String returnedData) {
        super.onPostExecute(returnedData);


        if (returnedData != null)
        {
            onTaskFinishedListener.OnTaskFinished(kayneQuote);
        }
    }


    public void getJsonData(String... strings)
    {
        try {
            URL url = new URL(strings[0]);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setDoInput(true); //signifies to read data from the URL connection
            conn.setRequestMethod("GET");
            conn.connect();


            int responseCode = conn.getResponseCode();


            if (responseCode != 200) { //if the responseCode is not 'OK'
                throw new RuntimeException("HttpResponseCode: " + responseCode);
            } else {
                InputStream inputStream = conn.getInputStream();


                //reader defined to read text from the inputStream
                BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));


                StringBuffer buffer = new StringBuffer(); //thread safe and mutable (compared with StringBuilder)
                String line = "";


                while ((line = reader.readLine()) != null) { //reads each line whilst there's a value
                    buffer.append(line + "\n"); //appends the data from the current line to the buffer, adding a new line
                }


                jsonData = buffer.toString();
            }
        } catch(IOException e){
            e.printStackTrace();
            jsonData = e.getMessage();
        }
    }


    public void parseJsonToKayneQuote()
    {
        if (jsonData != null) {
            try {
                JSONObject jsonQuotesObject = new JSONObject(jsonData);


                String quote = jsonQuotesObject.getString("quote");


                if (quote != null) {
                    kayneQuote = quote;
                }


            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    public interface OnTaskFinishedListener
    {
        void OnTaskFinished(String kayneQuote);
    }
}

A bit more code than the MainActivity… but don’t worry, again I will explain it!

MainActivity多一点的代码…但是不用担心,我会再次解释它!

I think it’s easier to reference the above code by a line numbers.. ok so here we go:

我认为通过行号引用上面的代码会更容易..好的,所以我们开始:

Lines 1–10: Imports necessary for Async-related functions (Stream, HTTP and URL libraries).

第1-10行:与异步相关的功能(流,HTTP和URL库)必需的导入。

Line 18: Class declaration which inherits from AsyncTask which includes <Params, Progress, Result> which are included/used as parameters in the methods: doInBackground, onProgressUpdate, onPostExecute. *Note: the method onProgressUpdate isn’t actually implemented in this project, however I mention it just for understanding of the AsyncTask parameters*

第18行:从AsyncTask 继承的类声明,该类声明包括< Params,Progress,Result> ,这些参数包含/用作方法中的参数: doInBackground,onProgressUpdateonPostExecute*注意: onProgressUpdate 方法 实际上并未在该项目中实现,但是我提到它只是为了理解AsyncTask参数*

Lines 19–21: Variables for storing the JSON data returned, reference to the onTaskFinishedListener and “kayneQuote” for storing the result returned from the API request.

第19至21行:用于存储返回的JSON数据的变量,请参考onTaskFinishedListener和用于存储从API请求返回的结果的“ kayneQuote”。

Lines 23–26: Defines constructor for the class, where onTaskFinishedListener is included as a parameter so that the MainActivity onTaskFinishedListener can be assigned to the FetchDataTask class instance.

第23–26行:为该类定义构造函数,其中将onTaskFinishedListener作为参数包含在内,以便可以将MainActivity onTaskFinishedListener分配给FetchDataTask类实例。

Lines 29–31: An overridden class from the AsyncTask class which includes preparing data before the API request. The method from the parent class is also included in this overridden method.

第29至31行:AsyncTask类中的重写类,包括在API请求之前准备数据。 父类的方法也包含在此重写的方法中。

Lines 33–39: Another overridden method that is the actual code run during the asynchronous request. This uses a different thread to the UI thread to send the request. The getJsonData method call is called to achieve the sending of the request. The parseJsonToKayneQuote method parses the returned JSON data into the required format for storage in the kayneQuote variable. The JSON data is returned from the doInBackground method (which is stored in the variable jsonData).

第33–39行:另一个重写的方法,是在异步请求期间运行的实际代码。 这使用与UI线程不同的线程来发送请求。 调用getJsonData方法调用以实现请求的发送。 parseJsonToKayneQuote方法将返回的JSON数据解析为所需格式,以存储在kayneQuote变量中。 JSON数据从doInBackground方法返回(存储在变量jsonData中)。

Lines 41–48: onPostExecute is the 3rd overridden method from the AsyncTask class. This runs code after the asynchronous call is completed for processing data accordingly. There is a null check in this method, however a check already takes place in the parseJsonToKayneQuote method so probably isn’t necessarily required. The onTaskFinished method is then called to signify the task… well has finished :).

第41–48行:onPostExecute是AsyncTask类中的第三个重写方法。 这将在异步调用完成之后运行代码以相应地处理数据。 此方法中有一个空检查,但是在parseJsonToKayneQuote方法中已经进行了检查,因此可能不一定必需。 然后调用onTaskFinished方法来表示任务……已经完成了:)。

Lines 50–82: [This is the largest method of the class]

第50-82行:[这是该课程中最大的方法]

  • Lines 53–57 create the necessary variables, then are used to setup a connection in order to make the API call. The requestMethod is set to a GET request (we only want to read data from the API and not POST anything to the API). A connection attempt is then invoked to connect to the API.

    第53–57行创建必要的变量,然后用于建立连接以进行API调用。 requestMethod设置为GET请求(我们只想从API读取数据,而不想向API发送任何内容)。 然后调用连接尝试以连接到API。
  • Lines 59–64 The response code sent back from the server is then stored, checked and if the request was successful (a 200 response which is ok) then an InputStream object is created in order to start reading the data stream using the established connection.

    第59–64行然后存储,检查从服务器发送回的响应代码,如果请求成功(200响应正常),则创建InputStream对象,以便开始使用已建立的连接读取数据流。
  • Lines 67–76 Involve using a BufferedReader and StringBuffer to read the InputStream data from the established connection. A StringBuffer is used as it’s Thread-Safe and Mutable (compared to a StringBuilder). The data is read until the line using the BufferedReader is null. The data stored using the StringBuffer object is then added to as long as the current ‘reader’ (BufferedReader) line has some data to append to it. The ‘buffer’ variable data is then assigned to the jsonData variable. The code after line 76 is just to catch an exceptions thrown when trying to establish a connection, (providing debug and exception messages when/if required).

    第67-76行涉及使用BufferedReader和StringBuffer从已建立的连接读取InputStream数据。 使用StringBuffer是因为它是线程安全的和可变的(与StringBuilder相比)。 读取数据,直到使用BufferedReader的行为空为止。 只要当前的“ reader”(BufferedReader)行中要追加一些数据,就会添加使用StringBuffer对象存储的数据。 然后将“ buffer”变量数据分配给jsonData变量。 第76行之后的代码仅用于捕获尝试建立连接时引发的异常((在需要时提供调试和异常消息)。
  • Lines 84–100 Initially checks that the returned jsonData contains data. If so, using the imported org.json… code library, a JSONObject is created to represent the raw json data (which is just a long String value) in a JSON structure. The “quote ”String variable accesses and the JSON key-value pair attribute called quote. If this attribute exists and contains data, then this data stored in the “quote” variable is assigned to the “kayneQuote” variable.

    第84–100行最初检查返回的jsonData是否包含数据。 如果是这样,则使用导入的org.json…代码库,创建一个JSONObject来表示JSON结构中的原始json数据(只是一个很长的String值)。 “ quote”字符串变量访问和名为quote的JSON键值对属性。 如果该属性存在并包含数据,则将存储在“ quote”变量中的该数据分配给“ kayneQuote”变量。
  • Lines 103–107 Include the declaration of the Interface that I mentioned about in the MainActivity class. This defines what method should be implemented when this Interface is used.

    第103–107行包含MainActivity类中提到的Interface的声明。 这定义了使用此接口时应实现的方法。

And that’s it for the code explanation!!

这就是代码说明!!

Once you have either an Android Virtual Device or actual Android device setup, you should see one of the Kayne quotes from the API:

有了Android虚拟设备或实际的Android设备设置后,您应该会从API中看到Kayne引号之一:

Image for post

I Heard ’Em Say that was the end of the story, now you are a Stronger developer.. ok I will stop with the Kayne song references!

听到'Em说到故事的结尾,现在您是一名Stronger开发人员。.好的,我将停止与Kayne的歌曲引用!

If you have any questions, feel free to comment on this story and I will do my best to help you out.

如果您有任何疑问,请随时评论这个故事,我们将尽力为您提供帮助。

与往常一样,如果您发现这很有用,有趣或两者兼而有之,请在Medium上关注我,以获得更多这些故事! (As always, if you found this useful, entertaining or both, follow me on Medium for more of these stories!)

Thanks and have a good day!

谢谢,祝你有美好的一天!

(…Just published this story and realised that I’ve spelt Kanye wrong…😐. Oh well 😄)

(……只是发表了这个故事,并意识到我拼写了坎耶错了……😐。哦well)

Image for post
Photo by Drew Beamer on Unsplash
Drew BeamerUnsplash上的 照片

翻译自: https://medium.com/dev-genius/what-do-kayne-west-and-software-development-have-in-common-a51df95314dd

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值