【问题标题】:ArrayList not populated correctly from AsyncTaskArrayList 未从 AsyncTask 正确填充
【发布时间】:2012-10-09 13:23:38
【问题描述】:

我有一个从网络服务填充ArrayList 的应用程序。从 AsyncTask 调用 Web 服务。当我在onPostExecute 中测试它时,会填充 ArrayList。 ArrayList 被定义为实例变量。为什么当 AsyncTask 完成时填充了 arrayList 但是当我之后测试实例变量本身时,它为空。似乎 Async 没有正确设置值。

一旦异步完成,我将 ArrayList 传递给 arrayAdapter,但我的 listView 是空的。

测试:onPostExecute

 Log.e(TAG, "array from WS = " + array.size());  // returns 4

测试:在onCreate

 Log.e(TAG, "checking to see if array is null " + array.size()); // returns 0



 package com.carefreegroup;

 public class GetRotaDetails extends NfcBaseActivity implements OnItemClickListener
 {
ArrayList<ArrayList<String>> array;
MySimpleArrayAdapter arrayAdapter;
Intent intent;
private static final String TAG = GetRotaDetails.class.getSimpleName();
ListView listView;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    array = new  ArrayList<ArrayList<String>>();
    nfcscannerapplication = (NfcScannerApplication) getApplication();
    intent = this.getIntent();
    setContentView(R.layout.getrotadetailslayout);
    listView = (ListView) findViewById(R.id.getrotadetailslistview);

    //set titlebar to carer's name
    Cursor cursorCarerName = nfcscannerapplication.loginValidate.queryAllFromCarer();
    cursorCarerName.moveToLast();
    String carerTitleName = cursorCarerName.getString(cursorCarerName
            .getColumnIndex(LoginValidate.C_CARER_NAME));
    setTitle(carerTitleName + " is currently logged in");

    callID = intent.getStringExtra("callIDExtra");
    Log.e(TAG, "callID = " + callID);
    String[] params = { callID };
    AsyncGetRotaDetails agrd = new AsyncGetRotaDetails();
    agrd.execute(params);

    Log.e(TAG, "checking to see if array is null " + array.size());
    if (arrayAdapter == null){
        MySimpleArrayAdapter arrayAdapter = new MySimpleArrayAdapter(this, array);
        listView.setAdapter(arrayAdapter);
    }
    listView.setAdapter(arrayAdapter);
    listView.setOnItemClickListener(this);


}// end of onCreate

@Override
protected void onResume() {


    super.onResume();
}


private class AsyncGetRotaDetails extends AsyncTask<String, Void, String> {

    ProgressDialog progressDialog;
    String rotaDetails = null;

    @Override
    protected void onPreExecute() {
        progressDialog = ProgressDialog
                .show(GetRotaDetails.this, "Connecting to Server",
                        " retrieving rota details...", true);

    };

    @Override
    protected String doInBackground(String... params) { 

        try {
            Log.e(TAG, "inside doInBackground");

            rotaDetails = nfcscannerapplication.loginWebservice.getRotaDetail(params[0]);

        } catch (Exception e) {

            e.printStackTrace();

        }
        return rotaDetails;

    }

    @Override
    protected void onPostExecute(String xmlResult) {
        super.onPostExecute(xmlResult);
        if (progressDialog != null)
            progressDialog.dismiss();

        if (rotaDetails != null) {



            RetrieveExtraDetails red = new RetrieveExtraDetails();
           array = red.getExtraDetails(xmlResult);
            Log.e(TAG, "array from WS = " + array.size());

        } else {

            AlertDialog alertDialog = new AlertDialog.Builder(
                    GetRotaDetails.this).create();
            alertDialog.setTitle("Signal/Server Test");
            alertDialog.setMessage("No Phone Signal or Server Problem");

            alertDialog.setButton("OK",
                    new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog,
                                int which) {

                            onStart();
                        }
                    });

            alertDialog.show();

        }

    }// end of postExecute

}//end of Async

private class MySimpleArrayAdapter extends ArrayAdapter<String> {



    private final Context context;
    private final ArrayList<?> list;

    public MySimpleArrayAdapter(Context context, ArrayList<?> list) {

        super(context, R.layout.getrotadetailsrow);
        Log.e(TAG, "inside adapter constructor");
        this.context = context;
        this.list = list;


    }// end of constructor

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        LayoutInflater inflater = (LayoutInflater) context
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);

        View rowView = inflater.inflate(R.layout.getrotadetailsrow, parent,
                false);

        TextView recTypeID = (TextView) rowView
                .findViewById(R.id.rectypeid);

        TextView recType = (TextView) rowView
                .findViewById(R.id.rectype);

        TextView name = (TextView) rowView
                .findViewById(R.id.name);

        TextView relationship = (TextView) rowView
                .findViewById(R.id.relationship);

        TextView address = (TextView) rowView
                .findViewById(R.id.address);

        TextView postCode = (TextView) rowView
                .findViewById(R.id.postcode);

        TextView telNo = (TextView) rowView
                .findViewById(R.id.telno);

        TextView keySafe = (TextView) rowView
                .findViewById(R.id.keysafe);

        TextView notes = (TextView) rowView
                .findViewById(R.id.notes);

        TextView meds = (TextView) rowView
                .findViewById(R.id.meds);

        String record = list.get(position).toString();

        Log.e(TAG, "record = " + record);
        recTypeID.setText(record);
        return super.getView(position, convertView, parent);
    }

}

@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
    // TODO Auto-generated method stub

}

}

【问题讨论】:

    标签: android android-listview android-asynctask android-arrayadapter


    【解决方案1】:

    实际上,AsyncTask 是异步运行的,它不是阻塞调用(就像 execute() 方法在 onPostExecute() 执行之后返回)。因此,您需要在下载数据时在 onPostExecute() 中通知适配器。这是一个与多线程相关的问题,当执行execute() 行时,会为AsyncTask 创建一个线程,并且onCreate() 的执行移到下一行,因此同时,doInBackground() 和onCreate() 将在AsyncTask 线程和UI 中执行分别线程。

    【讨论】:

    • 将arrayAdapter变量移动到类成员变量中,然后从onPostExecute()调用arrayAdapter.notifyDataSetChanged()
    【解决方案2】:

    让你的 ListView 成为类中的一个字段,然后

    使用

    listView.setAdapter(arrayAdapter);
    listView.setOnItemClickListener(this);
    

    onPostExecute(String result)方法中

    但我推荐的是:

    在获取数据并设置适配器之前使用加载微调器,否则行为是 Activity 显示为空,并且在 3-5 秒后突然出现整个列表,这是一个糟糕的用户体验。

    当获取的数据只是 UI 的一小部分,而不是作为 UI 主要组件的 ListView 时,我们通常使用不带任何加载微调器的异步任务。

    并且不要在 onCreate() 中检查 Array 的长度。它将始终为 0。因为代码流将是:

    1.创建数组

    2。在 onCreate //0 中检查它的长度,因为尚未添加任何内容

    3.在后台向数组添加数据

    4.在 onPostExecute(String result) //实际长度中检查它的长度

    【讨论】:

    • 嗨,我已将大部分内容移至类范围,并从 postExecute 设置适配器和列表视图。在 agrd.execute(params); 之后在 oncreate 中恢复执行之前,异步仍然没有完成;
    • postEx 中的长度始终为 4。但我的列表没有显示/填充
    • 我也忘记添加 @Override public int getCount() { return this.list.size(); } 在适配器中
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-31
    • 2020-08-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多