2015-05-10 2 views
4

Я переношу с ListView на RecyclerView, и последнее, что я застрял, обновляет одно из полей. У моего приложения есть простой список с некоторыми изображениями, найденными в Интернете. Когда вы выбираете один, изображение загружается в телефон для последующего автономного просмотра. Адаптер получает данные от SQLite database, поэтому, когда вы нажимаете на какую-то базу данных изображений, обновляется (изменения текста от «Нажмите здесь, чтобы загрузить» на номер «Скачан») и RecyclerView.Не удалось обновить поле TextView внутри RecyclerView

У меня была такая же проблема с ListView, но там я только что называл populateList(); каждый раз, когда приложение обновлялось db. Я знаю, что это не идеальное решение, но оно сработало. Теперь я хочу сделать это правильно с notifyDataSetChanged() или даже лучше notifyItemChanged(position), но я не могу заставить его работать.

В любом случае, вот код, извините за то, что он немного грязный. Это просто тестовый код (RecyclerView код из образцов):

public class RecyclerFragment extends Fragment { 

    private imgAdapter mAdapter; 
    private DatabaseHandler db; 
    private ProgressDialog mProgressDialog; 


    public RecyclerFragment() { 
    } 

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



     db = new DatabaseHandler(getActivity()); 
     List<Images> listdb = db.getImages(); 
     mAdapter = new ImgAdapter(getActivity(), listdb); 
     db.close(); 

     View view = inflater.inflate(R.layout.fragment_main, container, false); 
     RecyclerView recyclerView = (RecyclerView) view.findViewById(android.R.id.list); 
     recyclerView.addItemDecoration(new DividerItemDecoration(getActivity(), DividerItemDecoration.VERTICAL_LIST)); 
     recyclerView.setHasFixedSize(true); 
     recyclerView.setLayoutManager(new GridLayoutManager(
       getActivity(), getResources().getInteger(R.integer.list_columns))); 
     recyclerView.setAdapter(mAdapter); 
     return view; 
    } 


    private class ImgAdapter extends RecyclerView.Adapter<ViewHolder> 
      implements ItemClickListener { 

     public List<Images> mList; 
     private Context mContext; 

     public ImgAdapter(Context context, List<Images> listdb) { 
      super(); 
      mContext = context; 
      mList = listdb; 
     } 

     @Override 
     public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 
      LayoutInflater inflater = LayoutInflater.from(mContext); 
      View view = inflater.inflate(R.layout.list_row1, parent, false); 
      return new ViewHolder(view, this); 
     } 

     @Override 
     public void onBindViewHolder(final ViewHolder holder, final int position) { 
      Images image = mList.get(position); 
      holder.mTitle.setText(image.getTitle()); 
      holder.mDownloadStatus.setText(image.getDownloadStatus()); 
     } 

     @Override 
     public long getItemId(int position) { 
      return position; 
     } 

     @Override 
     public int getItemCount() { 
      return mList == null ? 0 : mList.size(); 
     } 


     @Override 
     public void onItemClick(View view, int position) { 
      switch (position) { 
       case 0: 
        Log.v("POSITION 0:", " " + position); 
        break; 
       case 1: 
        /* 
        some logic nvm 
        */ 
        String imgurl = "http:/..."; 
        String imagename = "Second image"; 
        new GetImages(imgurl, imagename).execute(); 

        /* 
        I've tried mAdapter.notitfy... , no luck aswell 
        This does nothing: 
        */ 
        notifyItemChanged(position); 
        notifyDataSetChanged(); 
       break; 
       //.... 

      } 
     } 
    } 

    private static class ViewHolder extends RecyclerView.ViewHolder 
      implements View.OnClickListener { 

     TextView mTitle; 
     TextView mDownloadStatus; 
     ItemClickListener mItemClickListener; 

     public ViewHolder(View view, ItemClickListener itemClickListener) { 
      super(view); 
      mTitle = (TextView) view.findViewById(R.id.text1); 
      mDownloadStatus = (TextView) view.findViewById(R.id.text2); 
      mItemClickListener = itemClickListener; 
      view.setOnClickListener(this); 
     } 

     @Override 
     public void onClick(View v) { 
      mItemClickListener.onItemClick(v, getPosition()); 
     } 
    } 

    interface ItemClickListener { 
     void onItemClick(View view, int position); 
    } 

    /* 
    This is my AsyncTask class used for downloading image and updating db 
    I removed some code just to to make it cleaner 
     */ 
    private class GetImages extends AsyncTask<Object, Object, Object> { 
     private final String requestUrl; 
     private final String imagename_; 
     private String imagename; 
     public int numberofbits; 


     private GetImages(String requestUrl, String _imagename_) { 
      this.requestUrl = requestUrl; 
      this.imagename_ = _imagename_; 
     } 

     @Override 
     protected void onPreExecute() { 
      super.onPreExecute(); 
      //pDialog... 
     } 

     @Override 
     protected Object doInBackground(Object... objects) { 
      try { 
       URL url = new URL(requestUrl); 
       URLConnection conn = url.openConnection(); 
       bitmap = BitmapFactory.decodeStream(conn.getInputStream()); 
       numberofbits = bitmap.getByteCount(); 
      } catch (Exception ignored) { 
      } 
      return null; 
     } 


     @Override 
     protected void onPostExecute(Object o) { 
      if (!ImageStorage.checkifImageExists(imagename)) { 
       ImageStorage.saveToSdCard(bitmap, imagename_); 
      } 

      if (numberofbits > 50) { 
       db = new DatabaseHandler(getActivity()); 
       db.updateImages(new Images(dbid, "Downloaded", imagename_)); 
       db.close(); 
       //populateList(); -> THIS I USED FOR A LISTVIEW 
       Toast.makeText(getActivity(), "Downloaded!", Toast.LENGTH_SHORT).show(); 
       mProgressDialog.dismiss(); 

       //If image gets downloaded open it in Viewer class 
       Intent intent = new Intent(getActivity(), DisplayImage.class); 
       intent.putExtra("imagePath", path); 
       startActivity(intent); 

      } else { 
       //Toast.makeText(getActivity(), "Unable to download", Toast.LENGTH_SHORT).show(); 
       mProgressDialog.dismiss(); 

      } 
     } 
    } 
} 

Вот Изображения класса

public class Images { 

    //private variables 
    private int _id; 
    private String _title; 
    private String _downloadstatus; 

    // Empty constructor 
    public Images() { 

    } 

    // constructor 
    public Images(int id, String title, String downloadstatus) { 
     this._id = id; 
     this._title = title; 
     this._downloadstatus = downloadstatus; 
    } 


    public int getID() { 
     return this._id; 
    } 

    public void setID(int id) { 
     this._id = id; 
    } 

    public String getTitle() { 
     return this._title; 
    } 

    public void setTitle(String title) { 
     this._title = title; 
    } 


    public String getDownloadStatus() { 
     return this._downloadstatus; 
    } 

    public void setDownloadStatus(String downloadstatus) { 
     this._downloadstatus = downloadstatus; 
    } 
} 

И вот XML (я пытаюсь обновить "text2"):

<?xml version="1.0" encoding="utf-8"?> 
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="match_parent" 
    android:foreground="?attr/selectableItemBackground" 
    android:layout_height="wrap_content" 
    android:padding="8dp"> 

    <RelativeLayout 
     android:layout_width="fill_parent" 
     android:layout_height="match_parent" 
     > 


     <TextView 
      android:id="@+id/text1" 
      android:layout_width="wrap_content" 
      android:layout_height="wrap_content" 
      android:textSize="@dimen/imagename" 
      android:textStyle="bold" 
      android:paddingStart="4sp" 
      android:paddingEnd="40sp" /> 

     <TextView 
      android:id="@+id/text2" 
      android:layout_width="wrap_content" 
      android:layout_height="wrap_content" 
      android:layout_below="@+id/text1" 
      android:textSize="@dimen/downloaded" 
      android:paddingStart="4sp" 
      android:paddingEnd="1sp" 
      android:textColor="@color/graydownloaded"  /> 


    </RelativeLayout> 

</FrameLayout> 
+0

ли вы подтвердить, что 'onItemClick' вызывается ?. Вы пытались выполнить 'recyclerView.setAdapter (mAdapter)' вместо 'notifyDataSetChanged (position)' ?. Есть ли у класса Image уникальный идентификатор целого числа, который мы могли бы использовать? – 4gus71n

+0

Да 'onItemClick' действительно работает. Я просто попробовал 'recyclerView.setAdapter (mAdapter)', но не повезло. Я обновил вопрос с помощью класса изображений, и я думаю, вы спрашивали о ID базы данных. :) – besthiroeu

ответ

1

Хорошо, я, наконец, получил это работает, и это было на самом деле довольно просто ...

//....  
if (numberofbits > 50) { 
        db = new DatabaseHandler(getActivity()); 
        db.updateImages(new Images(dbid, "Downloaded", imagename_)); 
        //This is what I added: 
        List<Images> listdb = db.getImages(); 
        mAdapter = new ImgAdapter(getActivity(), listdb); 
        recyclerView.setAdapter(mAdapter); 
        db.close(); 
        //populateList(); -> THIS I USED FOR A LISTVIEW 
        Toast.makeText(getActivity(), "Downloaded!", Toast.LENGTH_SHORT).show(); 
        mProgressDialog.dismiss(); 

        //If image gets downloaded open it in Viewer class 
        Intent intent = new Intent(getActivity(), DisplayImage.class); 
        intent.putExtra("imagePath", path); 
        startActivity(intent); 

       } else { 
//... 
1

Попробуйте сделать это: Override в адаптере метод getItemId как этот

@Override 
public long getItemId(int position) { 
    return mList.get(position).getID(); 
} 

И добавьте эту строку после recyclerView.setHasFixedSize(true):

recyclerView.setHasStableId(true);

EDIT:

mAdapter.setHasStableId(true);

Позвольте мне знать, если это сделал трюк.

+0

Я могу назвать этот метод только в адаптере, как этот 'mAdapter.setHasStableId (true);' но все-таки то же самое. Мое приложение работает на самом деле так: MainActivity -> RecyclerView -> ImageDisplayClass. Если AsyncTask выполняет задание и загружает изображение, он использует намерения, чтобы открыть загруженное изображение в ImageDisplayClass. Дело в том, что если вы вернетесь с ImageDisplayClass, вы увидите «старый» устаревший RecyclerView. Если вы вернетесь в MainActivity, а затем перейдете в RecyclerView, mAdapter будет использовать «новые» правильные данные. Вот почему я использовал repopulate ListViews, чтобы заставить эту работу работать. – besthiroeu

Смежные вопросы