recylerView 未显示在应用程序中

Posted

技术标签:

【中文标题】recylerView 未显示在应用程序中【英文标题】:the recylerView does not shown in the app 【发布时间】:2020-06-13 09:04:50 【问题描述】:

嘿,我是使用 android 的新手,我用这个应用程序制作了我正在学习的教程,当我尝试在 Fragment 中工作时,该教程从 MainActivity.java 读取和写入数据。

尽管应用程序没有显示任何错误,但 Firebase 实时数据库的 JSON 数据并未按预期显示在 RecylerView 中。

这是我的文件

MainActivity.java

package com.example.plutus;

import android.os.Bundle;
import android.view.MenuItem;
import android.widget.FrameLayout;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentTransaction;

import com.google.android.material.bottomnavigation.BottomNavigationView;

public class MainActivity extends AppCompatActivity 

    private TaskFragment taskFragment;
    private TimeFragment timeFragment;
    private HabitFragment habitFragment;
    private HourFragment hourFragment;
    private BottomNavigationView mMainNav;
    private FrameLayout mMainFrame;

    @Override
    protected void onCreate(Bundle savedInstanceState) 


        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


        mMainNav = (BottomNavigationView) findViewById(R.id.main_nav);
        mMainFrame = (FrameLayout) findViewById(R.id.main_frame);


        taskFragment = new TaskFragment();
        timeFragment = new TimeFragment();
        habitFragment = new HabitFragment();
        hourFragment = new HourFragment();

        setFragment(taskFragment);


        mMainNav.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() 
            @Override
            public boolean onNavigationItemSelected(@NonNull MenuItem item) 
                switch (item.getItemId()) 
                    case R.id.nav_task:
                        setFragment(taskFragment);
                        return true;


                    case R.id.nav_time:
                        setFragment(timeFragment);
                        return true;


                    case R.id.nav_habit:
                        setFragment(habitFragment);
                        return true;


                    case R.id.nav_hour:
                        setFragment(hourFragment);
                        return true;

                    default:
                        return false;
                

            
        );

    
    private void setFragment(Fragment fragment) 
        FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
        fragmentTransaction.replace(R.id.main_frame, fragment);
        fragmentTransaction.commit();
    




TaskAdapter.java

package com.example.plutus;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

import com.google.firebase.database.ValueEventListener;

import java.util.ArrayList;

public class TaskAdapter extends RecyclerView.Adapter<TaskAdapter.MyViewHolder> 

    ValueEventListener context;
    ArrayList<MyTasks> myTasks;

    public TaskAdapter(ValueEventListener c, ArrayList<MyTasks> p) 
        context =  c;
        myTasks = p;
    


    @NonNull
    @Override
    public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) 
        return new MyViewHolder(LayoutInflater.from((Context) context).inflate(R.layout.task_item, parent, false));
    

    @Override
    public void onBindViewHolder(@NonNull MyViewHolder holder, int position) 
        holder.tasktitle.setText(myTasks.get(position).getTasktitle());

    

    @Override
    public int getItemCount() 

        return myTasks.size();
    

    class MyViewHolder extends RecyclerView.ViewHolder 

        TextView tasktitle;

        public MyViewHolder(@NonNull View itemView) 
            super(itemView);
            tasktitle = (TextView) itemView.findViewById(R.id.tasktitletext);
        
    


TaskFragment.java

package com.example.plutus;


import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.ValueEventListener;

import java.util.ArrayList;


/**
 * A simple @link Fragment subclass.
 */
public class TaskFragment extends Fragment 

    //Firebase Json integration
    RecyclerView ourTasks;
    ArrayList<MyTasks> list;
    TaskAdapter taskAdapter;

    public TaskFragment() 

    

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) 

    View rootView = inflater.inflate(R.layout.fragment_task, container, false);

        ourTasks = rootView.findViewById(R.id.ourTasks);
        ourTasks.setLayoutManager(new LinearLayoutManager(getActivity()));
        list = new ArrayList<MyTasks>();

        // Inflate the layout for this fragment

        DatabaseReference taskDatabaseReference = FirebaseDatabase.getInstance().getReference();
        DatabaseReference taskuser = taskDatabaseReference.child("Task1").child("tasktitle");

        taskuser.addValueEventListener(new ValueEventListener() 
            @Override
            public void onDataChange(@NonNull DataSnapshot dataSnapshot) 

                for (DataSnapshot dataSnapshot1: dataSnapshot.getChildren())
                    MyTasks p = dataSnapshot1.getValue(MyTasks.class);
                    list.add(p);
                

                taskAdapter = new TaskAdapter(this, list);
                ourTasks.setAdapter(taskAdapter);
                taskAdapter.notifyDataSetChanged();
            

            @Override
            public void onCancelled(@NonNull DatabaseError databaseError) 
                Toast.makeText(getContext(), "I'm fetching this", Toast.LENGTH_SHORT).show();
            
        );

        return rootView;
    ;



MyTasks.java

package com.example.plutus;

public class MyTasks 
    String tasktitle;

    public MyTasks() 

    

    public MyTasks(String tasktitle) 

        this.tasktitle = tasktitle;
    

    public String getTasktitle() 

        return tasktitle;
    

    public void setTasktitle(String tasktitle) 

        this.tasktitle = tasktitle;
    


我不明白真正的问题在哪里。

编辑:包含的 JSON 文件。


    "Plutus":
        "Task1":
            "tasktitle":"Create an awesome app"
        ,

        "Task2":
            "tasktitle":"Learn More Android"
        ,

        "Task3":
            "tasktitle":"Learn Android Pentesting too"
        ,

        "Task4":
            "tasktitle":"Oi don't forget Bug Hunting"
        
    

【问题讨论】:

Stack Overflow 是一个非常低效的交互式调试器,因此很难帮助处理如此大量的代码。如果你在调试器中运行你的代码,你的onDataChange 会被调用吗?如果是这样,如果您逐步执行该方法会发生什么? p 是否包含您期望的数据?您越能帮助我们找到发生故障的特定线路,我们就越有可能提供帮助。 我通过调试器运行它,实际上onDataChange 确实被调用了,尽管内部的 for 循环没有被执行直接跳转到 for 循环之后,而且 onCancelled 也没有被调用。也因为 for 循环不起作用,数组列表保持不变。 如果onDataChange 被调用,但它没有进入你的循环,这意味着taskuser 没有数据。如果您编辑您的问题以包含您尝试显示的 JSON(作为文本,请不要截图),这可能会很有用。您可以通过单击Firebase Database console 上溢出菜单 (⠇) 中的“导出 JSON”链接来获取此信息。 我现在已经在问题中包含了 JSON 文件。 【参考方案1】:

您的代码中存在一些问题:

您没有在代码中处理 JSON 的 Plutus 级别。 您的行为好像快照中可以有多个节点,但实际上您加载的是一个非常特定的节点。所以你不需要循环getChildren()。 由于您只加载title 节点,因此结果不是MyTasks

要仅加载一项任务的标题,您可以执行以下操作:

DatabaseReference taskDatabaseReference = FirebaseDatabase.getInstance().getReference();
DatabaseReference taskuser = taskDatabaseReference.child("Plutus/Task1/tasktitle");

taskuser.addValueEventListener(new ValueEventListener() 
    @Override
    public void onDataChange(@NonNull DataSnapshot dataSnapshot) 
        Log.i("Firebase", dataSnapshot.getValue(String.class));
    

    @Override
    public void onCancelled(@NonNull DatabaseError databaseError) 
        throw databaseError.toException(); // make sure to show the programming error
    
);

要加载单个任务,但要加载整个任务,它会是这样的:

DatabaseReference taskDatabaseReference = FirebaseDatabase.getInstance().getReference();
DatabaseReference taskuser = taskDatabaseReference.child("Plutus/Task1");

taskuser.addValueEventListener(new ValueEventListener() 
    @Override
    public void onDataChange(@NonNull DataSnapshot dataSnapshot) 
        MyTasks p = dataSnapshot.getValue(MyTasks.class);
        Log.i("Firebase", p.toString());
    

    @Override
    public void onCancelled(@NonNull DatabaseError databaseError) 
        throw databaseError.toException(); // make sure to show the programming error
    
);

要加载所有任务,并将它们添加到适配器/视图,它会是这样的:

taskAdapter = new TaskAdapter(this, list);
ourTasks.setAdapter(taskAdapter);

DatabaseReference taskDatabaseReference = FirebaseDatabase.getInstance().getReference();
DatabaseReference taskuser = taskDatabaseReference.child("Plutus");

taskuser.addValueEventListener(new ValueEventListener() 
    @Override
    public void onDataChange(@NonNull DataSnapshot dataSnapshot) 
        for (DataSnapshot taskSnapshot: dataSnapshot.getChildren())
            MyTasks p = taskSnapshot.getValue(MyTasks.class);
            list.add(p);
        
        taskAdapter.notifyDataSetChanged();
    

    @Override
    public void onCancelled(@NonNull DatabaseError databaseError) 
        throw databaseError.toException(); // make sure to show the programming error
    
);

您会注意到我在这里将适配器从侦听器中拉出。不需要每次数据发生变化时都重新构建一个新的适配器,而是可以只更新list中的数据,然后通知适配器,让它更新UI。

【讨论】:

这很有效,虽然必须做一些改变是 TaskAdapter 现在它从 firebase 数据库加载所有的 tastitle。 感谢您的更新!很高兴听到你成功了。 :)

以上是关于recylerView 未显示在应用程序中的主要内容,如果未能解决你的问题,请参考以下文章

如何在片段内的 recylerview 列表中显示 SQLite 数据库数据?

Android-RecylerView控件

使用CustomLists数组显示recylerview数据

Recycler View 没有更新和显示任何内容

XamarinAndroid组件教程RecylerView适配器动画动画种类

如何在 Firestore RecylerView (Firestore UI) 中过滤和排序我的文档?