使用 AsyncTask 在 Fragment 的 RecyclerView 中显示来自 json 的数据?

Posted

技术标签:

【中文标题】使用 AsyncTask 在 Fragment 的 RecyclerView 中显示来自 json 的数据?【英文标题】:Display data from json in RecyclerView of Fragment using AsyncTask? 【发布时间】:2020-08-21 08:34:59 【问题描述】:

我有以下课程:

CategoryFragment.java

public class CategoryFragment extends Fragment 
    // TODO: Rename parameter arguments, choose names that match
    // the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
    private static final String ARG_PARAM1 = "category_name";

    // TODO: Rename and change types of parameters
    private int mParam1;

    public CategoryFragment() 
        // Required empty public constructor
    

    /**
     * Use this factory method to create a new instance of
     * this fragment using the provided parameters.
     *
     * @param param1 Parameter 1.
     * @return A new instance of fragment CategoryFragment.
     */
    // TODO: Rename and change types and number of parameters
    public static CategoryFragment newInstance(int param1) 
        CategoryFragment fragment = new CategoryFragment();
        Bundle args = new Bundle();
        args.putInt(ARG_PARAM1, param1);
        fragment.setArguments(args);
        return fragment;
    

    @Override
    public void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        if (getArguments() != null) 
            mParam1 = getArguments().getInt(ARG_PARAM1);
        
    

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) 
        Context context = getActivity();
        View view = inflater.inflate(R.layout.listado_noticias, container, false);
        RecyclerView rw_noticias = view.findViewById(R.id.rw_noticias);

        new LoadArticlesTask().execute(MainScreen.mPrefs,MainScreen.hasRemember,view,context,rw_noticias);


        return null;
    


listado_noticias.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_
    android:layout_
    android:id="@+id/constraintLayout"
    xmlns:tools="http://schemas.android.com/tools">


    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/rw_noticias"
        android:layout_
        android:layout_ />
</androidx.constraintlayout.widget.ConstraintLayout>

加载ArticlesTask.java

public class LoadArticlesTask extends AsyncTask<Object, Void, List<Article>> 
    
    private static final String TAG = "LoadArticlesTask";
    private View view;
    private Context context;
    private RecyclerView rw_noticias;

    @Override
    protected List<Article> doInBackground(Object... params) 
        SharedPreferences sp = (SharedPreferences)params[0];
        boolean hasRemember = (boolean)params[1];
        view = (View)params[2];
        context = (Context)params[3];
        rw_noticias = (RecyclerView)params[4];
        List<Article> res = null;
        Properties ini = new Properties();
        ini.setProperty(RESTConnection.ATTR_SERVICE_URL,Constants.URL_SERVICE);
        ini.setProperty(RESTConnection.ATTR_REQUIRE_SELF_CERT,Constants.CERT_VALUE);
        ModelManager.configureConnection(ini);
        String strIdUser;
        String strApiKey;
        String strIdAuthUser;

        if(hasRemember)
            strIdUser = sp.getString("pref_apikey","");
            strApiKey = sp.getString("pref_IdUser","");
            strIdAuthUser = sp.getString("pref_strIdAuthUser","");

        else 
            strIdUser = ModelManager.getLoggedIdUSer();
            strApiKey = ModelManager.getLoggedApiKey();
            strIdAuthUser = ModelManager.getLoggedAuthType();
        
        //ModelManager uses singleton pattern, connecting once per app execution in enough
        if (!ModelManager.isConnected())
            // if it is the first login
            if (strIdUser==null || strIdUser.equals("")) 
                try 
                    ModelManager.login(Constants.USER, Constants.PASS);

                 catch (AuthenticationError e) 
                    Log.e(TAG, e.getMessage());
                
            
            // if we have saved user credentials from previous connections
            else
                ModelManager.stayloggedin(strIdUser,strApiKey,strIdAuthUser);
            
        
        //If connection has been successful
        if (ModelManager.isConnected()) 
            try 
                // obtain 6 articles from offset 0
                res = ModelManager.getArticles(6, 0);
                for (Article article : res) 
                    // We print articles in Log
                    Log.i(TAG, String.valueOf(article));
                
             catch (ServerCommunicationError e) 
                Log.e(TAG,e.getMessage());
            
        
        return res;
    

    @Override
    protected void onPostExecute(List<Article> articles) 
        super.onPostExecute(articles);
        Log.i("Articles", articles.toString());
        for (Article article : articles) 
            // We print articles in Log
            Log.i("Articles", String.valueOf(article));
        
        refreshList(articles,view);
    

    public void refreshList(List<Article> data, View view)
        if (data == null)
            return;
        
        for (Article article : data) 
            // We print articles in Log
            Log.i("Articles_rl", String.valueOf(article));
        
        final LinearLayoutManager layoutManager = new LinearLayoutManager(context);
        layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
        rw_noticias.setLayoutManager(layoutManager);
        ArticlesAdapter articlesAdapter = new ArticlesAdapter(data);
        rw_noticias.setAdapter(articlesAdapter);
        ((ArticlesAdapter)rw_noticias.getAdapter()).updateData(data);

    



ArticlesAdapter.java

public class ArticlesAdapter extends RecyclerView.Adapter<ArticlesAdapter.ArticleViewHolder>

    private List<Article> articulos;
    public ArticlesAdapter(List<Article> articulos)
        this.articulos = articulos;
    
    @NonNull
    @Override
    public ArticleViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) 
        View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.card_layout_article, parent, false);
        return new ArticleViewHolder(v);
    

    @Override
    public void onBindViewHolder(@NonNull ArticleViewHolder holder, int position) 
        Bitmap imagen = null;
        holder.category.setText(articulos.get(position).getCategory());
        holder.title.setText(articulos.get(position).getTitleText());
        holder.resumen.setText(articulos.get(position).getAbstractText());
        try 
            imagen = SerializationUtils.base64StringToImg(articulos.get(position).getImage().getImage());
         catch (ServerCommunicationError serverCommunicationError) 
            serverCommunicationError.printStackTrace();
        
        holder.thumbnail.setImageBitmap(imagen);


    

    @Override
    public int getItemCount() 
        return articulos.size();
    
    @Override
    public void onAttachedToRecyclerView(RecyclerView recyclerView) 
        super.onAttachedToRecyclerView(recyclerView);
    


    public void updateData(List<Article>data)
        articulos.clear();
        articulos.addAll(data);
        notifyDataSetChanged(); //notify to repaint the list
    

    public void articlesFilterCategory(String category)
        for (Article a : articulos)
            if(!category.equals("ALL") && !a.getCategory().equals(category))
                articulos.remove(a);
            
        
    



    public static class ArticleViewHolder extends RecyclerView.ViewHolder
        CardView cv;
        TextView category;
        TextView title;
        TextView resumen;
        ImageView thumbnail;

        public ArticleViewHolder(@NonNull View itemView) 
            super(itemView);
            cv = (CardView)itemView.findViewById(R.id.card_article);
            category = (TextView)itemView.findViewById(R.id.category_noticia);
            resumen = (TextView)itemView.findViewById(R.id.resumen_noticia);
            thumbnail = (ImageView)itemView.findViewById(R.id.thumbnail);
        
    


card_layout_article.xml

<androidx.cardview.widget.CardView 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:orientation="vertical" android:layout_
    android:layout_
    android:foreground="?attr/selectableItemBackground"
    android:ellipsize="end"
    android:id="@+id/card_article"
    >


      <RelativeLayout
          android:layout_
          android:layout_
          android:paddingBottom="16dp"
          android:paddingHorizontal="1dp">


          <ImageView
              android:id="@+id/thumbnail"
              android:layout_
              android:layout_
              android:layout_alignParentLeft="true"
              android:layout_alignParentTop="true"
              android:layout_marginLeft="1dp"
              android:layout_marginTop="1dp"
              android:adjustViewBounds="true"
              android:background="@drawable/a15877171854035"
              android:cropToPadding="true"
              android:scaleType="fitXY"
              android:src="@drawable/degradado" />

          <View
              android:layout_
              android:layout_
              android:background="@drawable/degradado" />

          <TextView
              android:id="@+id/title_noticia"
              android:layout_
              android:layout_
              android:layout_alignBottom="@+id/thumbnail"
              android:layout_alignParentStart="true"
              android:layout_alignParentEnd="true"
              android:layout_marginStart="107dp"
              android:layout_marginEnd="107dp"
              android:layout_marginBottom="95dp"
              android:text="Nuevo caso de coronavirus"
              android:textAlignment="center"
              android:textColor="@color/cardview_light_background"
              android:textSize="20dp"
              android:textStyle="bold" />

          <TextView
              android:id="@+id/category_noticia"
              android:layout_
              android:layout_
              android:layout_alignBottom="@+id/thumbnail"
              android:layout_alignParentStart="true"
              android:layout_alignParentEnd="true"
              android:layout_marginStart="11dp"
              android:layout_marginEnd="316dp"
              android:layout_marginBottom="145dp"
              android:text="NATIONAL"
              android:textAlignment="center"
              android:textColor="@color/cardview_light_background"
              android:textSize="15dp"
              android:textStyle="bold" />

          <TextView
              android:id="@+id/resumen_noticia"
              android:layout_
              android:layout_
              android:layout_alignBottom="@+id/thumbnail"
              android:layout_alignParentStart="true"
              android:layout_alignParentEnd="true"
              android:layout_marginStart="0dp"
              android:layout_marginEnd="0dp"
              android:layout_marginBottom="-1dp"
              android:text="Nuevo caso de coronavirus"
              android:textAlignment="viewStart"
              android:textColor="@color/cardview_light_background"
              android:textSize="11dp"
              android:textStyle="bold" />


      </RelativeLayout>

</androidx.cardview.widget.CardView>

在我在异步任务的 Post Execute 中拥有的 log.i 中,我可以看到文章是如何形成的(Article 类有一个 toString () 函数)。

但我无法在 RecyclerView 中看到文章。我究竟做错了什么? Capture: Main screen with recyclerView empty...

谢谢!

【问题讨论】:

【参考方案1】:

传递RecyclerView的实例@like -

new LoadArticlesTask().execute(MainScreen.mPrefs, MainScreen.hasRemember, view, rw_noticias, context);

LoadArticlesTask 上接收此信息,就像在View 上一样。 不要在你的类中重新初始化/使用这个代码 -

RecyclerView rw_noticias = view.findViewById(R.id.rw_noticias);

【讨论】:

谢谢。用您的回复@W4R10CK 更新问题,但仍然无法正常工作...【参考方案2】:

在您的card_layout_article.xml 中,将高度wrap_content 设为cardview

<androidx.cardview.widget.CardView 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:orientation="vertical" android:layout_
    android:layout_
    ........
    ........

同样在您的回收站视图布局中,尝试使用 RelativeLayout 而不是 RelativeLayout 作为父级:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_
    android:layout_
    android:id="@+id/constraintLayout"
    xmlns:tools="http://schemas.android.com/tools">


    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/rw_noticias"
        android:layout_
        android:layout_ />

</RelativeLayout>

【讨论】:

以上是关于使用 AsyncTask 在 Fragment 的 RecyclerView 中显示来自 json 的数据?的主要内容,如果未能解决你的问题,请参考以下文章

Asynctask结果显示重新创建片段后

打开新的 Fragment 和 AsyncTask 时显示 ProgressDialog

从 Fragment 内的 AsyncTask 重新启动 Loader (SQLite) 时出现 IllegalStateException

什么是生命周期感知方式来实现重复的AsyncTask?

从另一个 Activity 类执行 Fragment 中的 AsyncTask 并更新其中的 UI

使用 recyclerview 和 Asynctask 设置 Viewpager