从类中填充GridView使用AsyncTask扩展BaseAdapter

时间:2015-12-02 15:02:37

标签: android android-asynctask baseadapter

我想使用他们的URL在GridView布局上显示图像。首先我创建了ImageAdapter扩展BaseAdapter

public class ImageAdapter extends BaseAdapter {

    private final String LOG_TAG = ImageAdapter.class.getSimpleName();
    private Context context;

//  refers to image paths
    static ArrayList<String> paths = new ArrayList<>();

    public ImageAdapter(Context c) {
        context = c;
    }

    public int getCount() {
        return paths.size();
    }

    public Object getItem(int position) {
        return null;
    }

    public long getItemId(int position) {
        return 0;
    }

//  create a new ImageView for each item referenced by the Adapter
    public View getView(int position, View convertView, ViewGroup parent) {
        View view;
        if (convertView == null) {
//          if it's not recycled, initialize some attributes
            LayoutInflater inflater = (LayoutInflater) context.getSystemService(
                    Context.LAYOUT_INFLATER_SERVICE);
            view = inflater.inflate(R.layout.grid_view_item, parent, false);
        } else {
            view = convertView;
        }
        ImageView imageView = (ImageView) view.findViewById(R.id.image_view_item);
        try {
            String url = "http://image.tmdb.org/t/p/w185/"+paths.get(position);
            Picasso.with(context).load(url).into(imageView);
            Log.v(LOG_TAG, url + "position=" + position);
        } catch (Exception e) {
            Log.e(LOG_TAG, "Error:", e);
        }
        return view;
    }

}
在petchMovieTask类中实现的onPostExecute()方法中的

扩展了AsyncTask。我将数据放入ImageAdapter.paths,一切都很好。

@Override
protected void onPostExecute(String[] results) {
    if (results != null) {
        ImageAdapter.paths = new ArrayList<>(Arrays.asList(results));
        for (int i = 0; i < ImageAdapter.paths.size(); i++)
            Log.v(LOG_TAG, "onPostExecute: " + ImageAdapter.paths.get(i));
    }
}

在fragment类中我应该填充gridView。 ImageAdapter.path仍为null

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    View rootView = inflater.inflate(R.layout.fragment_main, container, false);
    GridView gridView = (GridView) rootView.findViewById(R.id.grid_View);
    ImageAdapter imageAdapter = new ImageAdapter(getActivity());
    updateMovies();
    imageAdapter.notifyDataSetChanged();
    gridView.setAdapter(imageAdapter);
    return rootView;
}

public void updateMovies() {
    FetchMovieTask fetchMovieTask = new FetchMovieTask();
    fetchMovieTask.execute();
}

为什么ImageAdapter.paths在FetchMovieTask类中更改但在ImageAdapter类中没有?

3 个答案:

答案 0 :(得分:1)

这里有两个不同的主题。您的第一个线程正在处理代码,并在加载图像之前执行getView。您需要回调才能将结果发送回UIThread:

使用接口进行回叫:

public interface UpdateMovieCallback {
    void processLoadImg(String[] results);
}

public class ImageAdapter extends BaseAdapter implements UpdateMovieCallback {

    public void updateMovies() {
        FetchMovieTask fetchMovieTask = new FetchMovieTask(this);
        fetchMovieTask.execute();
    }
    .
    .
    @Override
    public void processLoadImg(String[] results) {
        //Load Images to your Adapter here 
        imageAdapter.notifyDataSetChanged();
    }
}

使用静态方法在这里没有意义,你必须处理你的实际对象:

public final class FetchMovieTask extends AsyncTask<Void, Void, Void>
    public FetchMovieTask(UpdateMovieCallback callback) {
        .
        .
        .
        @Override
        protected void doInBackground(Void... params) {
             // Executes first
        }

        .
        @Override
        protected void onPostExecute() {
            // Is called after doInBackground
            if (results != null) {
                callback.processLoadImg(results);
            }
        }
    }
}

我希望这会有所帮助。另一位上帝建议您学习Java中的线程和对象。回调的想法是,您可以启动异步任务或线程,并将回调/事件传回主Main / UIThread。

Threads Wikipedia

编辑您也可以像这样实现它并跳过构造函数:

public final class FetchMovieTask extends AsyncTask<Void, Void, String[] results> {
        public FetchMovieTask() {}

        @Override
        protected String[] doInBackground(Void... params) {
             // Executes first
             return results;
        }

        @Override
        protected void onPostExecute(String[] results) {
            // Is called after doInBackground
            if (results != null) {
                callback.processLoadImg(results);
            }
        }

}

注意:异步任务的第三个参数始终是后台计算结果的类型。如果它是void,则不会向onPostExecute返回任何内容,因此永远不会调用onPostExecute。因为onPostExecute()被调用。如果第三个参数是一个字符串数组,则调用onPostExecute(String [] results)。

Asnyc Tasks

答案 1 :(得分:0)

问题在于:您在FetchMovieTask完成获取结果之前设置适配器。

因此,请尝试按以下方式更改代码:

首先更改FetchMovieTask类,如下所示。

 public class FetchMovieTask extends AsyncTask<param,progress,result>{

            private final OnFetchMovieCompletedListener listenerFetchMovieTask;

            public interface OnFetchMovieCompletedListener{
                void OnFetchMovieCompleted(ArrayList<String> paths );
            }

            public FetchMovieTask(OnFetchMovieCompletedListener listenerFetchMovieTask){
                this.listenerFetchMovieTask = listenerFetchMovieTask;
            }
            @Override
            protected String[] doInBackground(Void... params) {
                //your code goes here
            }

            @Override
            protected void onPostExecute(String[] results) {
                if (results != null) {
                    if(listenerFetchMovieTask!=null){
                        listenerFetchMovieTask.OnFetchMovieCompleted(new ArrayList<>(Arrays.asList(results)));
                    }
                }
            }
        }

然后按以下方式更改您的片段:

public class YourFragment  extends Fragment{

    private GridView gridView;
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.fragment_main, container, false);
        gridView = (GridView) rootView.findViewById(R.id.grid_View);
        updateMovies();
        return rootView;
    }

    public void updateMovies() {
        FetchMovieTask fetchMovieTask = new FetchMovieTask(new OnFetchMovieCompletedListener(){

            @Override
            public void OnFetchMovieCompleted(ArrayList<String> paths) {
                ImageAdapter.paths = paths;
                ImageAdapter imageAdapter = new ImageAdapter(getActivity());
                gridView.setAdapter(imageAdapter);
                imageAdapter.notifyDataSetChanged();

            }
        });
        fetchMovieTask.execute();
    }

}

答案 2 :(得分:0)

编辑以下问题解决了问题:

  1. 将FetchMovieTask移动到ImageAdapter中的内部类。
  2. 将路径更改为非静态字段。
  3. 调用ImageAdapter.this.notifyDataSetChanged();在......的最后 方法onPostExecute()
  4. 更多详情:Android call notifyDataSetChanged from AsyncTask