#java #android #json #android-asynctask
#java #Android #json #android-asynctask
Вопрос:
Я использую Activity для загрузки данных из json с помощью AsyncTask и отображения в классе Fragment. Отображаемый контент включает в себя: ImageView, TextView, TextView, и когда пользователь нажимает на элемент, он перенаправляет соответствующий элемент в GridView
В ManufactureFragment входят:
- POJO ManufacturerItem
- LoadAllManufacturers расширяет AsyncTask для загрузки данных из json
- Адаптер: вызов загружает данные из 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 прошла успешно, но затем в строке возникает исключение:
Logcat:
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);
Есть некоторые ошибки, я не могу это обнаружить, Как исправить это исключение
Большое вам спасибо!!
Комментарии:
1. если вы работаете с сетью, вам следует использовать retrofit rxjava, а для синтаксического анализа json используйте GSON. для получения дополнительной информации прочитайте эту статью infinum.co/the-capsized-eight/articles /…
2. в этой статье при разборе json я использовал jersey и Gson. Я слышал о модернизации и попробую это позже, потому что сейчас мне нужно исправить это исключение, приведенное ниже. спасибо за ваш совет
Ответ №1:
Вы не инициализировали свой ArrayList
перед вызовом своего AsyncTask
. Добавьте эту строку перед выполнением AsyncTask
в onActivityCreated()
:
manufacturersList = new ArrayList<>();
Редактировать 1:
Назначьте свой адаптер переменной:
adapter = new MyAdapter(getActivity(), manufacturersList);
gridView.setAdapter(adapter);
Потому что теперь вы уведомляете пустой адаптер об изменениях.
Правка 2: Ваш код никогда не вводится onPostExecute
, потому что вы не переопределяете метод AsyncTask
‘s onPostExecute
. Ваш AsyncTask
инициализирован как AsyncTask<String, String, String>
, поэтому onPostExecute
параметром должен быть String
, а не Void
a.
@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;
}
Комментарии:
1. Я добавил эту строку, кажется, исключения не произошло, но диалоговое окно выполнения не останавливается: «загрузка производителя, пожалуйста, подождите …»
2. Привет, я вижу, что json загружен AsyncTask, но не может отображаться на экране
3. Привет, Моханадмохи, я обновил ваш код, это все та же ошибка
4. Пожалуйста, проверьте правку 2
5. Дорогой Моханадмохи, я продолжаю обновлять ваш шаг редактирования 2, очищать и перестраивать проект, после завершения загрузки данных на экран экран становится пустым. Как вы думаете, свойство в моем xml неверно?
Ответ №2:
Я записываю только изменения в вашем коде вместе со строками над и под ним.
Изменения
- Ваш
ArrayList
естьnull
. Инициализируйте его. - Создайте переменную для адаптера, поскольку вам нужно будет вызвать
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
...
}
}
Комментарии:
1. Привет, Кей Нирадж Лал, я отсылаю к твоему ответу, он хороший, но это та же ошибка. Диалоговое окно выполнения не останавливается: «производитель загрузки, пожалуйста, подождите …»
2. Logcart возвращает результат в формате json: Список производителей, исключений нет. Но данные не могут отображаться на экране