Android - 使用AsyncTask调用方法会中断其他方法

时间:2017-07-26 23:21:20

标签: android user-interface android-asynctask

我有一个菜单有两个选项。其中一个选项使用Web内容刷新应用程序的内容。我想调暗屏幕上的ListView,然后显示进度条直到内容刷新。我有方法startLoadingAnimation()endLoadingAnimation()来实现这一目标。但是当我在他们之间打电话给refreshArticles()时,他们就会停止工作。我在其中有打印语句,表明它们应该执行,但是

case R.id.refresh:
    startLoadingAnimation();
    refreshArticles();
    endLoadingAnimation();
执行

,只有打印语句通过,而不是UI更改。

完整活动代码:

package com.bruno.newsreader;

import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.AsyncTask;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.NumberPicker;
import android.widget.ProgressBar;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;

public class ListActivity extends AppCompatActivity {

    private ListView listView;
    private int numArticles;
    private SharedPreferences sharedPreferences;
    private ArrayList<String> articleTitles;
    private ArrayList<String> articleUrls;
    private SQLiteDatabase articleDB;
    private ProgressBar progressBar;

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {

        MenuInflater menuInflater = getMenuInflater();
        menuInflater.inflate(R.menu.options_menu, menu);

        return super.onCreateOptionsMenu(menu);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        super.onOptionsItemSelected(item);

        switch (item.getItemId()) {
            case R.id.refresh:
                startLoadingAnimation();
                refreshArticles();
                endLoadingAnimation();
                return true;
            case R.id.numArticles:
                final NumberPicker numberPicker = new NumberPicker(getApplicationContext());
                numberPicker.setMaxValue(50);
                numberPicker.setMinValue(5);
                numberPicker.setValue(numArticles);
                new AlertDialog.Builder(this)
                        .setTitle("Set Number of Articles")
                        .setMessage("This will determine how many articles are stored on your device:")
                        .setView(numberPicker)
                        .setPositiveButton("OK", new DialogInterface.OnClickListener() {

                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                numArticles = numberPicker.getValue();
                                sharedPreferences.edit().putInt("numArticles", numArticles).apply();
                            }
                        })
                        .setNegativeButton("Cancel", null)
                        .show();
            default:
                return false;

        }
    }

    public class TopArticleDownloadTask extends AsyncTask<URL, Void, JSONArray> {

        @Override
        protected JSONArray doInBackground(URL... urls) {
            String jsonString = "";
            URL url = urls[0];
            HttpURLConnection urlConnection = null;
            try {
                urlConnection = (HttpURLConnection) url.openConnection();
                InputStream in = urlConnection.getInputStream();
                InputStreamReader reader = new InputStreamReader(in);
                int data = reader.read();
                while(data != -1) {
                    char current = (char) data;
                    jsonString += current;
                    data = reader.read();
                }
                return new JSONArray(jsonString);
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
        }
    }

    public class IndividualArticleDownloadTask extends AsyncTask<URL, Void, JSONObject> {

        @Override
        protected JSONObject doInBackground(URL... urls) {
            String jsonString = "";
            URL url = urls[0];
            HttpURLConnection urlConnection = null;
            try {
                urlConnection = (HttpURLConnection) url.openConnection();
                InputStream in = urlConnection.getInputStream();
                InputStreamReader reader = new InputStreamReader(in);
                int data = reader.read();
                while(data != -1) {
                    char current = (char) data;
                    jsonString += current;
                    data = reader.read();
                }
                return new JSONObject(jsonString);
            } catch (Exception e) {

            }
            return null;
        }
    }

    private void refreshArticles() {

        String topArticlesUrlString = "https://hacker-news.firebaseio.com/v0/topstories.json?print=pretty";
        URL topArticlesUrl = null;
        try {
            topArticlesUrl = new URL(topArticlesUrlString);
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }
        TopArticleDownloadTask topArticleDownloadTask = new TopArticleDownloadTask();
        JSONArray topArticlesJSON = null;
        try {
            topArticlesJSON = topArticleDownloadTask.execute(topArticlesUrl).get();
        } catch (Exception e) {
            e.printStackTrace();
        }
        int[] articleIds = new int[numArticles];
        for (int i = 0; i < articleIds.length; i++) {
            try {
                articleIds[i] = topArticlesJSON.getInt(i );
            } catch (JSONException e) {
                e.printStackTrace();
            }
        }

        String articleUrlStart = " https://hacker-news.firebaseio.com/v0/item/";
        String articleUrlEnd = ".json?print=pretty";
        articleDB.execSQL("DELETE FROM articles");
        for (int id : articleIds) {
            String articleUrlString = articleUrlStart + id + articleUrlEnd;
            URL articleUrl = null;
            try {
                articleUrl = new URL(articleUrlString);
            } catch (MalformedURLException e) {
                e.printStackTrace();
            }
            JSONObject articleJSON = null;
            try {
                IndividualArticleDownloadTask individualArticleDownloadTask = new IndividualArticleDownloadTask();
                articleJSON = individualArticleDownloadTask.execute(articleUrl).get();
            } catch (Exception e) {
                e.printStackTrace();
            }

            try {
                String title = articleJSON.getString("title");
                title = title.replaceAll("'", "''");
                String url = articleJSON.getString("url");
                articleDB.execSQL("INSERT INTO articles (title, url) VALUES ('" + title + "', '" + url + "')");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        syncArrayListsWithDB();
    }

    private void syncArrayListsWithDB() {
        articleTitles.clear();
        articleUrls.clear();

        Cursor cursor = articleDB.rawQuery("SELECT * FROM articles", null);

        if (cursor.moveToFirst()) {
           while(!cursor.isAfterLast()) {
               String title = cursor.getString(0);
               String url = cursor.getString(1);
               articleTitles.add(title);
               articleUrls.add(url);
               cursor.moveToNext();
           }
        }

        ArrayAdapter<String> arrayAdapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1, articleTitles);
        listView.setAdapter(arrayAdapter);
    }

    private void startLoadingAnimation() {
        System.out.println("start start load");
        listView.setAlpha(.25f);
        progressBar.setVisibility(View.VISIBLE);
        System.out.println("end start load");
    }

    private void endLoadingAnimation() {
        System.out.println("start end load");
        listView.setAlpha(1);
        progressBar.setVisibility(View.INVISIBLE);
        System.out.println("end end load");
    }

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

        articleTitles = new ArrayList<>();
        articleUrls = new ArrayList<>();
        listView = (ListView) findViewById(R.id.listView);
        progressBar = (ProgressBar) findViewById(R.id.progressBar);

        sharedPreferences = this.getSharedPreferences("com.bruno.newsreader", Context.MODE_PRIVATE);
        numArticles = sharedPreferences.getInt("numArticles", 10);

        articleDB = this.openOrCreateDatabase("Data", MODE_PRIVATE, null);

        articleDB.execSQL("CREATE TABLE IF NOT EXISTS articles (title VARCHAR, url VARCHAR)");

        Cursor c = articleDB.rawQuery("SELECT count(*) FROM articles", null);
        c.moveToFirst();
        int count = c.getInt(0);
        if (count == 0) {
            refreshArticles();
        } else {
            syncArrayListsWithDB();
        }

        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {

            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                Intent intent = new Intent(getApplicationContext(), ReaderActivity.class);
                intent.putExtra("url", articleUrls.get(position));
                startActivity(intent);
            }
        });
    }
}

1 个答案:

答案 0 :(得分:0)

很难确切地说出refreshArticles()究竟在做什么,但我怀疑答案是“很多工作”,而且它不是异步地做(也就是说,它只是在运行它的工作而不是产生一个新线程来完成它然后在完成后回复给你。

onOptionsItemSelected()在主线程(也称为UI线程)上执行。在主线程上执行任何操作时,无法更新UI。因此,如果您正在“开始”加载动画,执行大量工作,然后“停止”该动画(全部在主线程上),您将无法实际看到动画运行。当您在主线程上运行代码时,您已经停止了加载动画。

解决方案是将refreshArticles()的工作移动到后台线程。有很多不同的方法来实现这一目标;阅读Handler.post(Runnable)AsyncTask应该可以帮助您入门。