Passing ArrayList from AsyncTask to PagerAdapter - android

hope you fine and well,
i have the following main class :
public class MainActivity extends AppCompatActivity {
Activity activity;
ViewPager viewPager;
CustomAdapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
viewPager=(ViewPager)findViewById(R.id.view_pager);
adapter=new CustomAdapter(this);
viewPager.setAdapter(adapter);
ConnectionAsyncTask connectionAsyncTask = new
ConnectionAsyncTask(MainActivity.this);
connectionAsyncTask.execute("http://www.mocky.io/v2/570d3677270000f600dc29b6");
}
public void showUploader()
{
// findViewById(R.id.progressBar1).setVisibility(View.VISIBLE);
}
public void hideUploader()
{
//findViewById(R.id.progressBar1).setVisibility(View.GONE);
}
public void DisplyOnTextView(List< Student > students) {
List <Student> my = students ;
}
}
when i run the app, this main activity will use another class to read json data from link as follows:
public class StudentJasonParser {
public static List<Student> getObjectFromJason(String jason)
{
List<Student> students;
try {
JSONArray jsonArray = new JSONArray(jason);
students = new ArrayList<>();
for(int i=0;i<jsonArray.length();i++)
{
JSONObject jsonObject = new JSONObject();
jsonObject= (JSONObject) jsonArray.get(i);
Student student = new Student();
student.setID(jsonObject.getInt("id"));
student.setName(jsonObject.getString("name"));
student.setUrl(jsonObject.getString("url"));
student.setDes(jsonObject.getString("des\n"));
student.setRate(jsonObject.getDouble("rate"));
student.setLon(jsonObject.getDouble("lon"));
student.setLat(jsonObject.getDouble("lat"));
students.add(student);
}
} catch (JSONException e) {
e.printStackTrace();
return null;
}
return students;
}
}
now this class will return the data to the following class :
public class ConnectionAsyncTask extends AsyncTask<String,String,String> {
Activity activity;
public ConnectionAsyncTask(Activity activity) {
this.activity=activity;
}
#Override
protected void onPreExecute() {
//((MainActivity)activity).DisplyOnTextView();
((MainActivity)activity).showUploader();
}
#Override
protected String doInBackground(String... params) {
String content =HttpManager.getData(params[0]);
return content;
}
#Override
protected void onProgressUpdate(String... values) {
super.onProgressUpdate(values);
}
#Override
protected void onPostExecute(String s) {
((MainActivity)activity).hideUploader();
List<Student> students= StudentJasonParser.getObjectFromJason(s);
if (students != null) {
((MainActivity) activity).DisplyOnTextView(students);
}
}
}
this line : ((MainActivity)activity).DisplyOnTextView(students);
will return the fetched data to the main class in the following function (mentioned in the main class ! )
public void DisplyOnTextView(List< Student > students) {
List <Student> my = students ;
}
now what i want is to pass this list to the following class in order to use it in the imageView and textView in the viewPager instead of the pre-defined data in the class :
public class CustomAdapter extends PagerAdapter {
private int[] images = {R.drawable.sample_0,R.drawable.sample_1};
private Context ctx;
private LayoutInflater LayoutInflater;
public CustomAdapter(Context ctx)
{
this.ctx=ctx;
}
#Override
public int getCount() {
return images.length;
}
#Override
public boolean isViewFromObject(View view, Object object) {
return (view==(LinearLayout)object);
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
LayoutInflater = (LayoutInflater)ctx.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = LayoutInflater.inflate(R.layout.slide_layout,container,false);
ImageView imageView =(ImageView) view.findViewById(R.id.image_view);
TextView textView = (TextView)view.findViewById(R.id.image_count);
imageView.setImageResource(images[position]);
textView.setText(""+position);
container.addView(view);
return view;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((LinearLayout) object);
}
}
any idea ?!
thanks, regards.

what i want is to pass this list to the following class in order to use it in the imageView and textView in the viewPager
Then simply pass in the list as a parameter to the adapter and add a member variable for it. The usage of this adapter is at the bottom of this post, because I want to mention some other stuff.
class CustomAdapter extends PagerAdapter {
private Context ctx;
private List<Student> data;
public CustomAdapter(Context ctx, List<Student> students) {
this.ctx = ctx;
this.data = students;
}
If you want to use that data variable in the instantiateItem method, then you can do Student s = this.data.get(position); and use the various methods on the Student object to load the TextView or ImageView.
Please note that you will need an image loading library (Picasso, Glide, Fresco, etc.) to load a URL into an ImageView. While on the topic of libraries, though, you will save yourself much development time by looking into Gson for JSON parsing and Retrofit or Volley for HTTP network calls with JSON data.
As for your usage of the AsyncTask, passing around the Activity variable is bad practice. Try to use an asynchronous callback to the Activity instead.
public interface AsyncResponse<T> {
void onResponse(T response);
}
public class ConnectionAsyncTask extends AsyncTask<String, Void, List<Student>> {
private AsyncResponse<List<Student>> callback;
public ConnectionAsyncTask(AsyncResponse<List<Student>> callback) {
this.callback = callback;
}
#Override
protected List<User> doInBackground(String... params) {
String url = params[0];
final List<Student> students = new ArrayList<Student>();
// TODO: JSON stuff
return students;
}
#Override
protected void onPostExecute(List<Student> result) {
if (this.callback != null) {
this.callback.onResponse(result);
} else {
Log.w("ConnectionAsyncTask", "Ignoring result");
}
}
}
public class SampleViewPagerActivity extends Activity {
private ViewPager pager;
private PagerAdapter adapter;
private ArrayList<Student> students;
private ProgressDialog progress;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 1. Inflate a layout
setContentView(R.layout.viewpager_activity);
// 2. Initialize the views
this.pager = (ViewPager) findViewById(R.id.pager);
this.progress = new ProgressDialog(this);
this.progress.setTitle("Loading");
this.progress.setMessage("Please wait");
// 3. Populate the views with data
this.students = new ArrayList<Student>();
this.adapter = new CustomAdapter(this, students);
this.pager.setAdapter(adapter);
// This code runs later, after 'execute' is called and the response is returned
ConnectionAsyncTask task = new ConnectionAsyncTask(new AsyncResponse<List<Student>>() {
#Override
public void onResponse(List<Student> response) {
students.clear();
students.addAll(response);
adapter.notifyDataSetChanged();
progress.hide();
}
});
// Optionally show some progress while waiting
this.progress.show();
// TODO: Use real URL
task.execute("http://www.somesite.com/data");
}
}

Related

RecyclerView is not updated when notifyDataSetChanged is used with MVVM

I am working with MVVM. Main screen shows movie's posters only during debugging (and not during regular run).
The problem is in observation of RecyclerView population. There is Observer in MainActivity. I expect that notifyDataSetChanged method will cause
posters to appear after receiving data from the API, but it doesn't happen.
My cleaned code related to this issue only is available in https://github.com/RayaLevinson/Test
I am missing some important point related to Observer. Please help me! Thank you.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRecyclerView = findViewById(R.id.recycler_view_movie);
mMainActivityViewModal = ViewModelProviders.of(this).get(MainActivityViewModel.class);
mMainActivityViewModal.init();
mMainActivityViewModal.getMovies().observe(this, new Observer<List<Movie>>() {
#Override
public void onChanged(#Nullable List<Movie> movies) {
mAdapter.notifyDataSetChanged();
}
});
initRecyclerView();
}
private void initRecyclerView() {
mAdapter = new RecyclerViewAdapter(this, mMainActivityViewModal.getMovies().getValue());
mRecyclerView.setLayoutManager(new GridLayoutManager(this, 2));
mRecyclerView.setAdapter(mAdapter);
}
MovieRepository.java
public class MovieRepository {
private static final String TAG = "MovieRepository";
private static String mSortBy = "popular";
private static MovieRepository instance;
private List<Movie> movies = new ArrayList<>();
public static MovieRepository getInstance() {
if (instance == null) {
instance = new MovieRepository();
}
return instance;
}
public MutableLiveData<List<Movie>> getMovies() {
setMovies();
MutableLiveData<List<Movie>> data = new MutableLiveData<List<Movie>>();
data.setValue(movies);
return data;
}
private void setMovies() {
Context context = GlobalApplication.getAppContext();
if (NetworkUtils.isNetworkAvailable(context)) {
movies.clear();
new MovieRepository.FetchMoviesTask().execute(mSortBy);
} else {
alertUserAboutNetworkError();
}
}
private void alertUserAboutNetworkError() {
Context context = GlobalApplication.getAppContext();
// Toast.makeText(context, R.string.networkErr, Toast.LENGTH_LONG).show();
}
private class FetchMoviesTask extends AsyncTask<String, Void, List<Movie>> {
#Override
protected List<Movie> doInBackground(String... params) {
if (params.length == 0) {
return null;
}
String sortBy = params[0];
Log.d(TAG, "In doInBackground " + sortBy);
URL moviesRequestUrl = NetworkUtils.buildUrl(sortBy);
try {
String jsonWeatherResponse = NetworkUtils.getResponseFromHttpUrl(moviesRequestUrl);
return MovieJsonUtils.getMoviesDataFromJson(jsonWeatherResponse);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
#Override
protected void onPostExecute(List<Movie> parsedMoviesData) {
if (parsedMoviesData != null) {
for (Movie movie : parsedMoviesData) {
movies.add(movie);
Log.d(TAG, "In onPostExecute " + " movie was added");
}
}
}
}
}
MainActivityViewModel.java
public class MainActivityViewModel extends ViewModel {
private MutableLiveData<List<Movie>> mMovies;
private MovieRepository mMoviewRepository;
public void init() {
if (mMovies != null) {
return;
}
mMoviewRepository = MovieRepository.getInstance();
mMovies = mMoviewRepository.getMovies();
}
public LiveData<List<Movie>> getMovies() {
return mMovies;
}
}
RecyclerViewAdapter.java
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder> {
private static final String TAG = "RecyclerViewAdapter";
private final Context mContext;
private List<Movie> mMovies;
public RecyclerViewAdapter(Context mContext, List<Movie> movies) {
this.mMovies = movies;
this.mContext = mContext;
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_list_item, parent, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull final ViewHolder holder, int position) {
Log.d(TAG, "onBindViewHolder called");
Picasso.get()
.load(mMovies.get(holder.getAdapterPosition()).getPosterPath())
.placeholder(R.mipmap.ic_launcher)
.into(holder.image);
}
#Override
public int getItemCount() {
return mMovies.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
final ImageView image;
final LinearLayout parentLayout;
private ViewHolder(#NonNull View itemView) {
super(itemView);
image = itemView.findViewById(R.id.image);
parentLayout = itemView.findViewById(R.id.parent_layout);
}
}
public void update(List<Movie> movies) {
mMovies.clear();
mMovies.addAll(movies);
notifyDataSetChanged();
}
}
Your MovieRepository#getMovies() executes the Livedata.setValue() before the AsyncTask finishes. You can see that in your debug output.
What you have to do is to call postValue() (cause your on not on the mainthread) in your onPostExecute() method. Then you have to call mAdapter.update() from the onChanged() method.
Also I would recommend to refactor your ViewModel a little bit. Remove the call to the repository from your init() method and create a new method that only calls the load function from the repo. So if you later on would like to support things like endless scrolling, this will help you a lot.
Just a matter of opinion, but i like to create my observables inside my ViewModel and not in the Repository and pass it along as parameter. Thats how it could look like:
Activity
#Override
protected void onCreate(Bundle savedInstanceState) {
...
viewModel = ViewModelProviders.of(this).get(YOUR_VIEW_MODEL.class);
viewModel.init();
viewModel.getItemsObservable().observe(this, new Observer<List<Item>>() {
#Override
public void onChanged(#Nullable List<Item> items) {
// Add/replace your existing adapter
adapter.add/replaceItems(items);
// For better performance when adding/updating elements you should call notifyItemRangeInserted()/notifyItemRangeChanged(). For replacing the whole dataset notifyDataSetChanged() is fine
adapter.notifyDataSetChanged();
// Normally i would put those calls inside the adapter and make appropriate methods but for demonstration.
}
});
initRecyclerView();
viewModel.loadItems()
}
ViewModel
public void init(){
repository = Repository.getInstance();
}
public void loadItems(){
repository.loadItems(getItemsObservable());
}
public LiveData<List<Item>> getItemsObservable() {
if (items == null) {
items = new MutableLiveData<>();
}
return items;
}
Repository
public void loadItems(LiveData<List<Item>> liveData){
List<Item> data = remote.getDataAsync(); // get your data asynchronously
liveData.postValue(data); // call this after you got your data, in your case inside the onPostExecute() method
}

How set Jsoup data to RecyclerView in AsyncTask

I'm parsing website title from URL, and set this title to RecyclerView item. When I call constructor, but I must use AsyncTasck for correctly work Jsoup. How can I set received data to RecyclerView?
I can do public MyAsyncTasck instead of private, but i don't now if it is right.
My MainActivity.java:
public class MainActivity extends AppCompatActivity {
public static final String TAG = "mLog";
#BindView(R.id.recycler_view)
RecyclerView recyclerView;
#BindView(R.id.imageView)
ImageView imageView;
private RecyclerView.Adapter adapter;
private List<ListItem> listItems;
ListItem item;
String URL = "https://sinoptik.ua/%D0%BF%D0%BE%D0%B3%D0%BE%D0%B4%D0%B0-
%D0%B2%D0%B8%D0%BD%D0%BD%D0%B8%D1%86%D0%B0";
Document document;
// Received data from Jsoup
String head = "something";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
MyAsyncTask myAsyncTask = new MyAsyncTask();
myAsyncTask.execute();
recyclerView.setLayoutManager(new LinearLayoutManager(this));
listItems = new ArrayList<>();
item = new ListItem(head, "desc1");
listItems.add(item);
adapter = new MyRecViewAdapter(listItems, this);
recyclerView.setAdapter(adapter);
}
private class MyAsyncTask extends AsyncTask<Void, Void, Void> {
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected Void doInBackground(Void... voids) {
try {
document = Jsoup.connect(URL).get();
head = document.title();
} catch (IOException e ) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
// ??????
}
}
}
And MyRecViewAdapter.java:
public class MyRecViewAdapter extends RecyclerView.Adapter<MyRecViewAdapter.ViewHolder>{
private List<ListItem> listItems;
private Context context;
public MyRecViewAdapter(List<ListItem> listItems, Context context) {
this.listItems = listItems;
this.context = context;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext())
.inflate(R.layout.list_item, parent, false);
//return our view
return new ViewHolder(v);
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
ListItem listItem = listItems.get(position);
holder.tvHead.setText(listItem.getHead());
holder.tvDesc.setText(listItem.getDesc());
}
#Override
public int getItemCount() {
return listItems.size();
}
public static class ViewHolder extends RecyclerView.ViewHolder {
public TextView tvHead;
public TextView tvDesc;
public ViewHolder(View itemView) {
super(itemView);
tvHead = (TextView) itemView.findViewById(R.id.tv_head);
tvDesc = (TextView) itemView.findViewById(R.id.tv_desc);
}
}
}
And the ListItem.java
public class ListItem {
private String head;
private String desc;
public ListItem(String head, String desc) {
this.head = head;
this.desc = desc;
}
public String getHead() {
return head;
}
public String getDesc() {
return desc;
}
}
You need to set the data got from your API call using the AsyncTask into your listItems which are being represented in your RecyclerView. Then you need to call notifyDataSetChanged in order to show the newly updated the in your RecyclerView.
So you need to modify the doInBackground function in your AsyncTask like the following.
private class MyAsyncTask extends AsyncTask<Void, Void, Void> {
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected Void doInBackground(Void... voids) {
try {
document = Jsoup.connect(URL).get();
listItems.clear();
ListItem item = new ListItem(document.title, document.desc);
listItems.add(item);
adapter.notifyDataSetChanged();
} catch (IOException e ) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
// ??????
}
}

How to update an item on a recyclerview after excuting AsyncTask doInBackground?

I'm creating a chat feature for an application and it works super fine. But I would like to show the user that message has been sent or it still wating for the server's response.
Fields:
List<ChatMessage> chatMessages;
ChatAdapter chatAdapter;
RecyclerView chatRecyclerView;
ImageButton submitMessageBtn;
this how I send a message on my ChatActivity class:
public void submitMessage(final String messageType, final byte[] message){
final ChatMessageResponse messageObject = new ChatMessageResponse();
new AsyncTask<Void, Void, Void>() {
#Override
protected void onPreExecute() {
super.onPreExecute();
messageObject.setMessage( message);
messageObject.setYours(true);
messageObject.setUserNickname(getNickname());
messageObject.setCreationDate(DateTime.now().withZone(DateTimeZone.UTC));
messageObject.setType(messageType);
AddMessage(messageObject);
}
#Override
protected Void doInBackground(Void... voids) {
try {
chatClient.chat().sendMessage(eventId, messageType, message);
runOnUiThread(new Runnable() {
#Override
public void run() {
// Update message on the list after has been sent to server
}
});
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}.execute();
}
public void AddMessage(ChatMessage message)
{
chatMessages.add(message);
chatAdapter.notifyDataSetChanged();
chatRecyclerView.scrollToPosition(chatMessages.size() -1);
}
When message is immediatly added to the adapter it should look like this:
my ChatAdapter class is setup like this:
public class ChatAdapter extends RecyclerView.Adapter<ChatAdapter.ChatViewHolder> {
private static final int VIEW_TYPE_MESSAGE_THIS_USER = 0;
private static final int VIEW_TYPE_MESSAGE_OTHER_USER = 1;
private final Activity activity;
public List<ChatMessage> chats=new ArrayList<>();
ArrayList<String> usercolor=new ArrayList<>();
Context mContext;
View view;
public ChatAdapter(List<ChatMessage> chats, Context mContext, Activity activity) {
this.chats = chats;
this.mContext = mContext;
this.activity = activity;
}
#Override
public ChatViewHolder onCreateViewHolder(ViewGroup parent, int viewType){
mContext = parent.getContext();
if (viewType == VIEW_TYPE_MESSAGE_OTHER_USER) {
view = View.inflate(mContext, R.layout.message_item_left, null);
} else if (viewType == VIEW_TYPE_MESSAGE_THIS_USER){
view = View.inflate(mContext, R.layout.message_item, null);
}
return new ChatViewHolder(view,(View.OnLongClickListener)activity);
}
#Override
public void onBindViewHolder(final ChatViewHolder holder, int position){
final ChatMessageResponse m = (ChatMessageResponse) chats.get(position);
if (getItemViewType(position) == VIEW_TYPE_MESSAGE_OTHER_USER){
holder.bindToView1(m);
} else if (getItemViewType(position) == VIEW_TYPE_MESSAGE_THIS_USER)
{
holder.bindToView(m);
}
}
#Override
public int getItemCount() {
return chats.size();
}
#Override
public int getItemViewType(int position) {
return chats.get(position).isYours() ? VIEW_TYPE_MESSAGE_THIS_USER : VIEW_TYPE_MESSAGE_OTHER_USER;
}
}
When the server's response is positive the views in the ChatViewHolder (that I don't show the code because is too long) should change visibility state
Someone told me to get a referece for the view and change it on the activity's asynctask or create a Callback listener for my adapter.
But I have no Idea how to do either one of then any help is appreciated.
Are you familiar with the use of "Callbacks" or "Interfaces"? You can create an interface and implement it in your activity. Pass the callback by parameters in the "AsyncTask" and use it there.
//Interface class
/**
* Created by gmora
*/
public interface IProcess {
void updateAdapter(String result);
}
On Activity:
public class YourActivity extends AppCompatActivity {
private IProcess mProcess;
private Adapter mRecyclerAdapter;
private RecyclerView mRecyclerView;
private List<ChatMessage> chats; //update chats on activity and refresh your adapter
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_layout);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
mProcess = new IProceso() {
#Override
public void updateAdapter(String pException) {
//update chats ... and update mAdater.notifyDataChange()...
// or mRecyclerView.setAdapter(new Adpater.... with new list chats)..
}
};
mRecyclerView = find....
// etc....
mRecyclerAdapter = new RecyclerAdapter( chats, ...);
mRecyclerView.setAdapter(mRecyclerAdapter);
}
}
Finally on AsyncTask... create a external class from AsyncTask please!
/**
* Created by gmora.
*/
public class YourAsyncTaskClass extends AsyncTask<String, Void, String > {
private IProcess iProcess;
public StarSearchPrinterTask(IProcess pIProcess) {
this.iProcess= pIProcess;
}
#Override
protected void onPreExecute() {
//loading... its optional
}
#Override
protected String doInBackground(String... interfaceType) {
// execute webservice or api and get results..
return results;
}
#Override
protected void onPostExecute(String results) {
mIProceso.updateAdapter(results);
}
}

Display Image from clicked item of Recyclerview

I am trying to get the image string from the recyclerview, that is already populated, so that I can display the image on the imageview of another activity. Here, I get the path(url) of image using jsoup:
org.jsoup.nodes.Document document = Jsoup.connect(URL).get();
for(Element e : document.select("img[src]"))
{
Elements imgScr = e.select("img[src]");
String elements = imgScr.attr("src");
String text = imgScr.attr("alt");
String desc = imgScr.attr("title");
arrayList.add(new FeedItem(text, elements, desc));
}
into elements variable and then storing it into arraylist. I want to get that path(url) of image(stored in elements) so that I can display that image in another activity. I tried to retrieve that url from the arrayList using this method:
public String getImageUrl(int pos)
{
return arrayList.get(pos).getThumb();
}
but a IndexOutOfBound exception is thrown, saying that the index(pos) is invalid and size of arrayList is 0. I don't know why it is saying that the list has size 0, while the Recyclerview gets pouplated and shows the data which I parsed using jsoup. Please help me out guys, I am stuck on this for three days.
Okay the complete code is here:
This the main activity which shows the recyclerview
public class RestaurantsAndCafesActivity extends Activity {
public static final String URL = "http://192.168.8.102:80/jay.html";
private RecyclerView mRecyclerView;
private RCRecyclerAdapter adapter;
public String imgUrl;
//public List<FeedItem> feedItemList;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.reyclerview_layout);
/* Initialize RecyclerView */
mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
//parseResult();
new getDataAsyncTask().execute();
final GestureDetector mGestureDetector = new GestureDetector(RestaurantsAndCafesActivity.this, new GestureDetector.SimpleOnGestureListener() {
#Override public boolean onSingleTapUp(MotionEvent e) {
return true;
}
});
mRecyclerView.addOnItemTouchListener(new RecyclerView.OnItemTouchListener() {
#Override
public boolean onInterceptTouchEvent(RecyclerView recyclerView, MotionEvent motionEvent) {
View child = recyclerView.findChildViewUnder(motionEvent.getX(),motionEvent.getY());
if(child!=null && mGestureDetector.onTouchEvent(motionEvent)){
Toast.makeText(RestaurantsAndCafesActivity.this,"Clicked Number "+recyclerView.getChildPosition(child), Toast.LENGTH_SHORT).show();
imgUrl = new getDataAsyncTask().getImageUrl(recyclerView.getChildPosition(child));
Intent intent = new Intent(RestaurantsAndCafesActivity.this, GetReviewActivity.class);
intent.putExtra("Imgurl" ,imgUrl);
startActivity(intent);
return true;
}
return false;
}
#Override
public void onTouchEvent(RecyclerView recyclerView, MotionEvent motionEvent) {
}
});
}
public class getDataAsyncTask extends AsyncTask<Void,Void,Void>{
ArrayList<FeedItem> arrayList = new ArrayList<>();
public String getImageUrl(int pos)
{
return arrayList.get(pos).getThumb();
}
#Override
protected Void doInBackground(Void... params) {
try {
org.jsoup.nodes.Document document = Jsoup.connect(URL).get();
for(Element e : document.select("img[src]"))
{
Elements imgScr = e.select("img[src]");
String elements = imgScr.attr("src");
String text = imgScr.attr("alt");
String desc = imgScr.attr("title");
arrayList.add(new FeedItem(text, elements, desc));
}
}
catch(IOException e)
{
e.printStackTrace();
}
return null;
}
ProgressDialog progressDialog;
#Override
protected void onPreExecute()
{
progressDialog = ProgressDialog.show(RestaurantsAndCafesActivity.this,"Loading","Please Wait",true,false);
}
#Override
protected void onPostExecute(Void aVoid) {
progressDialog.dismiss();
adapter = new RCRecyclerAdapter(getApplicationContext(),arrayList);
mRecyclerView.setAdapter(adapter);
}
}
}
These are the adapter, viewholder and data classes:
public class RCRecyclerAdapter extends RecyclerView.Adapter<RCRecyclerViewListRowHolder> {
private List<FeedItem> feedItemList;
private Context mContext;
public RCRecyclerAdapter(Context context, List<FeedItem> feedItemList) {
this.feedItemList = feedItemList;
this.mContext = context;
}
#Override
public RCRecyclerViewListRowHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.restaurants_cafes_layout_card, null);
RCRecyclerViewListRowHolder mh = new RCRecyclerViewListRowHolder(v);
return mh;
}
#Override
public void onBindViewHolder(RCRecyclerViewListRowHolder RCRecyclerViewListRowHolder, int i){
FeedItem feedItem = feedItemList.get(i);
Picasso.with(mContext).load(feedItem.getThumb()
).error(R.drawable.placeholder).placeholder(R.drawable.placeholder).into(RCRecyclerViewListRowHolder.thumbnail);
RCRecyclerViewListRowHolder.title.setText(feedItemList.get(i).title);
RCRecyclerViewListRowHolder.desc.setText(feedItemList.get(i).desc);
}
#Override
public int getItemCount() {
return (null != feedItemList ? feedItemList.size() : 0);
}
}
viewholder:
public class RCRecyclerViewListRowHolder extends RecyclerView.ViewHolder {
public ImageView thumbnail;
public TextView title;
public TextView desc;
//Context context;
public RCRecyclerViewListRowHolder(View view) {
super(view);
this.thumbnail = (ImageView) view.findViewById(R.id.thumbnail);
this.title = (TextView) view.findViewById(R.id.title);
this.desc = (TextView) view.findViewById(R.id.desc);
}
}
data:
public class FeedItem {
public String title;
public String thumb;
public String desc;
public FeedItem(String title, String thumb , String desc) {
this.title = title;
this.thumb = thumb;
this.desc = desc;
}
public String getThumb() {
return thumb;
}
}
Here is the culprit:
imgUrl = new getDataAsyncTask().getImageUrl(recyclerView.getChildPosition(child));
You're actually creating a new AsyncTask - if you try to get an element from the arrayList inside that new AsyncTask it's obvious the list is empty, because task populates the list within its doInBackground() method, and it hasn't been executed.
Solution:
In your onCreate method, create your getDataAsyncTask and keep a reference to it in a member variable.
Then, when the task finishes its execution and calls onPostExecute(Void aVoid) set a flag indicating that fact.
Next, in your onClickListener, reference the same task, but execute the code only if the asyncTaskFinished flag is set to true:
public class RestaurantsAndCafesActivity extends Activity {
public static final String URL = "http://192.168.8.102:80/jay.html";
private RecyclerView mRecyclerView;
private RCRecyclerAdapter adapter;
public String imgUrl;
//public List<FeedItem> feedItemList;
private getDataAsyncTask myAsyncTask;
private volatile boolean asyncTaskFinished = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.reyclerview_layout);
/* Initialize RecyclerView */
mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
//parseResult();
myAsyncTask = new getDataAsyncTask();
myAsyncTask.execute();
...
mRecyclerView.addOnItemTouchListener(new RecyclerView.OnItemTouchListener() {
#Override
public boolean onInterceptTouchEvent(RecyclerView recyclerView, MotionEvent motionEvent) {
View child = recyclerView.findChildViewUnder(motionEvent.getX(),motionEvent.getY());
if(child!=null && mGestureDetector.onTouchEvent(motionEvent)){
if(asyncTaskFinished) {
Toast.makeText(RestaurantsAndCafesActivity.this,"Clicked Number "+recyclerView.getChildPosition(child), Toast.LENGTH_SHORT).show();
imgUrl = myAsyncTask.getImageUrl(recyclerView.getChildPosition(child));
Intent intent = new Intent(RestaurantsAndCafesActivity.this, GetReviewActivity.class);
intent.putExtra("Imgurl" ,imgUrl);
startActivity(intent);
return true;
}
return false;
}
}
In AsyncTask:
#Override
protected void onPostExecute(Void aVoid) {
progressDialog.dismiss();
adapter = new RCRecyclerAdapter(getApplicationContext(),arrayList);
mRecyclerView.setAdapter(adapter);
asyncTaskFinished = true;
}
Please note that it is a solution that makes minimal changes in your existing code, however i would suggest a different approach - keeping the list in AsyncTask is kinda ugly, better way is to return it from doInBackground, and within onPostExecute, pass it to adapter (while not keeping a class-scope reference to it in the task), and when you need to access an element fromn the list, just reference the adapter, not your AsyncTask:
imgUrl = adapter.getList().get(recyclerView.getChildPosition(child)).getThumb();

Using a variable in two different methods

Am trying to use jsoup library in my android application and i want to get the value of str1 in the description class and use it in MyAdapter class as items.add(new Item(str1, R.drawable.flag_one)); i can't figure it out, any help is highly appreciated
public class HomeFragment extends Fragment {
// URL Address
String url = "http://www.livescore.com";
public HomeFragment(){}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final View rootView = inflater.inflate(R.layout.fragment_home, container, false);
getOverFlowMenu();
GridView gridView = (GridView)rootView.findViewById(R.id.gridview);
gridView.setAdapter(new MyAdapter(rootView.getContext()));
new Description();
return rootView;
}
private void getOverFlowMenu() {
}
//Description async task
class Description extends AsyncTask<Void, Void, Void>{
String desc;
#Override
protected Void doInBackground(Void... voids) {
try{
// Connect to the web site
Document document = Jsoup.connect(url).get();
Element content = document
.body().getElementsByClass("kubrick-info__title").first();
// Locate the content attribute
desc = content.text();
}catch (IOException e){
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void result){
// Set description into TextView
String str1 = desc;
}
}
private class MyAdapter extends BaseAdapter
{
private List<Item> items = new ArrayList<Item>();
private LayoutInflater inflater;
public MyAdapter(Context context)
{
inflater = LayoutInflater.from(context);
items.add(new Item(str1, R.drawable.flag_one));
items.add(new Item("teams", R.drawable.flag_two));
}
#Override
public int getCount() {
return items.size();
}
#Override
public Object getItem(int i)
{
return items.get(i);
}
#Override
public long getItemId(int i)
{
return items.get(i).drawableId;
}
}
Can you declare static String str1 = "" at the top, right under public class HomeFragment extends Fragment? Then in your onPostExecute method:
#Override
protected void onPostExecute(Void result){
// Set description into TextView
str1 = desc;
}
The idea is that if it the String is declared at the top, it will be visible throughout the entire HomeFragment class.

Categories

Resources