手把手教!如何通過API獲取數(shù)據(jù)并放入RecyclerView列表中展示

代碼不全,但盡可能詳細(xì)的講解了主要實(shí)現(xiàn)步驟,希望能對(duì)各位看官有所幫助!

步驟:

一、準(zhǔn)備一個(gè)RecyclerView列表用于展示數(shù)據(jù)

二、找到對(duì)應(yīng)的API接口并根據(jù)Json格式構(gòu)造用于解析的Gson類

三、創(chuàng)建ViewModel類承擔(dān)數(shù)據(jù)操作的責(zé)任

四、將解析好的數(shù)據(jù)放入RecyclerView中

一、準(zhǔn)備一個(gè)RecyclerView列表用于展示數(shù)據(jù)

  1. 在閉包中加入相應(yīng)的依賴庫
implementation "androidx.recyclerview:recyclerview:1.1.0"
implementation "androidx.recyclerview:recyclerview-selection:1.1.0-rc03"
  1. 在對(duì)應(yīng)的xml文件中加入RecyclerView控件

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/news_recyc"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
    
  2. 為列表中的子項(xiàng)創(chuàng)建一個(gè)xml布局頁面,再建立一個(gè)類存放展示所需的字段

  3. 接下來要為RecyclerView準(zhǔn)備一個(gè)適配器,新建NewAdapter類繼承自RecyclerView.Adapter,重寫和加載參數(shù)相關(guān)的方法,onCreateViewHolder()、onBindViewHolder ()和getItemCount()這三個(gè)方法。NewAdapter的泛型數(shù)據(jù)類型是自定義的ViewHolder。NewAdapter中有一個(gè)構(gòu)造函數(shù),把要展示的數(shù)據(jù)源傳進(jìn)來,并賦值給一個(gè)全局變量,作為數(shù)據(jù)源。后續(xù)操作都在數(shù)據(jù)源的基礎(chǔ)上進(jìn)行。


  4. onCreateViewHolder()用于創(chuàng)建ViewHolder實(shí)例。加載news_item布局,創(chuàng)建ViewHolder實(shí)例,并把加載出來的布局傳入到構(gòu)造函數(shù)中,最后將ViewHolder的實(shí)例返回。

    public ViewHolder onCreateViewHolder(final ViewGroup parent, int viewType) {
        //加載item布局
        final View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.new_item, parent, false);
        //創(chuàng)建ViewHolder實(shí)例
        final ViewHolder holder = new ViewHolder(view);
        //未來:實(shí)現(xiàn)下面兩個(gè)頁面跳轉(zhuǎn)到倉庫主頁的activity
        holder.newView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                int position = holder.getAdapterPosition();
                News news= newsList.get(position);
                Toast.makeText(v.getContext(), "you will see repo ", Toast.LENGTH_SHORT).show();
            }
        });
       //未來:實(shí)現(xiàn)下面兩個(gè)點(diǎn)擊事件跳轉(zhuǎn)到個(gè)人主頁的activity
        holder.userImage.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                int position = holder.getAdapterPosition();
                News news= newsList.get(position);
                Toast.makeText(v.getContext(), "you will see profile of  " + news.getUserName(), Toast.LENGTH_SHORT).show();
            }
        });
        holder.userName.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                int position = holder.getAdapterPosition();
                News news= newsList.get(position);
                Toast.makeText(v.getContext(), "you will see profile of  " + news.getUserName(), Toast.LENGTH_SHORT).show();
            }
        });
        return holder;
    }
    
  5. onBindViewHolder ()用于對(duì)RecyclerView子項(xiàng)的數(shù)據(jù)進(jìn)行賦值。我們通過position參數(shù)得到當(dāng)前項(xiàng)的News實(shí)例。

    public void onBindViewHolder(final ViewHolder holder, int position) {
        final News news = newsList.get(position);
        holder.userName.setText(news.getUserName());
        holder.time.setText(news.getTime());
        holder.action.setText(news.getAction());
    }
    
  6. getItemCount()統(tǒng)計(jì)子項(xiàng)個(gè)數(shù),返回?cái)?shù)據(jù)源的長(zhǎng)度。

    public int getItemCount() {
        return newsList.size();
    }
    

二、找到對(duì)應(yīng)的API接口并根據(jù)Json格式構(gòu)造用于解析的Gson類

  1. 通過GraphQL找到想找的API,復(fù)制到postman里生成請(qǐng)求代碼。獲取到的請(qǐng)求代碼我把它放到了一個(gè)函數(shù)里,以便調(diào)用和修改。

    public static String getUserNews() {
        return "{\"query\":\"query MyQuery {\\r\\n  viewer {\\r\\n    following(first: 10) {\\r\\n      edges {\\r\\n        node {\\r\\n          avatarUrl(size: 10)\\r\\n          login\\r\\n          starredRepositories {\\r\\n            edges {\\r\\n              starredAt\\r\\n            }\\r\\n            nodes {\\r\\n              nameWithOwner\\r\\n            }\\r\\n          }\\r\\n        }\\r\\n      }\\r\\n    }\\r\\n  }\\r\\n}\",\"variables\":{}}";
    }
    
  2. 通過OkHttp發(fā)起HTTP請(qǐng)求,建立網(wǎng)絡(luò)連接

    • 發(fā)起HTTP請(qǐng)求,需要?jiǎng)?chuàng)建一個(gè)Request對(duì)象??梢栽谧罱K的bulid方法前連綴很多方法來豐富Request對(duì)象,比如指定服務(wù)器返回?cái)?shù)據(jù)格式為json,將上一步得到的請(qǐng)求代碼放入body中。

    • 調(diào)用OkHttpClient的newCall(request)來創(chuàng)建一個(gè)call對(duì)象,重寫onFailure和onResponse方法。

      //構(gòu)造請(qǐng)求
      Request.Builder builder = BaseRequestBuilder.getBuilder();
      MediaType mediaType = MediaType.parse("application/json");
      //Json代碼
      RequestBody body = RequestBody.create(mediaType, RequestBodyHelper.getUserNews());
      //構(gòu)建請(qǐng)求
      Request request = builder.method("POST", body).build();
      OkHttpClient client = OkhttpUtil.getInstance();
      //請(qǐng)求數(shù)據(jù)
      client.newCall(request).enqueue(new Callback() {
          @Override
          public void onFailure(@NotNull Call call, @NotNull IOException e) {
              doFailure();
          }
      
          @Override
          public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
              Log.d("tag", "List數(shù)組創(chuàng)建成功");
              doSuccess(response);
      
          }
      });
      //服務(wù)器返回的數(shù)據(jù)
      String data = response.body().string();
      
  3. 通過Gson方法解析服務(wù)器返回的JSON數(shù)據(jù)

    • 先在閉包中添加依賴項(xiàng)

      implementation 'com.google.code.gson:gson:2.8.6'
      
    • 再用Gson反序列化服務(wù)器返回的數(shù)據(jù)。我獲取的數(shù)據(jù)是一個(gè)List數(shù)組。先對(duì)返回來的數(shù)據(jù)進(jìn)行字符串處理,<u>確保待解析的字符串是完整的[XXXXXX]</u>。這里說明一下,{}代表里面的代碼塊是一個(gè)類,[]代表里面的代碼塊是一個(gè)數(shù)組。根據(jù)在GraphQL中看到的Json格式,從內(nèi)往外的去定義相應(yīng)的類和數(shù)組,層層嵌套,確保變量命名和Json數(shù)據(jù)中名字一致。這里用簡(jiǎn)單的例子舉例說明一下吧。

      //String data = response.body().string();服務(wù)器返回的數(shù)據(jù)
      String userJson = " [{'isDeveloper':false,'name':'xiaoqiang','age':26,'email':'578570174@qq.com'}, {'isDeveloper':true,'name':'xiaoqiang123','age':27,'email':'578570174@gmail.com' }]";
      
      Gson gson = new Gson();
       Type userListType = new TypeToken<ArrayList<User>>(){}.getType();
      
      List<User> userList = gson.fromJson(userJson, userListType);
      //這個(gè)List將為后續(xù)操作的數(shù)據(jù)源
      
    • 對(duì)于 List ,反序列化時(shí)必須提供它的Type,通過 Gson 提供的 TypeToken<T>.getType() 方法可以定 義當(dāng)前List的 Type 。這個(gè)Type應(yīng)為服務(wù)器返回?cái)?shù)據(jù)的最外層所定義的類。

三、創(chuàng)建ViewModel類承擔(dān)數(shù)據(jù)操作的責(zé)任

ViewModel的生命周期比Activity和Fragment都要長(zhǎng),用ViewModel存儲(chǔ)數(shù)據(jù)不用擔(dān)心數(shù)據(jù)保存和恢復(fù)的問題。再者UI controller 比如 Activity 、Fragment 是設(shè)計(jì)用來渲染展示數(shù)據(jù)、響應(yīng)用戶行為、處理系統(tǒng)的某些交互。如果再要求他去負(fù)責(zé)加載網(wǎng)絡(luò)或數(shù)據(jù)庫數(shù)據(jù),會(huì)讓其顯得臃腫和難以管理。所以為了簡(jiǎn)潔、清爽、 絲滑,我們可以分離出數(shù)據(jù)操作的職責(zé)給 ViewModel。下面來看看怎么用ViewModel管理數(shù)據(jù)。

  1. 創(chuàng)建一個(gè)NewsViewModel繼承自ViewModel,并在構(gòu)造函數(shù)中初始化了數(shù)據(jù)源,雖然Google為防止內(nèi)存泄漏禁止在 ViewModel 中持有 Context 或 activity 或 view 的引用,但是為了在ViewModel里操作UI線程,我從外部傳了個(gè)Context進(jìn)來。

         private MutableLiveData<ArrayList<News>> Listdata;
        List<News> newList = new ArrayList<>();
        Context newsContext;
    
        public NewsViewModel() {
            Listdata = new MutableLiveData<>();
            initNewList();
        }
    
        public LiveData<ArrayList<News>> getList() {
            return Listdata;
        }
        private void initNewList(){//上文通過API獲取數(shù)據(jù)源,在doSuccess中完成了數(shù)據(jù)解析,并調(diào)用了setListValue()將數(shù)據(jù)裝入ViewModel的Listdata中
        }
         public void setContext(Context context) {
            newsContext = context;
        }
         public void setListValue() {
            ((MainActivity) newsContext).runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    Listdata.setValue((ArrayList<News>) newList);
                }
            });
        }
    
  2. 在UI控制器里(Fragment或Activity)生成一個(gè)ViewModel對(duì)象。通過對(duì)象調(diào)用getList()就可以獲取數(shù)據(jù)源進(jìn)行操作了。

    newsViewModel= new ViewModelProvider(this).get(NewsViewModel.class);
    

四、將解析好的數(shù)據(jù)放入RecyclerView中

  1. 先把RecyclerView與布局頁綁定(我的RecyclerView是放在fragment里的)

    View root = inflater.inflate(R.layout.fragment_news, container, false);
    final RecyclerView newsRecyclView = root.findViewById(R.id.news_recyc);
    LinearLayoutManager layoutManager = new LinearLayoutManager(this.getActivity());
    newsRecyclView.setLayoutManager(layoutManager);
    
  2. 之前已經(jīng)加載了item的布局頁到適配器中,因此需要將適配器與newsRecyclView進(jìn)行綁定

    //ViewModel里用于刷新UI的觀察者,getList()獲取到數(shù)據(jù)后則在這個(gè)方法中顯示在UI上
    newsViewModel.getList().observe(getViewLifecycleOwner(), new Observer<ArrayList<News>>() {
                @Override
                public void onChanged(@Nullable ArrayList<News> s) {
                  //將數(shù)據(jù)傳入適配器,將適配器綁定到RecyclerView
                    NewAdapter adapter=new NewAdapter(s);
                    newsRecyclView.setAdapter(adapter);
                  //負(fù)責(zé)頁面刷新效果的代碼
                    progressBar.setVisibility(View.GONE);
                    newsRecyclView.setVisibility(View.VISIBLE);
                }
            });
    
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容