Global ArrayList和AsyncTask问题

时间:2014-04-21 02:19:56

标签: android arraylist android-asynctask

AsyncTask和我相处得不好。我试图更好地理解它的使用方式。

所以我继续遇到这个问题,我通过GSON AsyncTask将JSON API加载到ArrayList(称为ratesList)。呼叫正在成功。然后我尝试将ratesList内容复制到另一个名为globalRates的ArrayList中。两个列表都是全局定义的。

为确保两个列表都已填充,我会从onPostExecute中打印列表的大小,并返回158.

但是当我尝试从onCreate方法的globalRates列表中获取一个元素时,我的程序崩溃了。我尝试了一个try / catch块来查看我是否可以获得更多信息,并且错误以NullPointerException响应。我将在下面显示我的日志。

这是MainActivity类:

public class PostsActivity extends Activity {

// JSON info will be stored here through GSON
public static List<GlobalRates> ratesList = new ArrayList<GlobalRates>();

// Trying to copy contents of ratesList into this ArrayList
// Then trying to call an index from here on the onCreate method
public static List<GlobalRates> globalRates;

TextView view;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_posts);

    view = (TextView) findViewById(R.id.textView1);

    BitRateFetcher br = new BitRateFetcher();
    br.execute();

    // Error comes here. Error keeps saying 'NullPointerException'
    try {
        String name = globalRates.get(0).getName();
    } catch (NullPointerException ex) {
        Log.e("BitRateFetcher", "Error: " + ex.fillInStackTrace());
        Log.e("BitRateFetcher", "Error: " + ex.getLocalizedMessage());
    }

    // view.setText(name);
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.posts, menu);
    return true;
}

private void failedLoadingPosts() {
    runOnUiThread(new Runnable() {
        @Override
        public void run() {
            Toast.makeText(PostsActivity.this,
                    "Failed to load Posts. Have a look at LogCat.",
                    Toast.LENGTH_SHORT).show();
        }
    });
}

private class BitRateFetcher extends AsyncTask<Void, Void, String> {
    private static final String TAG = "BitRateFetcher";
    public String BIT_PAY_SERVER = "https://bitpay.com/api/rates";

    private ProgressDialog dialog;

    @Override
    protected void onPreExecute() {
        // Things to be done before execution of long running operation. For
        // example showing ProgessDialog
        super.onPreExecute();
        dialog = new ProgressDialog(PostsActivity.this);
        dialog.setMessage("Please Wait... Downloading Information");
        dialog.show();
    }

    @Override
    protected String doInBackground(Void... params) {
        try {
            // Create an HTTP client
            HttpClient client = new DefaultHttpClient();
            HttpGet getBitRates = new HttpGet(BIT_PAY_SERVER);

            // Perform the request and check the status code
            HttpResponse bitRatesResponse = client.execute(getBitRates);

            StatusLine bitRatesStatus = bitRatesResponse.getStatusLine();

            if (bitRatesStatus.getStatusCode() == 200) {
                HttpEntity entity = bitRatesResponse.getEntity();
                InputStream content = entity.getContent();

                try {
                    // Read the server response and attempt to parse it as
                    // JSON
                    Reader reader = new InputStreamReader(content);
                    Gson gson = new Gson();

                    ratesList = Arrays.asList(gson.fromJson(reader,
                            GlobalRates[].class));

                    content.close();
                    entity.consumeContent();
                } catch (Exception ex) {
                    Log.e(TAG, "Failed to parse JSON due to: " + ex);
                    failedLoadingPosts();
                }
            } else {
                Log.e(TAG, "Server responded with status code: "
                        + bitRatesStatus.getStatusCode());
                failedLoadingPosts();
            }
        } catch (Exception ex) {
            Log.e(TAG, "Failed to send HTTP POST request due to: " + ex);
            failedLoadingPosts();
        }
        return null;
    }

    @Override
    protected void onPostExecute(String result) {
        // execution of result of Long time consuming operation
        globalRates = new ArrayList<GlobalRates>(ratesList);

        // This shows both lists are populated. 
        Log.i(TAG, "Bit Rates Connected");
        Log.i(TAG, "Rates List Size: " + ratesList.size());
        Log.i(TAG, "Global Rates Size: " + globalRates.size());

        if (dialog.isShowing()) {
            dialog.dismiss();
        }
    }
}

}

这是“BitRateFetcher”日志:

04-20 22:13:55.626: E/BitRateFetcher(21097): Error: java.lang.NullPointerException
04-20 22:13:55.626: E/BitRateFetcher(21097): Error: null
04-20 22:13:56.206: I/BitRateFetcher(21097): Bit Rates Connected
04-20 22:13:56.206: I/BitRateFetcher(21097): Rates List Size: 158
04-20 22:13:56.206: I/BitRateFetcher(21097): Global Rates Size: 158

我最终要做的是从列表中抓取一个特定的元素并通过bundle将它传递给一个片段(如果这是正确的方法)。

关于为什么会发生这种情况以及如何解决这个问题的想法?我甚至尝试从ratesList调用一个元素,但它也崩溃了。

感谢您的帮助!

编辑: 为了了解它是否有所帮助,这是关于我正在尝试做什么的更多信息。 当用户单击导航抽屉中的ListView时,将返回其位置编号。更多信息在代码中的注释中。这是代码:

private void displayView(int position) {
    // update the main content by replacing fragments
    Bundle bundle;
    Fragment fragment = null;
    String name;

    switch (position) {
    case 0:

        // I want to get the name of a specific element depending on
        // the position the user clicked. When i run the below line, it 
        // crashes and return the NullPointerException. globalRates is
        // defined globally up top, similar to the code I pasted above. 
        name = globalRates.get( position).getName(); // <------ Crashes  

        // I will then pass the variable "name" into the bundle so
        // that I can call it from the fragment.
        bundle = new Bundle();
        bundle.putString("message", "Test " + position);

        fragment = new CoinFragment();
        fragment.setArguments(bundle);
        break;
    case 1:
        bundle = new Bundle();
        bundle.putString("message", "Litecoin Info");

        fragment = new CoinFragment();
        fragment.setArguments(bundle);
        break;
    case 2:
        bundle = new Bundle();
        bundle.putString("message", "Peercoin Info");

        fragment = new CoinFragment();
        fragment.setArguments(bundle);
        break;
    case 3:
        bundle = new Bundle();
        bundle.putString("message", "Dogecoin Info");

        fragment = new CoinFragment();
        fragment.setArguments(bundle);
        break;
    case 4:
        bundle = new Bundle();
        bundle.putString("message", "Nxt Info");

        fragment = new CoinFragment();
        fragment.setArguments(bundle);
        break;
    case 5:
        bundle = new Bundle();
        bundle.putString("message", "Namecoin Info");

        fragment = new CoinFragment();
        fragment.setArguments(bundle);
        break;

    default:
        break;
    }

}

它可能不合适,但我真的需要通过AsyncTask调用API吗?我可以实现一个新线程并执行相同的操作吗?

1 个答案:

答案 0 :(得分:1)

您应该在onPostExecute();

中移动以下内容
// Error comes here. Error keeps saying 'NullPointerException'
try {
    String name = globalRates.get(0).getName();
} catch (NullPointerException ex) {
    Log.e("BitRateFetcher", "Error: " + ex.fillInStackTrace());
    Log.e("BitRateFetcher", "Error: " + ex.getLocalizedMessage());
}

为什么?

因为AsyncTask在后台运行(换句话说是在另一个线程中)。当你调用上面的代码时,它仍在处理,因此globalRates列表仍为空 首先确保在使用globalRates之前调用onPostExecute() 当你打电话

BitRateFetcher br = new BitRateFetcher();
br.execute();

程序不会等到AsyncTask完成后再跳到下一行。
希望现在很清楚。