从服务器下载数据并将此数据同步添加到本地数据库

Downloading data from server and add this data to local database with sync

我正在开发我的应用程序,其中存储报价。 我从服务器下载的报价数据。 我想要用户下载 10 个报价(当时数据添加到本地数据库),如果他滚动这 10 个报价,将下载新数据(再次 10 个)。 例如,在 facebook 磁带中(将数据添加到本地数据库)。 但我还需要将本地数据库与服务器数据库同步。 我不明白如何将所有这些结合起来。

下载数据 - 这里我传递了从服务器db的id下载的id。

class DownloadAndParseJson extends AsyncTask<Integer, Void, ArrayList<QuoteObject>> {

    interface AsyncResponse {
        void processFinish(ArrayList<QuoteObject> output);
    }

    private AsyncResponse delegate = null;

    DownloadAndParseJson(AsyncResponse delegate){
        this.delegate = delegate;
    }

    private static final String TAG = "###" + "DownloadAndParseJson";

    @Override
    protected ArrayList<QuoteObject> doInBackground(Integer... params) {

        Log.i(TAG, "Starting download quotes from " + params[0] + " id");
        if (params.length == 0) {
            return null;
        }
        int id = params[0];

        HttpURLConnection urlConnection = null;
        BufferedReader reader = null;
        String countriesJsonStr = null;

        try {
            final String BASIC_URL = "http://*******.com";
            final String ID_PARAM = "id";

            Uri builtUri = Uri.parse(BASIC_URL).buildUpon()
                    .appendQueryParameter(ID_PARAM, Integer.toString(id))
                    .build();

            URL url = new URL(builtUri.toString());
            urlConnection = (HttpURLConnection) url.openConnection();
            urlConnection.setRequestMethod("GET");
            urlConnection.connect();

            InputStream inputStream = urlConnection.getInputStream();
            StringBuffer buffer = new StringBuffer();
            if (inputStream == null) {
                return null;
            }
            reader = new BufferedReader(new InputStreamReader(inputStream));

            String line;
            while ((line = reader.readLine()) != null) {
                buffer.append(line + "\n");
            }

            if (buffer.length() == 0) {
                return null;
            }
            countriesJsonStr = buffer.toString();
            Log.v(TAG, "download end");
        } catch (IOException e) {
            Log.e(TAG, "Error", e);
            return null;
        } finally {

            if (urlConnection != null) {
                urlConnection.disconnect();
            }
            if (reader != null) {
                try {
                    reader.close();
                } catch (final IOException e) {
                    Log.e(TAG, "Error", e);
                }
            }
        }

        Log.i(TAG, "End download quotes");
        return getArrayParsedJson(countriesJsonStr);
    }

    @Override
    protected void onPostExecute(ArrayList<QuoteObject> result) {
        Log.i(TAG, "Downloaded " + result.size() + " quotes");
        delegate.processFinish(result);
    }

    private  ArrayList<QuoteObject> getArrayParsedJson(String jsonStr){
        Gson gson = new Gson();
        Type collectionType = new TypeToken<ArrayList<QuoteObject>>(){}.getType();
        return gson.fromJson(jsonStr, collectionType);
    }
}

使用数据库 - 我在这里存储报价对象

public class RealmHelper {

    private static final String TAG = "###" + "RealmHelper";
    Context context;

    public RealmHelper(Context context) {
        this.context = context;
    }

    public void write(ArrayList<QuoteObject> quoteObjectArrayList) {

        Realm.init(context);
        Realm realm = Realm.getDefaultInstance();
        realm.beginTransaction();

        for (QuoteObject quoteObject : quoteObjectArrayList){
            realm.copyToRealm(quoteObject);
        }
        realm.commitTransaction();
    }

    public ArrayList<QuoteObject> read() {

        Realm.init(context);
        Realm realm = Realm.getDefaultInstance();

        return new ArrayList<>(realm.where(QuoteObject.class).findAll());
    }

    public void delete() {
        Realm.init(context);
        Realm realm = Realm.getDefaultInstance();
        final RealmResults<QuoteObject> countries = realm.where(QuoteObject.class).findAll();

        realm.executeTransaction(new Realm.Transaction() {
            @Override
            public void execute(Realm realm) {
                countries.deleteAllFromRealm();
                Log.i(TAG, "size = " + countries.size());
            }
        });
    }
}

MainActivity

public class MainActivity extends AppCompatActivity
       implements  DownloadAndParseJson.AsyncResponse{

        .
        .
    RVAdapter adapter;
    private ArrayList<QuoteObject> quoteObjectArrayList;
        .
        .

         protected void onCreate(){
       .
       .
       .
    RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
            recyclerView.setHasFixedSize(true);
            LinearLayoutManager layoutManager = new LinearLayoutManager(this);
            recyclerView.setLayoutManager(layoutManager);
            adapter = new RVAdapter(this, quoteObjectArrayList);
            recyclerView.setAdapter(adapter);
        }

        @Override
    public void processFinish(ArrayList<QuoteObject> output) {
        if (output.size() != 0) {
            quoteObjectArrayList = output;
            Log.i(TAG, "processFinish() returned outputArray size " + output.size());
        }   else
            Toast.makeText(this, "Not found quotes", Toast.LENGTH_SHORT).show();
    }

RecyclerView.Adapter - 要使用卡片视图显示报价。

class RVAdapter extends RecyclerView.Adapter<RVAdapter.PersonViewHolder>
     implements  DownloadAndParseJson.AsyncResponse{

    private static final String TAG = "###" + "RVAdapter";

    private Context context;
    private boolean hasMoreItems;
    private ArrayList<QuoteObject> quoteObjectArrayList;

    RVAdapter(Context context, ArrayList<QuoteObject> quoteObjectArrayList){
        this.context = context;
        this.hasMoreItems = true;
        this.quoteObjectArrayList = quoteObjectArrayList;

        Log.i(TAG, "quoteObjectArrayList = " + quoteObjectArrayList.size());

    }

    private void notifyNoMoreItems(){
        hasMoreItems = false;
        Toast.makeText(context, "No More Items", Toast.LENGTH_SHORT).show();
    }

    @Override
    public RVAdapter.PersonViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {

        View view = LayoutInflater.from(viewGroup.getContext())
                .inflate(R.layout.card_of_quote, viewGroup, false);

        return new PersonViewHolder(view);
    }

    @Override
    public void onBindViewHolder(final RVAdapter.PersonViewHolder holder, int position) {

        Log.i(TAG, "Card position = " + position);

        if (position == quoteObjectArrayList.size() && hasMoreItems){
            new DownloadAndParseJson(this).execute(Integer.parseInt(quoteObjectArrayList.get(position).getId()));
        }
        holder.contentOfQuote.setText(quoteObjectArrayList.get(position).getQuote());
        holder.authorQuote.setText(quoteObjectArrayList.get(position).getAuthor());

        holder.ratingBar.setOnRatingChangeListener(new MaterialRatingBar.OnRatingChangeListener() {
            @Override
            public void onRatingChanged(MaterialRatingBar ratingBar, float rating) {
                //ratingBar.setRight(Integer.parseInt(quoteObjectArrayList.get(position).getId()));
            }
        });

        holder.btnShareQuote.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                Intent sendIntent = new Intent();
                sendIntent.setAction(Intent.ACTION_SEND);
                sendIntent.putExtra(Intent.EXTRA_TEXT, holder.contentOfQuote.getText()
                                                + "\n" + holder.authorQuote.getText() );
                sendIntent.setType("text/plain");
                context.startActivity(sendIntent);
            }
        });

        holder.btnViewComment.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //View Comments
            }
        });

    }

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

    @Override
    public void processFinish(ArrayList<QuoteObject> output) {
        if (output.size() != 0) {
            quoteObjectArrayList.addAll(output);
            Log.i(TAG, "Total quoteArray Size = " + quoteObjectArrayList.size());
            new RealmHelper(context).write(output); // NEED separate throw
        } else notifyNoMoreItems();
    }

    static class PersonViewHolder extends RecyclerView.ViewHolder {

        CardView cardView;

        TextView contentOfQuote, authorQuote;

        MaterialRatingBar ratingBar;

        ImageButton btnViewComment, btnShareQuote;
        TextView rating;

        public PersonViewHolder(View itemView) {
            super(itemView);

            this.cardView = (CardView) itemView.findViewById(R.id.cardView);

            this.contentOfQuote = (TextView) itemView.findViewById(R.id.contentOfQuote);
            this.authorQuote = (TextView) itemView.findViewById(R.id.authorQuote);

            this.btnViewComment = (ImageButton) itemView.findViewById(R.id.btnViewComment);
            this.btnShareQuote = (ImageButton) itemView.findViewById(R.id.btnShareQuote);

            this.ratingBar = (MaterialRatingBar) itemView.findViewById(R.id.ratingBar);
            this.rating = (TextView) itemView.findViewById(R.id.txtRating);
        }
    }
}

现在我需要结合所有这些。

结果应该是:

  1. 从本地数据库的数据开始。
    • 如果没有数据 - 下载新的(10 个引号)。
    • 否则从本地数据库中获取数据,直到它们 运行 出来
  2. 从服务器bd下载10句名言,添加到本地并显示。 或者如果没有数据就打印出来吧。
  3. 将本地 bd 与服务器同步。

请帮帮我。

谢谢。

如果您按预期使用 RealmResults 以及 RealmChangeListener 和 Realm 的通知系统,这会容易得多。见 official documentation.

class DownloadAndParseJson extends AsyncTask<Integer, Void, Void> {
    DownloadAndParseJson(){
    }

    private static final String TAG = "###" + "DownloadAndParseJson";

    @Override
    protected Void doInBackground(Integer... params) {
        Log.i(TAG, "Starting download quotes from " + params[0] + " id");
        if (params.length == 0) {
            return null;
        }
        int id = params[0];
        try {
            final List<QuoteObject> quotes = retrofitService.getQuotes(id).execute().body();
            if(quotes == null) {
                throw new RuntimeException("Download failed");
            }
            try(Realm realm = Realm.getDefaultInstance()) {
                realm.executeTransaction(new Realm.Transaction() {
                    @Override
                    public void execute(Realm realm) {
                        realm.insert(quotes);
                    }
                });
            }
        } catch (Exception e) {
            Log.e(TAG, "Error", e);
            return null;
        } 
        Log.i(TAG, "End download quotes");
        return null;
    }

    @Override
    protected void onPostExecute(Void ignored) {
    }
}

class RVAdapter extends RealmRecyclerViewAdapter<QuoteObject, RVAdapter.PersonViewHolder> {
    private static final String TAG = "###" + "RVAdapter";

    RVAdapter(OrderedRealmCollection<QuoteObject> quotes) {
        super(quotes, true);
    }

    // onCreateViewHolder

    // onBindViewHolder

    // view holder
}

RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
adapter = new RVAdapter(realm.where(QuotesObject.class).findAll()); // <-- RealmResults
recyclerView.setAdapter(adapter);

和一些 "did download all" 类逻辑,尽管这需要更智能的错误处理;和 "is data being downloaded" 以便您在向下滚动时不会发送垃圾邮件请求。