【问题标题】:Refresh RecyclerView in realtime after adding new data to sqLite向 sqLite 添加新数据后实时刷新 RecyclerView
【发布时间】:2017-07-14 08:10:20
【问题描述】:

每次 SQLite 获取新数据时,我都会尝试使用 recyclerview 刷新活动(实际上 SQLite 从 TCP 客户端信号获取数据) 这是我的 RecyclerView 代码:

public static class ViewHolder extends RecyclerView.ViewHolder{
    public TextView data_txt;
    public TextView text_txt;
    public TextView ora_txt;
    public ImageView img;

    public ViewHolder(final View itemView) {
        super(itemView);

        data_txt = itemView.findViewById(R.id.Data);
        ora_txt = itemView.findViewById(R.id.Ora);
        text_txt = itemView.findViewById(R.id.Errore);
        img = itemView.findViewById(R.id.error_photo);
    }

}
private List<Adapter> mText;

public RecyclerViewAdapter(Context c,List<Adapter> testo) {
    this.c = c;
    mText = testo;

}


@Override
public RecyclerViewAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View contactView = LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_blueprint, parent, false);
    return new ViewHolder(contactView);
}

@Override
public void onBindViewHolder(RecyclerViewAdapter.ViewHolder viewHolder, int position) {
    Adapter adapter = mText.get(position);

    TextView mData = viewHolder.data_txt;
    mData.setText(adapter.getDataText());

    TextView mOra = viewHolder.ora_txt;
    mOra.setText(adapter.getOraText());

    TextView mTesto = viewHolder.text_txt;
    mTesto.setText(adapter.getTesto());

    ImageView mImg = viewHolder.img;
    mImg.setImageBitmap(adapter.getImage());
}

@Override
public int getItemCount() {
    return mText.size();
}

public void removeItem(int position) {

    Adapter a = mText.get(position);
    int id=a.getId();

     DataBaseHandler myDB;
     myDB = DataBaseHandler.getInstance(c);
    myDB.openDB();
    if(myDB.delete(id))
    {
        mText.remove(position);
    }else
    {
        Toast.makeText(c,"Unable To Delete", Toast.LENGTH_SHORT).show();
    }
    myDB.closeDB();
    this.notifyDataSetChanged();
}

当我尝试使用RecyclerViewAdapter.notifyDataSetChanged(); 更新 RecyclerView 时,TCP 服务器获取的数据因错误而崩溃:

java.lang.NullPointerException: Attempt to invoke virtual method 'void com.example.sguidetti.selfmanegment.RecyclerViewAdapter.notifyDataSetChanged()' on a null object reference

编辑: 这是我在 TCP 服务器类中调用 notifyDataSetChande() 的代码:

    Vibrator vibrator;
    String date,ora;
    long[] pattern = {0, 1000, 500, 1000, 500, 1000};

    int lun;

    @Override
    public void run() {
        InputStream leggi;
        try {


            serverSocket = new ServerSocket(socketServerPORT);

            while (true) {
                myDB = DataBaseHandler.getInstance(activity);

                Socket socket = serverSocket.accept();
                leggi = socket.getInputStream();
                byte[] data = new byte[1000];
                lun = leggi.read(data, 0, data.length);
                letto = new String(data, "UTF-8");
                count++;
                MediaPlayer mPlay = MediaPlayer.create(activity, R.raw.gabsuono);
                mPlay.start();

                vibrator = (Vibrator) activity.getSystemService(VIBRATOR_SERVICE);
                vibrator.vibrate(pattern, -1);

                date = new SimpleDateFormat("dd-MM-yyyy").format(new Date());
                ora = new SimpleDateFormat("HH:mm:ss").format(new Date());



                myDB.insertDataServer(date, ora, letto);

                adapterView.notifyDataSetChanged();

                activity.runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        prefs = activity.getSharedPreferences("MY_DATA", MODE_PRIVATE);
                        SharedPreferences.Editor edit = prefs.edit();
                        edit.putInt("counter", count);
                        edit.commit();
                        activity.msg.setText(String.valueOf(count));
                        activity.msg.setVisibility(View.VISIBLE);

                    }
                });
                leggi.close();


            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();

        }

这是我调用 RecyclerView 的活动:

DataBaseHandler myDB;
RecyclerView recyclerView;
RecyclerViewAdapter adapterView;
ImageButton home;
String IMGSTRING;
Adapter adapter;
List<Adapter> textList;
private Paint p = new Paint();


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_allert);
    Utils.darkenStatusBar(this, R.color.colorAccent);
    myDB = DataBaseHandler.getInstance(this);
    home = (ImageButton) findViewById(R.id.casa);
    recyclerView = (RecyclerView) findViewById(R.id.recyclerview);
    Bitmap img;
    img = BitmapFactory.decodeResource(getResources(), R.drawable.allert);
    Cursor data = myDB.fetchDataServer();
    textList = new ArrayList<>();
    int cont = 0;
    if (data.getCount() != 0) {
        while (data.moveToNext()) {


            IMGSTRING = data.getString(3).substring(0, 3);


            switch (IMGSTRING) {
                case "X00":
                    img = BitmapFactory.decodeResource(getResources(), R.drawable.allert);
                    break;
                case "E01":
                    img = BitmapFactory.decodeResource(getResources(), R.drawable.e01);
                    break;
                case "E02":
                    img = BitmapFactory.decodeResource(getResources(), R.drawable.e02);
                    break;
                case "E03":
                    img = BitmapFactory.decodeResource(getResources(), R.drawable.e03);
                    break;
                case "E90":
                    img = BitmapFactory.decodeResource(getResources(), R.drawable.e90);
                    break;
                case "E04":
                    img = BitmapFactory.decodeResource(getResources(), R.drawable.e04);
                    break;
                case "E05":
                    img = BitmapFactory.decodeResource(getResources(), R.drawable.e04);
                    break;
                case "E06":
                    img = BitmapFactory.decodeResource(getResources(), R.drawable.e04);
                    break;
            }


            adapter = new Adapter(data.getInt(0), data.getString(1), data.getString(2), data.getString(3).substring(3), img);   // 1 = time 2 = data 3 = text


            textList.add(cont, adapter);
            cont++;

        }
        RecyclerViewAdapter recycler = new RecyclerViewAdapter(this, textList);
        recyclerView.setAdapter(recycler);
        recyclerView.setLayoutManager((new LinearLayoutManager(this)));
    } else {
        Toast.makeText(allert.this, "NESSUN MESSAGGIO DA VISUALIZZARE!", Toast.LENGTH_LONG).show();
    }
    adapterView = new RecyclerViewAdapter(this, textList);
    recyclerView.setAdapter(adapterView);
    adapterView.notifyDataSetChanged();
    initSwipe();
    home.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            finish();
        }
    });
}

private void initSwipe() {
    ItemTouchHelper.SimpleCallback simpleItemTouchCallback = new ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT) {

        @Override
        public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
            return false;
        }

        @Override
        public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
            int position = viewHolder.getAdapterPosition();
            adapterView.removeItem(position);


        }

        @Override
        public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {

            Bitmap icon;
            if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) {

                View itemView = viewHolder.itemView;
                float height = (float) itemView.getBottom() - (float) itemView.getTop();
                float width = height / 3;

                p.setColor(Color.parseColor("#D32F2F"));
                RectF background = new RectF((float) itemView.getRight() + dX, (float) itemView.getTop(), (float) itemView.getRight(), (float) itemView.getBottom() - 10);
                c.drawRect(background, p);
                icon = BitmapFactory.decodeResource(getResources(), R.drawable.ic_delete_white);
                RectF icon_dest = new RectF((float) itemView.getRight() - 2 * width, (float) itemView.getTop() + width, (float) itemView.getRight() - width, (float) itemView.getBottom() - width);
                c.drawBitmap(icon, null, icon_dest, p);

            }
            super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
        }
    };
    ItemTouchHelper itemTouchHelper = new ItemTouchHelper(simpleItemTouchCallback);
    itemTouchHelper.attachToRecyclerView(recyclerView);
}

【问题讨论】:

  • 从您使用 RecyclerView 的 Fragment 调用 notifyDataSetChanged
  • 你从哪里调用“notifyDataSetChanged()”?您需要确保您对适配器的引用不为空。我会调查拨打电话的地点。
  • 布局中还有一个 notifyDataSetChange 我使用它但仍然不起作用,我的意思是当我在该活动中更新新的 RecyclerView 消息时,我必须退出该活动并进入再说一遍。 (对不起我的英语不好)
  • ViewHolder.notiftyDataSetChanged()
  • @paligap 我从 TCP 服务器活动中调用它,我的意思是在发送 TCP 客户端信号后,recyclerView 必须刷新。

标签: java android sqlite android-recyclerview android-sqlite


【解决方案1】:

你能在这里做一个空检查吗?

@Override
public int getItemCount() {
    return mText != null ? mText.size() : 0;
}

我对原因的最佳猜测是当 mText 仍然为空时调用 notifyDataSetChanged()。调用 notifyDataSetChanged() 时,将首先调用 getItemCount() 来检查列表中的当前位置是否在“mText”列表的大小范围内,但由于 mText 为 null,它会崩溃。

您可以在 removeItem() 方法上改进两点:

  1. 不要调用 this.notifyDataSetChanged(),而是调用 this.notifyItemRemoved(position),因为 onBindViewHolder() 不会被调用 n 次(n = 当前在 RecyclerView 中可见的行数)
  2. 不要将您的数据库代码与您的 UI 代码混用。您的 RecyclerView.Adapter 类应该只关注 UI 逻辑和 UI 状态对象(在本例中为 mText)。换句话说,

    public void removeItem(int position) {
        mText.remove(position);
        this.notifyItemRemoved(position);
    }
    

在您的 MainActivity 类中,除了您的数据库代码之外,还调用 removeItem()。

【讨论】:

  • 是的,实际上 RecyclerViewAdapter 和 Adapter 中的 mText 为空,这将填充另一个从数据库获取数据的活动,我该如何解决?因为我实际上需要将该 mText 初始化为空...
  • 也许有一个异步回调并且只在回调的成功方法中调用 this.notifyDataSetChanged() ? (当然是在将数据传递给 mText 之前)
【解决方案2】:

在调用 notifyDataSetChanged() 方法之前,您需要确保适配器已初始化。另一种方法是在适配器类中添加一个方法,您可以在其中传递 ArrayList 并调用 notifyDataSetChanged() ;

【讨论】:

  • 你能举一个ArrayList的例子吗?
  • /** * 适配器中的方法添加从数据库接收到的最新通知。 * @param notificationsArrayList */ public void updateAdapter(List notificationsArrayList){ try { Logger.logd("Size " ,notificationsList.size()+"");通知列表.addAll(notificationsArrayList); notifyDataSetChanged(); } 捕捉(异常 e){ e.printStackTrace();在活动中添加这个。 notifyListRecycleAdapter.updateAdapter(notificationsList);
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-05-19
  • 2021-11-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多