同步Web服务手册后RecyclerView不刷新

时间:2019-07-14 03:53:32

标签: java android android-recyclerview

我在手动同步Web服务后,RecyclerView出现问题,无法刷新。 通过在列表上向下滑动或点击ActionBar项来触发手动同步。 手动同步使用Volley Request来检索JSON格式的数据,然后将数据解析并保存到SQLite数据库表中。同步日期时间也会保存到SQLite数据库表中,并随后显示在Fragment的ActionBar字幕中。排球请求是通过WorkManager OneTimeWorkRequest发起的。

问题是RecyclerView列表未刷新。但是,如果我随后触发另一个手动同步,则将更新ActionBar字幕和RecyclerView内容中的同步数据时间,但会使用以前的手动同步中的数据。如果我从应用程序导航到设备的主屏幕,然后导航回到我的应用程序,这将变得很清楚,该应用程序现在显示来自最新手动同步的刷新数据。

我查看了有关此问题的大量文章(请参阅下文),尽管我认为我已经改进了代码,但没有推荐的解决方案可以解决此问题。

Recyclerview not call onCreateViewHolder RecyclerView not calling onCreateViewHolder or onBindView Recyclerview not call onCreateViewHolder RecyclerView is not refreshing

get JSON data from web and display using RecyclerView Recycler View appear blank and doesn't show SQLite data

RecyclerView onClick not working properly? Why doesn't RecyclerView have onItemClickListener()?

ListView not updating after web service Sync

查看了其他资源: https://www.mytrendin.com/display-data-recyclerview-using-sqlitecursor-in-android/ https://medium.com/@studymongolian/updating-data-in-an-android-recyclerview-842e56adbfd8 https://www.youtube.com/watch?v=ObU-wCqoo2I https://www.youtube.com/watch?v=_0C18cbv6UE

因此,在几个月后尝试解决此问题之后,我现在向StackOverflow社区寻求帮助。

片段


    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_warning_list, container, false);

        mSwipeRefreshLayout = (SwipeRefreshLayout) view.findViewById(R.id.warning_swipe_refresh_layout);

        /* Set the Refresh Listener for the Swipe gesture */
        mSwipeRefreshLayout.setOnRefreshListener(
                new SwipeRefreshLayout.OnRefreshListener() {
                    @Override
                    public void onRefresh() {
                        SyncWarningsScheduler.oneTime();
                        updateUI();
                    }
                }
        );

        mWarningRecyclerView = (RecyclerView) view.findViewById(R.id.warning_recycler_view);

        /* Set the Toolbar to replace the default ActionBar, which has been hidden */
        if (mActivity != null) {
            Toolbar toolbar = (Toolbar) mActivity.findViewById(R.id.toolbar_abstract_single_fragment);
            mActivity.setSupportActionBar(toolbar);

            /* Set the toolbar title */
            ActionBar actionbar = mActivity.getSupportActionBar();
            if (actionbar != null) {
                actionbar.setDisplayHomeAsUpEnabled(true);
                actionbar.setTitle(getString(R.string.warning_list_fragment_toolbar_title));
            }
        }

        updateUI();
        return view;
    }


    @Override
    public void onResume() {
        super.onResume();
        updateUI();
    }


    @Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        super.onCreateOptionsMenu(menu, inflater);
        inflater.inflate(R.menu.fragment_warning_list, menu);
    }


    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.sync:
                mSwipeRefreshLayout.setRefreshing(true);
                SyncWarningsScheduler.oneTime();
                updateUI();

                return true;
            case R.id.information:
                /* Handle the Information Menu Item */
                FragmentManager fm = getFragmentManager();
                if (fm != null) {
                    WarningListFragmentTFBInformationDialogFragment dialog = new WarningListFragmentTFBInformationDialogFragment();
                    dialog.show(fm, TFB_INFO_DIALOG_TAG);
                }
                return true;
            default:
                return super.onOptionsItemSelected(item);
        }
    }


    private void updateUI() {
        WarningList warningList = WarningList.get(mActivity);
        List<Warning> warnings = warningList.getWarnings();

        if (mWarningAdaptor == null) {
            mWarningAdaptor = new WarningAdaptor(warnings);
            mWarningRecyclerView.setLayoutManager(new LinearLayoutManager(mContext));
            mWarningRecyclerView.setAdapter(mWarningAdaptor);
        } else {
            mWarningAdaptor.setWarnings(warnings);
            mWarningAdaptor.notifyDataSetChanged();
        }

        /* Update the ToolBar sub title to show the latest sync datetime */
        updateToolBarSubTitle();

        /* If visible, turn off the Swipe Refresh Progress Circle */
        if (mSwipeRefreshLayout != null && mSwipeRefreshLayout.isRefreshing()) {
            mSwipeRefreshLayout.setRefreshing(false);
        }
    }


    private void updateToolBarSubTitle() {
        SyncInformationList syncInformationList = SyncInformationList.get(mContext);
        Date syncDate = syncInformationList.getSyncDatetime(ORMSync.getWarningSyncTypeKey());

        ActionBar actionBar = mActivity.getSupportActionBar();
        if (actionBar != null) {
            actionBar.setSubtitle(DatabaseUtilities.formatDateSpecial(syncDate, true));
        }
    }


    private class WarningHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
        private Warning mWarning;
        private TextView mIssueForTextView;
        private TextView mDeclarationTextView;
        private View mStatusWarningViewLeft;
        private View mStatusWarningViewRight;

        public WarningHolder(LayoutInflater inflater, ViewGroup parent) {
            super(inflater.inflate(R.layout.list_item_warning, parent, false));
            /* Handlers a user press on a Warning */
            itemView.setOnClickListener(this);

            mIssueForTextView = (TextView) itemView.findViewById(R.id.issueFor_textView);
            mDeclarationTextView = (TextView) itemView.findViewById(R.id.declaration_textView);
            mStatusWarningViewLeft = (View) itemView.findViewById(R.id.status_warning_left);
            mStatusWarningViewRight = (View) itemView.findViewById(R.id.status_warning_right);
        }

        public void bind(Warning warning) {
            mWarning = warning;
            String issueForDate;

            issueForDate = DatabaseUtilities.formatDateSpecial(mWarning.getIssuedFor(), "d MMM yyyy");
            mIssueForTextView.setText(issueForDate);

            mDeclarationTextView.setText(mWarning.getTfbDeclaration());
            /* Set Declaration text colour */
            if (mWarning.isTfbStatus()) {
                /* If the day is a TFB set text color to Red */
                mIssueForTextView.setTextColor(getResources().getColor(R.color.red));
                mDeclarationTextView.setTextColor(getResources().getColor(R.color.red));
            }

            /* Set left and right status warning colour based on TFB status */
            mStatusWarningViewLeft.setBackgroundResource(mWarning.setStatusWarningColor());
            mStatusWarningViewRight.setBackgroundResource(mWarning.setStatusWarningColor());
        }

        @Override
        public void onClick(View v) {
            /* Process onClick */
            Intent intent = WarningPagerActivity.newIntent(mActivity, mWarning.getUID());
            startActivity(intent);
        }
    }


    private class WarningAdaptor extends RecyclerView.Adapter<WarningHolder> {
        private List<Warning> mWarnings;

        public WarningAdaptor(List<Warning> warnings) {
            mWarnings = warnings;
        }

        @NonNull
        @Override
        public WarningHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
            LayoutInflater layoutInflater = LayoutInflater.from(mActivity);
            return new WarningHolder(layoutInflater, parent);
        }

        @Override
        public void onBindViewHolder(@NonNull WarningHolder holder, int position) {
            /* Bind data */
            Warning warning = mWarnings.get(position);
            holder.bind(warning);
        }

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

        public void setWarnings(List<Warning> warnings) {
            mWarnings.clear();
            mWarnings = warnings;
        }

        public List<Warning> getWarnings() {
            return mWarnings;
        }
    }
}

WorkManager oneTimeWorkRequest计划程序

public class SyncWarningsScheduler {
    private static final String TAG = "SyncWarningsScheduler";
    private static final String ONE_TIME_WORK_REQUEST = "OneTime";
    private static final String ONE_TIME_WORK_REQUEST_TAG = TAG + ONE_TIME_WORK_REQUEST;
    private static final String ONE_TIME_WORK_REQUEST_TAG_UNIQUE = ONE_TIME_WORK_REQUEST_TAG + "Unique";


    /* Getters and Setters */
    public static String getOneTimeWorkRequestTagUnique() {
        return ONE_TIME_WORK_REQUEST_TAG_UNIQUE;
    }

    public static void oneTime() {
        WorkManager workManager = WorkManager.getInstance();

        /* Create a Constraints object that defines when and how the task should run */
        Constraints constraints = new Constraints.Builder()
                .setRequiresCharging(false)
                .setRequiredNetworkType(NetworkType.CONNECTED)
                .build();

        /* Build the Input Data to pass to the Worker */
        Data inputData = new Data.Builder()
                .putString(SyncWarningsWorker.getWorkRequestTypeKey(), ONE_TIME_WORK_REQUEST)
                .build();

        /* Build the One Time Work Request */
        OneTimeWorkRequest oneTimeWorkRequest = new OneTimeWorkRequest.Builder(SyncWarningsWorker.class)
                .setConstraints(constraints)
                /* Sets the input data for the ListenableWorker */
                .setInputData(inputData)
                .addTag(ONE_TIME_WORK_REQUEST_TAG)
                .build();

        workManager.enqueueUniqueWork(ONE_TIME_WORK_REQUEST_TAG_UNIQUE, ExistingWorkPolicy.REPLACE, oneTimeWorkRequest);
    }
}

WorkManager Worker

public class SyncWarningsWorker extends Worker {
    private static final String TAG = "SyncWarningsWorker";
    private Context mContext;
    private SQLiteDatabase mDatabase;
    private WarningList mWarningList;

    private static final String WORK_REQUEST_TYPE_KEY = "warningworkrequesttype";
    private static final String SYNC_DATE_TIME_KEY = "warningsyncdatetime";

    public SyncWarningsWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) {
        super(context, workerParams);

        /* Set the Context which must be the Application Context */
        mContext = context;

        mDatabase = IncidentsDatabaseHelper.get(context).getWritableDatabase();
        /* Get a refer to the WarningList Singleton */
        mWarningList = WarningList.get(context);
    }

    /* Getters and Setters */
    public static String getWorkRequestTypeKey() {
        return WORK_REQUEST_TYPE_KEY;
    }

    public static String getSyncDateTimeKey() {
        return SYNC_DATE_TIME_KEY;
    }


    @NonNull
    @Override
    public Result doWork() {
        /* Read passed-in argument(s) */
        String workRequestType = getInputData().getString(WORK_REQUEST_TYPE_KEY);
        LogUtilities.info(TAG, "doWork() - Processing EMV Warnings Work Request Type: " + workRequestType);

        try {
            downloadWarnings();

            Date now = new Date();
            long nowMilliSeconds = now.getTime();
            now.setTime(nowMilliSeconds);

            /* Update the WarningSyncType in SyncInformationList with the Warnings Sync Datetime */
            SyncInformationList syncInformationList = SyncInformationList.get(mContext);
            syncInformationList.updateSyncDatetime(ORMSync.getWarningSyncTypeKey(), now);

            Data syncDateTime = new Data.Builder()
                    .putLong(SYNC_DATE_TIME_KEY, nowMilliSeconds)
                    .build();

            return Result.success(syncDateTime);
        } catch (Exception e){
            LogUtilities.error(TAG, "doWork() - Can't download EMV Warnings data.\n\n" + e.toString());
            return Result.failure();
        }
    }

    private void downloadWarnings() {
        VolleyRequestQueue volleyRequestQueue;

        StringRequest request = new StringRequest(Request.Method.GET, JSONWarningsSchema.getTfbFdrJsonEndPoint(), onPostsLoaded, onPostsError);

        volleyRequestQueue = VolleyRequestQueue.get(mContext);

        volleyRequestQueue.addToVolleyRequestQueue(request);
    }

    private final Response.Listener<String> onPostsLoaded = new Response.Listener<String>() {
        ContentValues contentvalues;
        String noData = "NO DATA";

        @Override
        public void onResponse(String response) {
            /* Delete all the Warning records from the SQLite table */
            mWarningList.deleteAllWarnings();

            try {
                JSONObject jsonBody = new JSONObject(response);
                /* Within jsonBody is one nested JSON Array */
                JSONArray jsonArrayResults = jsonBody.getJSONArray(JSONWarningsSchema.getJsonRootArrayName());

                for (int i = 0; i < jsonArrayResults.length(); i++) {
                    /*
                     * Within jsonArrayResults are 10 sometimes 9 JSON Objects, the first 5 Objects are for TFB declarations and
                     * the last 5 (4) Objects are for FDR declarations.
                     */
                    JSONObject warningMetadata = jsonArrayResults.getJSONObject(i);

                    if (i < 5) {
                        /*
                         * The first 5 Objects are for Today and the next 4 days worth of TFB declarations. The TFB declaration in these Objects are
                         * used to INSERT new records into the warnings table using the issueFor date as the Alternate Primary Key.
                         * The FDR declarations for each day are defaulted to "NO DATA" to cater for the sometimes missing FDR data on the 5th day, this is
                         * to avoid null pointer errors when displaying the data in fragment_warning.
                         */
                        Warning warning = new Warning();

                        String issueForDate = warningMetadata.getString(JSONWarningsSchema.Keys.getIssueFor());
                        warning.setIssuedFor(JSONUtilities.stringToDate(issueForDate, JSONWarningsSchema.getJsonIssueForDateFormat()));

                        String status = warningMetadata.getString(JSONWarningsSchema.Keys.getStatus());
                        warning.setTfbStatus(JSONUtilities.stringToBoolean(status));

                        warning.setTfbDeclaration(warningMetadata.getString(JSONWarningsSchema.Keys.getDeclaration()));

                        /*
                         * Within the warningMetadata JSONObject is a JSONArray called declareList. Need to get the Array and
                         * iterate through the Array to extract the TFB warning for each District for this day.
                         * We know the exact number of JSONObjects in the declareList Array (ie an Object for each District).
                         */
                        JSONArray jsonArrayTFBDeclareList = warningMetadata.getJSONArray(JSONWarningsSchema.getJsonDeclareListArrayName());

                        /* Iterate through the TFB declareList Array */
                        for (int j = 0; j < jsonArrayTFBDeclareList.length(); j++) {
                            /* Get the JSON Object within the jsonArrayDeclareList Array */
                            JSONObject declareListMetadata = jsonArrayTFBDeclareList.getJSONObject(j);

                            /* Get the name and status pairs from the declareListMetadata Object */
                            String name = declareListMetadata.getString(JSONWarningsSchema.Keys.getDeclareListName());
                            String declareListStatus = declareListMetadata.getString(JSONWarningsSchema.Keys.getDeclareListStatus());

                            switch (name) {
                                case "Mallee":
                                    warning.setTfbMallee(declareListStatus);
                                    warning.setFdrMallee(noData);
                                    break;
                                case "Wimmera":
                                    warning.setTfbWimmera(declareListStatus);
                                    warning.setFdrWimmera(noData);
                                    break;
                                case "South West":
                                    warning.setTfbSouthWest(declareListStatus);
                                    warning.setFdrSouthWest(noData);
                                    break;
                                case "Northern Country":
                                    warning.setTfbNorthernCountry(declareListStatus);
                                    warning.setFdrNorthernCountry(noData);
                                    break;
                                case "North Central":
                                    warning.setTfbNorthCentral(declareListStatus);
                                    warning.setFdrNorthCentral(noData);
                                    break;
                                case "Central":
                                    warning.setTfbCentral(declareListStatus);
                                    warning.setFdrCentral(noData);
                                    break;
                                case "North East":
                                    warning.setTfbNorthEast(declareListStatus);
                                    warning.setFdrNorthEast(noData);
                                    break;
                                case "West and South Gippsland":
                                    warning.setTfbWestAndSouthGippsland(declareListStatus);
                                    warning.setFdrWestAndSouthGippsland(noData);
                                    break;
                                case "East Gippsland":
                                    warning.setTfbEastGippsland(declareListStatus);
                                    warning.setFdrEastGippsland(noData);
                                    break;
                                default:
                                    break;
                            } 
                        } 

                        contentvalues = ContentValueUtilities.getWarningListContentValues(warning, true);

                        mDatabase.beginTransaction();
                        try {
                            mDatabase.insert(ORMWarnings.getTableName(), null, contentvalues);
                            mDatabase.setTransactionSuccessful();
                        } catch (SQLiteException e) {
                            LogUtilities.error(TAG, "onPostsLoaded > onResponse - ERROR Inserting record into the '" + ORMWarnings.getTableName() + "' Table.\n\n" + e.toString());
                        } finally {
                            mDatabase.endTransaction();
                        } 
                    } else {
                        /*
                         * The last 5 or sometimes 4 Objects are for Today and the next 4 days worth of FDR declarations. The FDR declarations
                         * in these Objects are used to UPDATE FDR attributes in the warnings table using the issueFor date to find the existing warnings
                         * record.
                         */
                        String issueForFDR = warningMetadata.getString(JSONWarningsSchema.Keys.getIssueFor());
                        /* Ensure the retrieved issueFor date string is converted consistently */
                        Date issueForFDRDate = JSONUtilities.stringToDate(issueForFDR, JSONWarningsSchema.getJsonIssueForDateFormat());

                        /* Find the record in the warnings table by using the issueForFDRDate date. */
                        Warning warningExists = mWarningList.getWarning(issueForFDRDate);

                        /* Make sure a warning record has been returned */
                        if (warningExists != null) {
                            String issueAtDate = warningMetadata.getString(JSONWarningsSchema.Keys.getIssueAt());
                            warningExists.setFdrIssuedAt(JSONUtilities.stringToDate(issueAtDate, JSONWarningsSchema.getJsonIssueAtDateFormat()));

                            /*
                             * Within the warningMetadata JSONObject is a JSONArray called declareList. Need to get the Array and
                             * iterate through the Array to extract the FDR warning for each District for this day.
                             * We know the exact number of JSONObjects in the declareList Array (ie an Object for each District).
                             */
                            JSONArray jsonArrayFDRDeclareList = warningMetadata.getJSONArray(JSONWarningsSchema.getJsonDeclareListArrayName());

                            /* Iterate through the FDR declareList Array */
                            for (int z = 0; z < jsonArrayFDRDeclareList.length(); z++) {
                                /* Get the JSON Object within the jsonArrayFDRDeclareList Array */
                                JSONObject declareListMetadataFDR = jsonArrayFDRDeclareList.getJSONObject(z);

                                /* Get the name and status pairs from the declareListMetadataFDR Object */
                                String nameFDR = declareListMetadataFDR.getString(JSONWarningsSchema.Keys.getDeclareListName());
                                String declareListStatusFDR = declareListMetadataFDR.getString(JSONWarningsSchema.Keys.getDeclareListStatus());

                                switch (nameFDR) {
                                    case "Mallee":
                                        warningExists.setFdrMallee(declareListStatusFDR);
                                        break;
                                    case "Wimmera":
                                        warningExists.setFdrWimmera(declareListStatusFDR);
                                        break;
                                    case "South West":
                                        warningExists.setFdrSouthWest(declareListStatusFDR);
                                        break;
                                    case "Northern Country":
                                        warningExists.setFdrNorthernCountry(declareListStatusFDR);
                                        break;
                                    case "North Central":
                                        warningExists.setFdrNorthCentral(declareListStatusFDR);
                                        break;
                                    case "Central":
                                        warningExists.setFdrCentral(declareListStatusFDR);
                                        break;
                                    case "North East":
                                        warningExists.setFdrNorthEast(declareListStatusFDR);
                                        break;
                                    case "West and South Gippsland":
                                        warningExists.setFdrWestAndSouthGippsland(declareListStatusFDR);
                                        break;
                                    case "East Gippsland":
                                        warningExists.setFdrEastGippsland(declareListStatusFDR);
                                        break;
                                    default:
                                        break;
                                } 
                            }

                            contentvalues = ContentValueUtilities.getWarningListContentValues(warningExists, false);

                            mDatabase.beginTransaction();
                            try {
                                mDatabase.update(ORMWarnings.getTableName(), contentvalues, ORMWarnings.getUUIDColumn() + " = ?", new String[] {warningExists.getUID().toString()});
                                mDatabase.setTransactionSuccessful();
                            } catch (SQLiteException e) {
                                LogUtilities.error(TAG, "onPostsLoaded > onResponse - ERROR Updating record in the '" + ORMWarnings.getTableName() + "' Table.\n\n" + e.toString());
                            } finally {
                                mDatabase.endTransaction();
                            }
                        } else {
                            /* Something went wrong can't find warning record using the issueForFDRDate date */
                            LogUtilities.wtf(TAG, "onPostsLoaded > onResponse - " + issueForFDRDate.toString() + " warning record not found.\n\n");
                        } 
                    }
                }
            } catch (JSONException e) {
                LogUtilities.error(TAG, "onPostsLoaded > onResponse - Failed to Parse JSON body.\n\n" + e.toString());
            }
        }
    };


    private final Response.ErrorListener onPostsError = new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError error) {
            LogUtilities.error(TAG, "onPostsError > onErrorResponse - Failed to download JSON body.\n\n" + error.toString());
        }
    }; 
} 

2 个答案:

答案 0 :(得分:0)

在适配器中使用它

 public void setWarnings(List<Warning> warnings) {
        mWarnings.clear();
        mWarnings = warnings;
        notifyDataSetChanged();

    }

答案 1 :(得分:0)

我认为您要updateUI();成功调用api之后进行方法调用,因为api调用在后台运行时有效。 要么 您可以设置

sleep(5000)
updateUI();