【问题标题】:Recyclerview from SQLite displays empty page on first timeSQLite 的 Recyclerview 第一次显示空白页面
【发布时间】:2017-05-23 08:14:11
【问题描述】:

我正在尝试从异步任务中填充 recyclerview。在异步任务中,数据通过 API 调用获取并推送到 SQLite 表,然后从 SQLite 表填充列表。首次加载时列表无法显示。但是当我关闭应用程序并重新打开应用程序时,列表会填充。这是需要正确解决的一般问题还是我缺少其他东西?

public class KingsActivity extends AppCompatActivity {
    RecyclerView mRecyclerView;
    RecyclerView.Adapter mAdapter;
    RecyclerView.LayoutManager mLayoutManager;
    List<King> kingList=new ArrayList<King>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        Log.d("method_track","onCreate");
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //To avoid the load on the main thread
        new DownloadDataAsync().execute(this);


    }

    public class DownloadDataAsync extends AsyncTask<Context, Integer, Context> {

        @Override
        protected Context doInBackground(Context... ctx) {
            downloadData(ctx[0]);
            return ctx[0];
        }

        @Override
        protected void onProgressUpdate(Integer... progress) {
        }

        @Override
        protected void onPostExecute(Context result) {

            Log.d("method_track","PostExecute");
            Cursor kingsRows=DatabaseHelper.getInstance(result.getApplicationContext()).getData(DatabaseHelper.TABLE_WESTEROS_KINGS);
            kingsRows.moveToFirst();
            while(kingsRows.moveToNext()){
                String kingName=kingsRows.getString(kingsRows.getColumnIndex(DatabaseHelper.KEY_WESTEROS_KINGS_NAME));
                int battleCount=kingsRows.getInt(kingsRows.getColumnIndex(DatabaseHelper.KEY_WESTEROS_KINGS_BATTLE_COUNT));
                int rating=kingsRows.getInt(kingsRows.getColumnIndex(DatabaseHelper.KEY_WESTEROS_KINGS_RATING));
                kingList.add(new King(kingName,rating,battleCount));

            }
            kingsRows.close();


            mRecyclerView = (RecyclerView)findViewById(R.id.my_recycler_view);

            mLayoutManager = new LinearLayoutManager(result);
            mRecyclerView.setLayoutManager(mLayoutManager);
            mAdapter = new KingsAdapterRC(kingList,result);
            mRecyclerView.setAdapter(mAdapter);
            mAdapter.notifyDataSetChanged();
        }

        public void downloadData(final Context ctx){
            // Get a RequestQueue
            RequestQueue queue = HttpRequestHandler.getInstance(ctx.getApplicationContext()).
                    getRequestQueue();

            String url ="http://starlord.hackerearth.com/gotjson";
            // Request a string response from the provided URL.
            StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
                    new Response.Listener<String>() {
                        @Override
                        public void onResponse(String response) {
                            // Display the first 500 characters of the response string.
                            //Log.d("result_check",response.substring(0,500));

                            loadToDb(response,ctx);
                            populateList(ctx);
                            calculateRating(ctx);
                            logRatings(ctx);


                            //mTextView.setText("Response is: "+ response.substring(0,500));
                        }
                    }, new Response.ErrorListener() {
                @Override
                public void onErrorResponse(VolleyError error) {
                    Log.d("result_check","Error");
                    //mTextView.setText("That didn't work!");
                }
            });

            // Add a request to RequestQueue.
            HttpRequestHandler.getInstance(ctx).addToRequestQueue(stringRequest);
        }
        protected void loadToDb(String jsonResponse,Context ctx){
            DatabaseHelper.getInstance(ctx.getApplicationContext()).truncate(DatabaseHelper.TABLE_WESTEROS_DATA);
            try {
                JSONArray jsonArray = new JSONArray(jsonResponse);
                for(int i=0;i<jsonArray.length();i++){
                    JSONObject jsonObj = (JSONObject)jsonArray.get(i);
                    Iterator<String> iter = jsonObj.keys();
                    HashMap<String,String> fieldVales=new HashMap<String, String>();
                    while (iter.hasNext()) {
                        String key = iter.next();
                        try {
                            Object value = jsonObj.get(key);
                            fieldVales.put(key,value.toString());

                        } catch (JSONException e) {
                            // Something went wrong!
                            Log.e("loadTodb",e.toString());
                        }
                    }
                    DatabaseHelper.getInstance(ctx.getApplicationContext()).insert(DatabaseHelper.TABLE_WESTEROS_DATA,fieldVales);
                }

            } catch (Throwable t) {
                //Log.e("My App", "Could not parse malformed JSON: \"" + json + "\"");
            }
        }
        protected void populateList(Context ctx){
            List<King> kingList=new ArrayList<King>();
            String[] kings;
            int kingsCount=0;
            String sql="SELECT DISTINCT "+DatabaseHelper.KEY_WESTEROS_ATTACKER_KING+ " FROM "+ DatabaseHelper.TABLE_WESTEROS_DATA
                    +" WHERE "+ DatabaseHelper.KEY_WESTEROS_ATTACKER_KING +" <> ''";
            Cursor rows=DatabaseHelper.getInstance(ctx.getApplicationContext()).getReadableDatabase().rawQuery(sql, null);
            kingsCount+=rows.getCount();



            String sql2="SELECT DISTINCT "+DatabaseHelper.KEY_WESTEROS_DEFENDER_KING + " FROM "+ DatabaseHelper.TABLE_WESTEROS_DATA
                    + " WHERE "+ DatabaseHelper.KEY_WESTEROS_DEFENDER_KING + " NOT IN ( "+sql+ " ) AND "
                    + DatabaseHelper.KEY_WESTEROS_DEFENDER_KING +" <> ''";

            Cursor rows2=DatabaseHelper.getInstance(ctx.getApplicationContext()).getReadableDatabase().rawQuery(sql2, null);
            kingsCount+=rows2.getCount();

            kings=new String[kingsCount];
            int i=0;

            if (rows.moveToFirst()) {
                while (!rows.isAfterLast()) {
                    //your code to implement
                    kings[i]=rows.getString(rows.getColumnIndex(DatabaseHelper.KEY_WESTEROS_ATTACKER_KING));
                    i++;
                    rows.moveToNext();
                }
            }
            rows.close();

            if (rows2.moveToFirst()) {
                while (!rows2.isAfterLast()) {
                    //your code to implement
                    kings[i]=rows2.getString(rows2.getColumnIndex(DatabaseHelper.KEY_WESTEROS_DEFENDER_KING));
                    i++;
                    rows2.moveToNext();
                }
            }
            rows2.close();


            DatabaseHelper.getInstance(ctx.getApplicationContext()).truncate(DatabaseHelper.TABLE_WESTEROS_KINGS);
            for(i=0;i<kingsCount;i++){
                HashMap<String,String> fieldValues=new HashMap<String, String>();
                fieldValues.put(DatabaseHelper.KEY_WESTEROS_KINGS_NAME,kings[i]);
                fieldValues.put(DatabaseHelper.KEY_WESTEROS_KINGS_RATING,"400");
                fieldValues.put(DatabaseHelper.KEY_WESTEROS_KINGS_BATTLE_COUNT,"0");
                DatabaseHelper.getInstance(ctx.getApplicationContext()).insert(DatabaseHelper.TABLE_WESTEROS_KINGS,fieldValues);
            }
        }


        protected void calculateRating(Context ctx){
            Cursor battles_cur=DatabaseHelper.getInstance(ctx.getApplicationContext()).getData(DatabaseHelper.TABLE_WESTEROS_DATA);

            if(battles_cur.moveToFirst()){
                while(!battles_cur.isAfterLast()){
                    String attackingKing=battles_cur.getString(battles_cur.getColumnIndex(DatabaseHelper.KEY_WESTEROS_ATTACKER_KING));
                    String defendingKing=battles_cur.getString(battles_cur.getColumnIndex(DatabaseHelper.KEY_WESTEROS_DEFENDER_KING));


                    if(!attackingKing.equals("") && !defendingKing.equals("")){

                        HashMap<String,String> whereConDfk=new HashMap<String,String>();
                        whereConDfk.put(DatabaseHelper.KEY_WESTEROS_KINGS_NAME,defendingKing);
                        Cursor cursor1=DatabaseHelper.getInstance(ctx.getApplicationContext()).getData(DatabaseHelper.TABLE_WESTEROS_KINGS,whereConDfk);
                        double defKing_rating;
                        double defKing_battleCount;
                        if(cursor1.moveToFirst()){

                            defKing_rating=cursor1.getDouble(cursor1.getColumnIndex(DatabaseHelper.KEY_WESTEROS_KINGS_RATING));
                            defKing_battleCount=cursor1.getDouble(cursor1.getColumnIndex(DatabaseHelper.KEY_WESTEROS_KINGS_BATTLE_COUNT));
                            cursor1.close();

                            HashMap<String,String> whereConAtk=new HashMap<String,String>();
                            whereConAtk.put(DatabaseHelper.KEY_WESTEROS_KINGS_NAME,attackingKing);
                            Cursor cursor2=DatabaseHelper.getInstance(ctx.getApplicationContext()).getData(DatabaseHelper.TABLE_WESTEROS_KINGS,whereConAtk);
                            Double atkKing_rating;
                            Double atkKing_battleCount;
                            if(cursor2.moveToFirst()){

                                atkKing_rating=cursor2.getDouble(cursor2.getColumnIndex(DatabaseHelper.KEY_WESTEROS_KINGS_RATING));
                                atkKing_battleCount=cursor2.getDouble(cursor2.getColumnIndex(DatabaseHelper.KEY_WESTEROS_KINGS_BATTLE_COUNT));
                                cursor2.close();
                                atkKing_battleCount++;
                                defKing_battleCount++;

                                Double defKing_rating_tr=Math.pow(10,(defKing_rating/400));
                                Double atkKing_rating_tr=Math.pow(10,(atkKing_rating/400));

                                Double defKing_rating_ex=defKing_rating_tr/(defKing_rating_tr+atkKing_rating_tr);
                                Double atkKing_rating_ex=atkKing_rating_tr/(defKing_rating_tr+atkKing_rating_tr);

                                String attackerStatus=battles_cur.getString(battles_cur.getColumnIndex(DatabaseHelper.KEY_WESTEROS_ATTACKER_OUTCOME));

                                Double atkKing_rating_new=atkKing_rating;
                                Double defKing_rating_new=defKing_rating;
                                if(attackerStatus.equals("win")){
                                    atkKing_rating_new=atkKing_rating+(32*(1-atkKing_rating_ex));
                                    defKing_rating_new=defKing_rating+(32*(0-defKing_rating_ex));
                                }else if(attackerStatus.equals("loss")){
                                    atkKing_rating_new=atkKing_rating+(32*(0-atkKing_rating_ex));
                                    defKing_rating_new=defKing_rating+(32*(1-defKing_rating_ex));
                                }else if(attackerStatus.equals("draw")){
                                    atkKing_rating_new=atkKing_rating+(32*(0.5-atkKing_rating_ex));
                                    defKing_rating_new=defKing_rating+(32*(0.5-defKing_rating_ex));
                                }
                                String update_atkKing_ratingQuery="UPDATE "+ DatabaseHelper.TABLE_WESTEROS_KINGS + " SET "
                                        + DatabaseHelper.KEY_WESTEROS_KINGS_RATING+" = "+atkKing_rating_new+", "
                                        + DatabaseHelper.KEY_WESTEROS_KINGS_BATTLE_COUNT+" = "+atkKing_battleCount
                                        + " WHERE "+ DatabaseHelper.KEY_WESTEROS_KINGS_NAME +" =\""+attackingKing+"\"";

                                String update_defKing_ratingQuery="UPDATE "+ DatabaseHelper.TABLE_WESTEROS_KINGS + " SET "
                                        + DatabaseHelper.KEY_WESTEROS_KINGS_RATING+" = "+defKing_rating_new+", "
                                        + DatabaseHelper.KEY_WESTEROS_KINGS_BATTLE_COUNT+" = "+defKing_battleCount
                                        + " WHERE "+ DatabaseHelper.KEY_WESTEROS_KINGS_NAME +" =\""+defendingKing+"\"";

                                DatabaseHelper.getInstance(ctx.getApplicationContext()).getWritableDatabase().execSQL(update_atkKing_ratingQuery);
                                DatabaseHelper.getInstance(ctx.getApplicationContext()).getWritableDatabase().execSQL(update_defKing_ratingQuery);

                            }

                        }
                    }
                    battles_cur.moveToNext();
                }
            }

        }
        protected void logRatings(Context ctx){
            Log.d("method_track","logratings");
            Cursor kings_cur=DatabaseHelper.getInstance(ctx.getApplicationContext()).getData(DatabaseHelper.TABLE_WESTEROS_KINGS);
            try {
                while (kings_cur.moveToNext()) {

                    String name=kings_cur.getString(kings_cur.getColumnIndex(DatabaseHelper.KEY_WESTEROS_KINGS_NAME));
                    String rating=kings_cur.getString(kings_cur.getColumnIndex(DatabaseHelper.KEY_WESTEROS_KINGS_RATING));
                    String battleCount=kings_cur.getString(kings_cur.getColumnIndex(DatabaseHelper.KEY_WESTEROS_KINGS_BATTLE_COUNT));
                    //Log.d("method_track", "logratings");
                    Log.d("rating_inspect",name+" - "+rating+" - "+battleCount);

                }
            }finally {
                kings_cur.close();
            }

        }
    }



}

【问题讨论】:

  • 调试你的应用程序..它会第一次告诉你到底发生了什么......尝试删除 mAdapter.notifyDataSetChanged();
  • 不要在 onPostExecute 中初始化您的回收器视图,然后在调用异步任务之前执行此操作,并在从异步任务(即 onPostExecute 内部)获取列表后通过调用 notifyDataSetChange 更新适配器列表

标签: android sqlite android-asynctask


【解决方案1】:

这里:

downloadData(ctx[0]);

downloadData 方法引起的问题。

downloadData 方法中使用StringRequest 从服务器获取数据。 StringRequest 处理工作线程上的所有请求并使用Response.Listener 返回结果。

doInBackground 也完成了工作线程的所有工作。所以doInBackground 方法的工作线程只是执行downloadData 方法而不等待从StringRequest 得到响应。

使用StringRequest 时无需使用额外的线程。只需删除 AsyncTask 并仅使用 StringRequest 即可使其正常工作。

【讨论】:

  • 当我在没有异步任务的情况下使用时,我收到此消息I/Choreographer: Skipped 68 frames! The application may be doing too much work on its main thread.,这是由于方法calculateRating
  • @DharanBro:是的,这是可能的,因为您也在 onResponse 方法中执行其他操作。所以只需在onResponse 中使用`AsyncTask` 来做其他操作
  • @DharanBro:将您的代码安排为 StringRequest 请求 -> onResponse -> 运行 AsyncTask 以在 doInBackground 中调用 loadToDb(response,ctx); 方法并从 onPostExecute 调用 populateList(ctx);calculateRating(ctx);logRatings(ctx);
  • 这就是我对代码所做的混乱。现在它完美地工作了。它让我失去了我的夜晚。谢谢
【解决方案2】:

你不应该从doInBackground 调用volley StringRequest,因为async task 立即执行post execute 方法,您的列表将是空的,因此它不会显示任何数据。只需使用string request 并在获得响应后将其保存在您的“数据库”中并从那里获取(您可以直接从database 保存和获取数据或使用异步任务)。

不要只使用StringRequest 而不使用任何async task 并对其进行测试。

【讨论】:

    猜你喜欢
    • 2014-04-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多