应用程序可能在 Andriod 中的主线程(Firebase 数据库)上做了太多工作

Posted

技术标签:

【中文标题】应用程序可能在 Andriod 中的主线程(Firebase 数据库)上做了太多工作【英文标题】:The application may be doing too much work on its main thread (Firebase Database) in Andriod 【发布时间】:2018-05-28 03:38:05 【问题描述】:

片段代码

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

                list = new ArrayList<>();
                for (DataSnapshot dataSnapshot1 : dataSnapshot.getChildren()) 

                    for (DataSnapshot dataSnapshot2 : dataSnapshot1.child("Posts").getChildren()) 

                        try 

                            Model listdata = new Model();

                            Model for_post_details = dataSnapshot2.child("info").getValue(Model.class);

                            //Toast.makeText(getActivity(), ""+dataSnapshot1.child("username").getValue(), Toast.LENGTH_SHORT).show();

                            String path = for_post_details.getPath();
                            String location = for_post_details.getLocation();
                            String caption = for_post_details.getCaption();
                            String username = "" + dataSnapshot1.child("username").getValue();

                            listdata.setPath(path);
                            listdata.setLocation(location);
                            listdata.setCaption(caption);
                            listdata.setUsername(username);

                            list.add(listdata);

                         catch (Exception ignored) 
                        
                    

                
                Adapter recyclerview = new Adapter(list, getActivity());
                RecyclerView.LayoutManager layoutmanager = new LinearLayoutManager(getActivity());
                recycler.setLayoutManager(layoutmanager);
                recycler.setItemAnimator(new DefaultItemAnimator());
                recycler.setAdapter(recyclerview);

            

            @Override
            public void onCancelled(DatabaseError error) 
            
        );

适配器代码

public class Adapter extends RecyclerView.Adapter<Adapter.MyHoder> 

    List<Model> list;
    Context context;

    public Adapter(List<Model> list, Context context) 
        this.list = list;
        this.context = context;
    

    @Override
    public MyHoder onCreateViewHolder(ViewGroup parent, int viewType) 

        View view = LayoutInflater.from(context).inflate(R.layout.recycler_trending,parent,false);
        MyHoder myHoder = new MyHoder(view);
        return myHoder;
    

    @Override
    public void onBindViewHolder(MyHoder holder, int position) 
        Model mylist = list.get(position);
        holder.caption.setText(mylist.getCaption());
        holder.location.setText(mylist.getLocation());
        holder.username_top.setText(mylist.getUsername());
        holder.username_bottom.setText(mylist.getUsername());
        Glide.with(context)
                .load(mylist.getPath())
                .into(holder.image);
    

    @Override
    public int getItemCount() 
        return list.size();
    

    class MyHoder extends RecyclerView.ViewHolder
        TextView total_likes, caption, location, username_top, username_bottom;
        ImageView image;
        ImageButton like, share;

        public MyHoder(View itemView) 
            super(itemView);
            total_likes = (TextView) itemView.findViewById(R.id.total_likes);
            caption = (TextView) itemView.findViewById(R.id.caption);
            username_top = (TextView) itemView.findViewById(R.id.username_top);
            username_bottom = (TextView) itemView.findViewById(R.id.username_bottom);
            location = (TextView) itemView.findViewById(R.id.location);
            image = (ImageView) itemView.findViewById(R.id.image);
            like = (ImageButton) itemView.findViewById(R.id.like);
            share = (ImageButton) itemView.findViewById(R.id.share);

        
    

这是我用于构建 Instagram 等应用程序的代码。

代码运行良好,但 UI 很慢,滚动很慢,应用挂起。

我收到了这条消息。

I/Choreographer(1378):跳过了 65 帧!该应用程序可能是 在它的主线程上做太多的工作。

我做错了什么??

你知道 Instagram 使用哪种技术来显示帖子 顺利吗?

谢谢

【问题讨论】:

可能是您正在加载大量图片 @AswinPAshok 图片只有 15kb-17kb 大小。 您是否在点击按钮时获取数据? 加载片段时的 OnViewCreated 试试我的代码并检查它是否仍然挂起 UI。 【参考方案1】:

runOnUiThread() 中运行上述方法,只需将其复制到片段中的onViewCreated()

    runOnUiThread(new Runnable()
    
        @Override
        public void run()
        
            ref.addValueEventListener(new ValueEventListener() 
                @Override
                public void onDataChange(DataSnapshot dataSnapshot) 

                    list = new ArrayList<>();
                    for (DataSnapshot dataSnapshot1 : dataSnapshot.getChildren()) 

                        for (DataSnapshot dataSnapshot2 : dataSnapshot1.child("Posts").getChildren()) 

                            try 

                                Model listdata = new Model();

                                Model for_post_details = dataSnapshot2.child("info").getValue(Model.class);

                                //Toast.makeText(getActivity(), ""+dataSnapshot1.child("username").getValue(), Toast.LENGTH_SHORT).show();

                                String path = for_post_details.getPath();
                                String location = for_post_details.getLocation();
                                String caption = for_post_details.getCaption();
                                String username = "" + dataSnapshot1.child("username").getValue();

                                listdata.setPath(path);
                                listdata.setLocation(location);
                                listdata.setCaption(caption);
                                listdata.setUsername(username);

                                list.add(listdata);

                             catch (Exception ignored) 
                            
                        

                    
                    Adapter recyclerview = new Adapter(list, getActivity());
                    RecyclerView.LayoutManager layoutmanager = new LinearLayoutManager(getActivity());
                    recycler.setLayoutManager(layoutmanager);
                    recycler.setAdapter(recyclerview);

                

                @Override
                public void onCancelled(DatabaseError error) 
                
            );
        
    );

更新 另一种方法是使用AsyncTask

将此代码复制到onViewCreated()之外

private class LoadData extends AsyncTask<String, String, String>

    final ProgressDialog pDialog = new ProgressDialog(getActivity());

    @Override
    protected void onPreExecute()
    
        super.onPreExecute();
        pDialog.setMessage("Loading please wait..");
        pDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
        pDialog.setIndeterminate(true);

        pDialog.show();
    

    @Override
    protected String doInBackground(String... strings)
    
        ref.addValueEventListener(new ValueEventListener() 
            @Override
            public void onDataChange(DataSnapshot dataSnapshot) 

                list = new ArrayList<>();
                for (DataSnapshot dataSnapshot1 : dataSnapshot.getChildren()) 

                    for (DataSnapshot dataSnapshot2 : dataSnapshot1.child("Posts").getChildren()) 

                        try 

                            Model listdata = new Model();

                            Model for_post_details = dataSnapshot2.child("info").getValue(Model.class);

                            //Toast.makeText(getActivity(), ""+dataSnapshot1.child("username").getValue(), Toast.LENGTH_SHORT).show();

                            String path = for_post_details.getPath();
                            String location = for_post_details.getLocation();
                            String caption = for_post_details.getCaption();
                            String username = "" + dataSnapshot1.child("username").getValue();

                            listdata.setPath(path);
                            listdata.setLocation(location);
                            listdata.setCaption(caption);
                            listdata.setUsername(username);

                            list.add(listdata);

                         catch (Exception ignored) 
                        
                    

                

            

            @Override
            public void onCancelled(DatabaseError error) 
            Log.d("anyError", error.toString());
            
        );

    

    @Override
    protected void onPostExecute(String lengthOfFile)
    

               Adapter recyclerview = new Adapter(list, getActivity());
                RecyclerView.LayoutManager layoutmanager = new LinearLayoutManager(getActivity());
                recycler.setLayoutManager(layoutmanager);
                recycler.setAdapter(recyclerview);

        if ((pDialog != null)  && (pDialog.isShowing()))
        
            pDialog.dismiss();
        
    

onViewCreated() 内只需调用new LoadData().execute();

【讨论】:

尝试第二种方法。如果可行,请接受答案:)【参考方案2】:

addValueEventListener 会在数据发生更改而导致 ui 卡住时不断调用尝试使用 addListenerForSingleValueEvent,它只会读取一次数据并添加一个计时器任务以定期更新您的应用程序的数据,它只会在计时器完成时偶尔更新数据,并且不会卡住你的ui

【讨论】:

我尝试过使用“addListenerForSingleValueEvent”,但没有任何改变。结果相同。 请检查您没有同时使用其他线程操作。 @jubinpatel 我对线程一无所知。请指导我。 发布您的整个活动。 @MohammedFarhan 这是整个活动,其余代码只是视图初始化。

以上是关于应用程序可能在 Andriod 中的主线程(Firebase 数据库)上做了太多工作的主要内容,如果未能解决你的问题,请参考以下文章

是否可以使用 VS2010 分析器对 C# 中的主线程以外的线程进行采样

“从您的主线程调用它可能会导致死锁和/或 ANR,同时从 GoogleAuthUtil(Android 中的 Google Plus 集成)获取 accessToken”

在 Python 中使用 PyQT 应用程序的主线程中的回调方法启动一个新线程

当 Cocoa 应用程序中的主线程被阻塞时,UI 不会更新

面试官问我:Andriod为什么不能在子线程更新UI?

面试官问我:Andriod为什么不能在子线程更新UI?