【问题标题】:Global ArrayList and AsyncTask problems全局 ArrayList 和 AsyncTask 问题
【发布时间】:2014-06-05 01:46:31
【问题描述】:

所以 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

我最终要做的是从列表中获取特定元素并通过捆绑将其传递给片段(如果这是正确的方法)。

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

感谢您的帮助!

编辑: 为了看看它是否有更多帮助,这是关于我正在尝试做的更多信息。 当用户在 Navigation Drawer 中单击 ListView 时,将返回其位置编号。更多信息在代码中的 cmets 中。代码如下:

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 吗?我可以只实现一个新线程并做同样的事情吗?

【问题讨论】:

  • 尝试在循环中打印List 的内容或打印其大小,而不是在第一个位置获取名称。我知道您已经在 onPostExecute() 中尝试过,但您的实现似乎还不错。

标签: android arraylist android-asynctask


【解决方案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 完成后才跳转到下一行。
希望现在很清楚。

【讨论】:

  • 嗯嗯。有没有办法让它在调用 globalRates 之前完成处理?在 onCreate 中,我做了一个 if/else if 语句来检查 AsyncTask 的状态,它总是出现 RUNNING。我尝试了一个while循环来打印状态以查看它是否会改变,但它使我的手机崩溃并让它重新启动LOL!这就是我想要做的。我将有一个监听列表视图点击的 switch 语句。根据位置,它会调用 globalRates.get(position).DataThatIWant。我不确定我可以在 PostExecute 中做到这一点。你知道我来自哪里或需要更多信息吗? @懒惰忍者
  • 有一些方法可以尝试在 onCreate() 中等待,但这是一种不好的做法。建议您在触发 listview 单击事件时调用 globalRates.get(position),而不是在 onCreate 中调用。
  • 我编辑了我的原始帖子。如果您提到的内容符合我添加的内容,那么它也会崩溃。老实说,我在这里没有想法:/感谢您的帮助,我真的很感激。 @懒惰忍者
  • 只是为了检查,尝试在 displayView() 中使用 ratesList.get(position) 而不是 globalRates.get(position)
  • 不,同样的问题:/ 我将 ratesList 设置为全局变量,但它仍然崩溃。
猜你喜欢
  • 2014-06-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多