【问题标题】:Fragment implementing AsyncTask and GridView in android在android中实现AsyncTask和GridView的片段
【发布时间】:2016-10-23 09:59:37
【问题描述】:

我使用 Activity 从带有 AsyncTask 的 json 加载数据并显示在 Fragment 类中。 显示内容包括:ImageView、TextView、TextView,当用户点击一个item时会重定向GridView中对应的item

在 ManufactureFragment 中包括:

  1. POJO 制造商项目
  2. Lo​​adAllManufacturers 扩展 AsyncTask 以从 json 加载数据
  3. 适配器:从 json 调用加载数据

我的片段:

public class ManufacturerFragment extends Fragment {

ProgressDialog pDialog;
JSONParser jsonParser = new JSONParser();


// initiliaze adapter variable
MyAdapter adapter; 
JSONArray manufacturers = null;

// manufacturers JSON url
private static final String URL_MANUFACTURERS = "http://MYURL";

public ManufacturerFragment() {
    // Required empty public constructor
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    // Inflate the layout for this fragment
    View view = inflater.inflate(R.layout.gridview_manufacturer, container, false);

    GridView gridView = (GridView) view.findViewById(R.id.gridview);
    // gridView.setAdapter(new MyAdapter(getActivity(), manufacturersList));
    adapter = new MyAdapter(getActivity(), manufacturersList);
    gridView.setAdapter(adapter);

    gridView.setOnItemClickListener(new android.widget.AdapterView.OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView<?> arg0, View view, int arg2, long arg3) {
            // on selecting a single manufacturer
            // CategoryCarActivity will be launched to show category car inside the manufacturer
            Intent i = new Intent(getActivity(), CategoryCarActivity.class);

            // send manufacturer id to activity to get list of cars under that manufacturer
            String manufacturer_id = ((TextView) view.findViewById(R.id.manufacturer_id)).getText().toString();
            i.putExtra("manufacturer_id", manufacturer_id);

            startActivity(i);
        }
    });

    return view;
}

@Override
public void onActivityCreated(Bundle savedInstanceState) {
    // TODO Auto-generated method stub
    super.onActivityCreated(savedInstanceState);

    new LoadAllManufacturers().execute();
}


class LoadAllManufacturers extends AsyncTask<String, String, String> {
    /**
     * Before starting background thread Show Progress Dialog
     * */
    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        pDialog = new ProgressDialog(getActivity());
        pDialog.setMessage("Loading manufacturers. Please wait...");
        pDialog.setIndeterminate(false);
        pDialog.setCancelable(false);
        pDialog.show();
    }

    /**
     * After completing background task Dismiss the progress dialog
     * **/
    @Override
    protected void onPostExecute(String s) {
        super.onPostExecute(s);

        adapter.notifyDataSetChanged();
        // dismiss the dialog after getting all manufacturers
        if (pDialog.isShowing())
            pDialog.dismiss();
    }
}

private class MyAdapter extends BaseAdapter
{
    LayoutInflater inflater;
    Context context;

    public MyAdapter(Context context, ArrayList<HashMap<String, String>> arrayList)
    {
        this.context = context;
        this.manufacturersList = arrayList;
        this.inflater = LayoutInflater.from(context);
    }

    @Override
    public int getCount() {
        if (manufacturersList != null)
            return manufacturersList.size();
        return 0;
    }

    @Override
    public Object getItem(int i)
    {
        if (manufacturersList != null)
            return manufacturersList.get(i);
        return null;
    }

    @Override
    public long getItemId(int i)
    {
        if (manufacturersList != null)
            return manufacturersList.get(i).hashCode();
        return 0;
    }

    @Override
    public View getView(int i, View view, ViewGroup viewGroup)
    {
        View v = view;
        ImageView picture;
        TextView name;

        if(v == null)
        {
            v = inflater.inflate(R.layout.gridview_item, viewGroup, false);
            v.setTag(R.id.picture, v.findViewById(R.id.picture));
            v.setTag(R.id.text, v.findViewById(R.id.text));
        }

        picture = (ImageView)v.getTag(R.id.picture);
        name = (TextView)v.getTag(R.id.text);   

        picture.setImageResource(item.drawableId);
        name.setText(item.name);

        return v;
    }
   }
 }

我的 list_item_manufacturers.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical">

<!-- Manufacturer_id / Hidden by default -->
<TextView
    android:id="@+id/manufacturer_id"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:visibility="gone" />

<!-- Manufacturer_name -->
<TextView
    android:id="@+id/manufacturer_name"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:textSize="16dip"
    android:textColor="#000000"
    android:paddingTop="15dip"
    android:paddingBottom="15dip"
    android:paddingLeft="10dip"
    android:textStyle="bold"/>

<!-- Logo image -->
<ImageView
    android:id="@+id/iconName"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentRight="true"
    android:background="#000000"
    android:padding="1dp" />
 </RelativeLayout>

我的 gridview_manufacturer.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<GridView
    android:id="@+id/gridview"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:verticalSpacing="0dp"
    android:horizontalSpacing="0dp"
    android:stretchMode="columnWidth"
    android:numColumns="2" />
</FrameLayout>

当我调试和构建时,我看到 json 加载成功,但随后在以下行发生异常: 日志猫:

E/AndroidRuntime: FATAL EXCEPTION: AsyncTask #1
              Process: com.totoroads.android.app, PID: 3723
              java.lang.RuntimeException: An error occurred while executing doInBackground()
                  at android.os.AsyncTask$3.done(AsyncTask.java:309)
                  at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:354)
                  at java.util.concurrent.FutureTask.setException(FutureTask.java:223)
                  at java.util.concurrent.FutureTask.run(FutureTask.java:242)
                  at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:234)
                  at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
                  at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
                  at java.lang.Thread.run(Thread.java:818)
               Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'boolean java.util.ArrayList.add(java.lang.Object)' on a null object reference
                  at com.totoroads.android.app.FeedBackFragment$LoadAllManufacturers.doInBackground(ManufacturerFragment.java:136)
                  at com.totoroads.android.app.FeedBackFragment$LoadAllManufacturers.doInBackground(ManufacturerFragment.java:89)
                  at android.os.AsyncTask$2.call(AsyncTask.java:295)
                  at java.util.concurrent.FutureTask.run(FutureTask.java:237)
                  at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:234) 
                  at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113) 
                  at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588) 
                  at java.lang.Thread.run(Thread.java:818)  

Logcat 中的最终异常:

E/AndroidRuntime: FATAL EXCEPTION: main
              Process: com.totoroads.android.app, PID: 5730
              java.lang.ClassCastException: java.util.HashMap cannot be cast to com.totoroads.android.app.ManufacturerFragment$MyAdapter$ManufacturerItem
                  at com.totoroads.android.app.ManufacturerFragment$MyAdapter.getView(FeedBackFragment.java:226)
                  at android.widget.AbsListView.obtainView(AbsListView.java:2346)
                  at android.widget.GridView.onMeasure(GridView.java:1065)
                  at android.view.View.measure(View.java:18788)
                  at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5951)

在线:

ManufacturerFragment.MyAdapter.ManufacturerItem item = (ManufacturerFragment.MyAdapter.ManufacturerItem)getItem(i);

有一些错误我无法检测到,如何解决这个异常

非常感谢!!

【问题讨论】:

  • 如果你正在使用网络,你应该使用retrofit+rxjava,对于json解析使用GSON。欲了解更多信息,请阅读本文infinum.co/the-capsized-eight/articles/…
  • 在本文中,当我解析 json 时,我使用了 jersey 和 Gson。我听说过 Retrofit 并稍后尝试,因为现在我必须在下面的异常中解决这个问题。谢谢你的建议

标签: java android json android-asynctask


【解决方案1】:

在调用AsyncTask 之前,您没有初始化您的ArrayList。在执行onActivityCreated() 中的AsyncTask 之前添加此行:

manufacturersList = new ArrayList<>();

编辑 1: 将您的适配器分配给变量:

adapter = new MyAdapter(getActivity(), manufacturersList);
gridView.setAdapter(adapter);

因为现在您将更改通知空适配器。

编辑 2: 您的代码永远不会进入onPostExecute,因为您没有覆盖AsyncTaskonPostExecute 方法。你的AsyncTask 被初始化为AsyncTask&lt;String, String, String&gt;,因此onPostExecute 的参数应该是String,而不是Void

@Override
protected void onPostExecute(String s) {
    super.onPostExecute(s);

    adapter.notifyDataSetChanged();
    // dismiss the dialog after getting all manufacturers
    if (pDialog.isShowing())
        pDialog.dismiss();
}

编辑 3: 这是您可以开始使用的 getView 方法的一个工作示例:

    @Override
    public View getView(int i, View view, ViewGroup viewGroup) {
        View v = view;
        ImageView picture;
        TextView name, idTV;

        inflater = (LayoutInflater) context.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
        v = inflater.inflate(R.layout.gridview_item, viewGroup, false);
        picture = (ImageView) v.findViewById(R.id.picture);
        name = (TextView) v.findViewById(R.id.manufacturer_name);
        idTV = (TextView) v.findViewById(R.id.manufacturer_id);

        HashMap<String, String> itemHash = (HashMap<String, String>) getItem(i);
        String nameString = itemHash.get(TAG_NAME);
        String iconUrl = itemHash.get(TAG_ICONNAME);
        String idString = itemHash.get(TAG_ID);

        // Use an image loader to load your Photo from URL.
        Picasso.with(context).load(iconUrl).into(picture);

        idTV.setText("ID: "+idString);
        name.setText("Name: "+nameString);
        return v;
    }

【讨论】:

  • 我已经添加了那行,似乎没有发生异常,但是进度对话框没有停止:“正在加载制造商,请稍候...”
  • 您好,我看到 json 已被 AsyncTask 加载,但无法在屏幕上显示
  • 嗨 MohanadMohie,我已经更新了你的代码,仍然是同样的错误
  • 请检查编辑2
  • 亲爱的 MohanadMohie,我已经继续更新您的步骤编辑 2,清理并重建项目,当屏幕加载数据完成时,屏幕现在是空的和空白的。你认为我的 xml 中的属性不正确吗?
【解决方案2】:

我只写了代码中的更改以及上面和下面的行。

变化

  1. 您的ArrayListnull。初始化它。
  2. 为您需要调用的适配器创建一个变量 notifyDataSetChanged 就在 onPostExecute 中。


// manufacturers JSON url
private static final String URL_MANUFACTURERS = "http://MYURL";

MyAdapter adapter;
ArrayList<HashMap<String, String>> manufacturersList = new ArrayList<>();

public ManufacturerFragment() {
    // Required empty public constructor
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    ...

    // initialize the adapter
    adapter = new MyAdapter(getActivity(), manufacturersList)
    GridView gridView = (GridView) view.findViewById(R.id.gridview);
    gridView.setAdapter(adapter);

    ...
}


class LoadAllManufacturers extends AsyncTask<String, String, String> {

    /**
     * After completing background task Dismiss the progress dialog
     * **/
    protected void onPostExecute(Void args) {

        // notify the adapter
        adapter.notifyDataSetChanged();

        // dismiss the dialog after getting all manufacturers
        ...
    }
}

【讨论】:

  • 嗨,K Neeraj Lal,我已经参考了您的回复,这很好,但同样的错误。进度对话框未停止:“正在加载制造商,请稍候...”
  • Logcart返回json结果:厂商列表,无一例外。但数据无法在屏幕上显示
猜你喜欢
  • 2014-04-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多