我想使用他们的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类中没有?
答案 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。
编辑您也可以像这样实现它并跳过构造函数:
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)。
答案 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)
编辑以下问题解决了问题: