I have a problem with the recycler view and card view. I'm using asynctask to get info from API, and for now I'm getting only a name - which means, I display in my card view only a text view. however, when I'm loading the list, it is awfully slow. in the log cat I can see that the app is getting the data pretty fast, but it takes a lot of time to show it in the recycler view.
I'm adding few samples - from the adapter of the recycler view and the fragment that holds the recycler view in. maybe I did something wrong in the adapter.
Thank you for your help!
Adapter:
public class PlacesListAdapter extends RecyclerView.Adapter<PlacesListAdapter.ListViewHolder>{
ArrayList<PlaceItem> items;
Context context;
public PlacesListAdapter(Context context,ArrayList<PlaceItem> placeItems){
this.context = context;
this.items = placeItems;
}
public void swap(ArrayList<PlaceItem> places){
items.clear();
items.addAll(places);
notifyDataSetChanged();
}
#Override
public ListViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(context).inflate(R.layout.card_view, parent, false);
return new ListViewHolder(v);
}
#Override
public void onBindViewHolder(ListViewHolder holder, int position) {
PlaceItem item = items.get(position);
holder.bindData(item);
}
#Override
public int getItemCount() {
return items.size();
}
public class ListViewHolder extends RecyclerView.ViewHolder{
TextView title;
PlaceItem placeItem;
public ListViewHolder(View itemView) {
super(itemView);
title = (TextView) itemView.findViewById(R.id.txtTitlePlace);
}
public void bindData(PlaceItem item){
this.placeItem = item;
title.setText(placeItem.getTitle());
}
}
}
Fragment:
public class FragmentListPlaces extends Fragment implements View.OnClickListener {
ArrayList<PlaceItem> placeItems;
PlacesListAdapter adapter;
RecyclerView list;
EditText editName;
public FragmentListPlaces() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View v = inflater.inflate(R.layout.fragment_list_places, container, false);
editName = (EditText) v.findViewById(R.id.editPlaceName);
v.findViewById(R.id.btnGetLocations).setOnClickListener(this);
v.findViewById(R.id.btnSearchByText).setOnClickListener(this);
placeItems = new ArrayList<>();
placeItems.add(new PlaceItem("Example"));
adapter = new PlacesListAdapter(getContext(), placeItems);
list = (RecyclerView) v.findViewById(R.id.placesList);
list.setLayoutManager(new LinearLayoutManager(getContext()));
list.setAdapter(adapter);
return v;
}
#Override
public void onClick(View v) {
switch (v.getId()){
case R.id.btnGetLocations:
GetUserLocation location = new GetUserLocation();
location.getLocation(getActivity());
adapter.swap(placeItems);
break;
case R.id.btnSearchByText:
// this is the method loading data with user input
String getNameFromUser = editName.getText().toString();
searchPlaceByText(getNameFromUser);
adapter.swap(placeItems);
break;
}
}
public void searchPlaceByText(String place){
// instantiate the asynctask here
LocationDetailsByText locationDetailsByText = new LocationDetailsByText(placeItems);
locationDetailsByText.execute("http://api.v3.factual.com/t/places-il?q=" + place + "&KEY=AFvDryDJmPkkgXohbpFdqkRQelT9w0HKtyEqXy3G");
}
Loading of data from the web:
public class LocationDetailsByText extends AsyncTask<String, Void, String> {
ArrayList<PlaceItem> placeItems = new ArrayList<>();
public LocationDetailsByText(ArrayList<PlaceItem> places){
this.placeItems = places;
}
#Override
protected String doInBackground(String... params) {
StringBuilder result = new StringBuilder();
BufferedReader reader;
HttpURLConnection connection = null;
URL url;
String query = (params[0]);
try {
url = new URL(query);
connection = (HttpURLConnection)url.openConnection();
if(connection.getResponseCode() != 200){
return "Error!";
}
reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String line = "";
while((line = reader.readLine())!= null){
result.append(line);
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
connection.disconnect();
}
return result.toString();
}
#Override
protected void onPostExecute(String s) {
PlaceItem placeItem;
try {
JSONObject root = new JSONObject(s);
JSONObject response = root.getJSONObject("response");
JSONArray data = response.getJSONArray("data");
for(int i = 0; i < data.length(); i++){
JSONObject getData = data.getJSONObject(i);
String title = getData.getString("name");
placeItem = new PlaceItem(title);
placeItems.add(placeItem);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
Apart from the issue that #M G pointed out that messes up the behavior in general.
you have 2 other major flaws that I can see of which 1) is affecting you mostly.
1) you do all the Json parsing + moving the data to your POJO(PlaceItem[]) onPostExecute. this is wrong!
this can be very heavy on computation
this way you create 2 many intermediate objects lots of GC
I suggest move these to background and use Gson.
2) it seems that you do lots of network calls that could happen quite frequently. This needs better managing of concurrent requests, network connections, threads, streams and data arrays obtained form the network stream. This can cause lots of GC.
I would recommend to use some networking library made for this purpose such as retrofit, volley or jus. These all can handle also parsing network data straight to your POJO in the background and minimizing GC and performance in general.
Few issues with your code
searchPlaceByText(getNameFromUser);
adapter.swap(placeItems);
adapter.swap(placeItems); starts right after you start your AsyncTask but you didn't download anything yet. This is wrong. You should remove adapter.swap(placeItems); from here and do something like this instead:
#Override
public void onClick(View v) {
switch (v.getId()){
case R.id.btnGetLocations:
GetUserLocation location = new GetUserLocation();
location.getLocation(getActivity());
adapter.swap(placeItems);//also here probably
break;
case R.id.btnSearchByText:
// this is the method loading data with user input
String getNameFromUser = editName.getText().toString();
searchPlaceByText(getNameFromUser);
break;
}
}
public void searchPlaceByText(final String place) {
// instantiate the asynctask here
LocationDetailsByText locationDetailsByText = new LocationDetailsByText(placeItems) {
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
adapter.swap(placeItems);
}
};
locationDetailsByText.execute("http://api.v3.factual.com/t/places-il?q=" + place + "&KEY=AFvDryDJmPkkgXohbpFdqkRQelT9w0HKtyEqXy3G");
}
Next thing is that you clear your list
items.clear();
items.addAll(places);
Which is basically also removing everything from your placeItems because erlier in this class you set this.items = placeItems;. So in PlacesListAdapter just do
public void swap(ArrayList<PlaceItem> places){
notifyDataSetChanged();
}
In Your Asynctask, in OnPostExcute, at the end of it notify your adapter about the changes in your data, that's why you cant see your data unless you click on edit text again.
Related
I'm building both background server and android application for food-ordering project.
There is a function that helps customers make sure whether the table is occupied or not. The logic is written in TableActivity.java which I will show down below. Basically the item to inflate the view is a ImageView and a TextView. ImageView is either vacant or occupied while TextView is the number of the table.
The background code is okay that returns a json string that contains the
table number and table flag(1 vacant;0 occupied). But the LogCat gave me null pointer exception. I'll be appreciated if you give some advice.
I use tomcat 7 as server software and servlet to handle the connection between client and database. Background is fine and I think the problem is in my android client codes.
Android SDK version is 27.
public class TableActivity extends Activity {
GridView gv;
List<Table> list;
MyAdapter myAdapter;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.table);
list = new ArrayList<Table>(); //Table is an Entity class
gv = findViewById(R.id.table_gridView);
myAdapter = new MyAdapter();
//init network
String url = "http://10.0.2.2:8080/WL_Server/TableServlet";
new MyTask().execute(url);
gv.setAdapter(myAdapter);
}
/*#param: The url of server servlet
Visit target url, gets the output of the server. The function returns a json that contains info of Tabletbl table.
* */
String doGetTableMsg(String url){
String json = OkHttpUtil.doGet(url);
return json;
}
//异步任务,处理网络请求
class MyTask extends AsyncTask<String, Integer, String>{
#Override
protected String doInBackground(String... strings) {
return doGetTableMsg(strings[0]);
}
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
Gson gson = new Gson();
Type type = new TypeToken<List<Table>>(){}.getType();
list = gson.fromJson(s, type);
myAdapter.notifyDataSetChanged();
}
}
class MyAdapter extends BaseAdapter {
#Override
public int getCount() {
//This return sentence is where the exception happened. But this
// list object has been initiated and assigned with value already?
return list.size();
}
#Override
public Object getItem(int i) {
return null;
}
#Override
public long getItemId(int i) {
return 0;
}
#Override
public View getView(int i, View view, ViewGroup viewGroup) {
View view1;
if (view == null){
//Inflate a view from an XML resource.
view1 = View.inflate(getApplicationContext(), R.layout.table_item, null);
}else {
view1 = view;
}
ImageView imageView1 = view1.findViewById(R.id.itemImageView1);
TextView textView1 = view1.findViewById(R.id.itemTextView1);
//Logic to decide whether table is vacant or not. Totally fine.
Table table = list.get(i);
int flag = table.getFlag();
if (flag == 0){
imageView1.setImageResource(R.drawable.kongwei);
}else {
imageView1.setImageResource(R.drawable.youren);
}
textView1.setText(table.getTid() + "");
return view1;
}
}
}
I expect the emulator will show the view but it gave me null pointer exception like below:
java.lang.NullPointerException: Attempt to invoke interface method 'int java.util.List.size()' on a null object reference
at xuming.com.wl_client.TableActivity$MyAdapter.getCount(TableActivity.java:82)
Line 82 is return list.size();
The normal reason that occurs this could be using [findViewById] instead of [View.findViewById] in getItem method but I've already used the latter one.
Appreciated and if you need more codes I'll provide.
Try following:
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.table);
list = new ArrayList<Table>(); //Table is an Entity class
gv = findViewById(R.id.table_gridView);
//myAdapter = new MyAdapter(); //remove; intialize after web request has a value
String url = "http://10.0.2.2:8080/WL_Server/TableServlet";
new MyTask().execute(url);
}
class MyTask extends AsyncTask<String, Integer, String>{
...
...
...
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
Gson gson = new Gson();
Type type = new TypeToken<List<Table>>(){}.getType();
list = gson.fromJson(s, type); //debug here, maybe gson is returning null
//inizialize adapter whit list
myAdapter = new MyAdapter(list);
gv.setAdapter(myAdapter);
}
}
class MyAdapter extends BaseAdapter {
List<Table> adptList;
public MyAdapter(List<Table> list){
this.adptList = list;
}
#Override
public int getCount() {
return this.adptList.size();
}
...
...
...
}
Place your setAdpetr() after AsyncTask finish execution, and add constructor for your adapter.
you should place your gv.setAdapter(myAdapter); within onPostExecute()
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
Gson gson = new Gson();
Type type = new TypeToken<List<Table>>(){}.getType();
list = gson.fromJson(s, type);
gv.setAdapter(myAdapter);
myAdapter.notifyDataSetChanged();
}
and also change your getItem() and getItemId()to :
#Override
public Object getItem(int i) {
return list.get(i);
}
#Override
public long getItemId(int i) {
return list.get(i).getId;
}
I want a help from you guys can anybody solve this problem i am trying to insert three rows into mysql table but right here only two rows are visible and third on get visible on scrolling down so when i click submit it gets me an error it inserts 2 visible rows on the screen and throws a null pointer expection on the 3 row that is not visible can some one help me to get the data from the view that is not visible i know its recyclerview and it re uses the view i know the mechanism i just want the solution from some that so that the 3 row that is not visible can get added successfully to the database
Here is an image for that :
https://imgur.com/a/rkARs
My recyclerview adapter code:
public class MyAdapterClosing extends RecyclerView.Adapter<MyAdapterClosing.myViewHolder> {
private Context context;
private List<DataofClosing> student;
public MyAdapterClosing(Context context, List<DataofClosing> student){
this.context = context;
this.student = student;
}
#Override
public myViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.layoutclosing,parent,false);
return new myViewHolder(itemView);
}
#Override
public void onBindViewHolder(myViewHolder holder, int position) {
DataofClosing s = student.get(position);
holder.brand.setText(s.Brandname);
}
public void updateList(List<RecyclerviewWholesale> student)
{
student = student;
notifyDataSetChanged();
}
public void addItem(int position, DataofClosing stud)
{
student.add(position, stud);
notifyItemInserted(position);
}
public void removeItem(int position) {
student.remove(position);
notifyItemRemoved(position);
notifyItemRangeChanged(position, student.size());
}
#Override
public int getItemCount() {
return student.size();
}
#Override
public int getItemViewType(int position) {
return position;
}
public class myViewHolder extends RecyclerView.ViewHolder{
TextView brand;
EditText qts,pts,nip,ml90;
public myViewHolder(View itemView) {
super(itemView);
brand = (TextView) itemView.findViewById(R.id.brand);
qts = (EditText) itemView.findViewById(R.id.qts);
pts = (EditText) itemView.findViewById(R.id.pts);
nip = (EditText) itemView.findViewById(R.id.nip);
ml90 = (EditText) itemView.findViewById(R.id.ml90);
String qtss = qts.getText().toString();
String ptss = pts.getText().toString();
String nipp = nip.getText().toString();
String ml900 = ml90.getText().toString();
DataofClosing dataofClosing = new DataofClosing();
dataofClosing.qts = qtss;
dataofClosing.pts = ptss;
dataofClosing.nip = nipp;
dataofClosing.ml90 = ml900;
}
}
}
Inserting code in the main activity is:
class Insertclosing extends AsyncTask<String, String, String> {
/**
* Before starting background thread Show Progress Dialog
*/
#Override
protected void onPreExecute() {
super.onPreExecute();
}
/**
* Creating product
*/
protected String doInBackground(String... args) {
for (int i = 0; i < mAdapter.getItemCount(); i++) {
rcData = data.get(i);
View view1 = closingService.getChildAt(i);
EditText nameEditText = (EditText) view1.findViewById(R.id.qts);
String name = nameEditText.getText().toString();
EditText ptss = (EditText) view1.findViewById(R.id.pts);
String pts = ptss.getText().toString();
EditText nipp = (EditText) view1.findViewById(R.id.nip);
String nip = nipp.getText().toString();
EditText ml900 = (EditText) view1.findViewById(R.id.ml90);
String ml90 = ml900.getText().toString();
// Building Parameters
List<NameValuePair> params = new ArrayList<NameValuePair>();
params.add(new BasicNameValuePair("brand", rcData.Brandname));
params.add(new BasicNameValuePair("quantity", name));
params.add(new BasicNameValuePair("discount",pts));
params.add(new BasicNameValuePair("ammount",nip ));
// getting JSON Object
// Note that create product url accepts POST method
JSONObject json = jsonParser.makeHttpRequest(url_insert_product_sales,
"POST", params);
// check log cat fro response
Log.d("Create Response", json.toString());
// check for success tag
try {
int success = json.getInt(TAG_SUCCESS);
if (success == 1) {
/*runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(ChangeAddress.this, "Order Placed Successfully", Toast.LENGTH_SHORT).show();
}
});*/
} else {
runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(closing.this, "Try Again", Toast.LENGTH_SHORT).show();
}
}); // failed to create product
}
} catch (JSONException e) {
e.printStackTrace();
}
}
return null;
}
/**
* After completing background task Dismiss the progress dialog
**/
protected void onPostExecute(String file_url) {
Toast.makeText(closing.this, "Closing added Successfully", Toast.LENGTH_SHORT).show();
}
}
I found a solution for this.
adapter has two methods
onViewAttachedToWindow(RecyclerView.ViewHolder holder){}
and
onViewDetachedFromWindow(RecyclerView.ViewHolder holder){}
Cretae a HashMap in your adapter
public HashMap<Integer, RecyclerView.ViewHolder> holderHashMap = new HashMap<>();
and add holder into it in onDetach and remove the same onAttach. Like this.
#Override
public void onViewDetachedFromWindow(RecyclerView.ViewHolder holder) {
holderHashMap.put(holder.getAdapterPosition(),holder);
super.onViewDetachedFromWindow(holder);
}
#Override
public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) {
holderHashMap.remove(holder.getAdapterPosition());
super.onViewAttachedToWindow(holder);
}
to access all viewHolders including the invisible ones use this in you activity.
for(int i =0; i<recyclerView.getItemCount();i++){
RecyclerView.ViewHolder holder = surveyQuestionList.findViewHolderForAdapterPosition(i);
if(holder == null){
holder = adapter.holderHashMap.get(i);
}
}
This is the best solution so far I have come up with.
Let me know if it works for you.
Please help me. My Home Fragment is blank. I cant print JSON array to my Home Fragment. i want the ListView show data from Json array from API, how i can place the array data from Json using fragment. Sory for my english.
I'm using Fragment:
public class HomeFragment extends Fragment implements OnFeedListener{
ListView listView;
FeedAdapter adapter;
ArrayList<Post> posts;
View myView;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
myView = inflater.inflate(R.layout.home, container, false);
return myView;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
}
#Override
public void onFeed(JSONArray array) {
posts = new ArrayList<>();
int lenght = array.length();
for(int i = 0; i < lenght; i++)
{
JSONObject object = array.optJSONObject(i);
Post post = new Post(object.optString("title"), object.optString("excerpt"), object.optString("thumbnail"));
posts.addAll(posts);
}
adapter.addAll(posts);
adapter.notifyDataSetChanged();
listView.setAdapter(adapter);
FeedTask task = new FeedTask(this);
task.execute("http://indo-coc.com/api/get_recent_posts/");
}
public class FeedTask extends AsyncTask<String, Void, JSONArray>
{
private OnFeedListener listener;
public FeedTask(OnFeedListener listener)
{
this.listener = listener;
}
#Override
protected JSONArray doInBackground(String... params)
{
String url = params[0];
OkHttpClient client = new OkHttpClient();
Request.Builder builder = new Request.Builder();
Request request = builder.url(url).build();
try {
Response response = client.newCall(request).execute();
String json = response.body().string();
try
{
JSONObject object = new JSONObject(json);
JSONArray array = object.optJSONArray("posts");
return array;
}
catch (JSONException e)
{
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(JSONArray array) {
super.onPostExecute(array);
if(null == array)
return;
if(null != listener )
listener.onFeed(array);
}
}
public class FeedAdapter extends ArrayAdapter<Post>
{
private int resource;
public FeedAdapter(Context context, int resource) {
super(context, resource);
this.resource = resource;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// Convert View -> Reuse
if (null==convertView)
{
LayoutInflater inflater = LayoutInflater.from(getContext());
convertView = inflater.inflate(resource, null);
}
// Binding Data
Post post = getItem(position);
TextView title = (TextView) convertView.findViewById(R.id.title);
TextView desc = (TextView) convertView.findViewById(R.id.description);
title.setText(post.title);
desc.setText(post.description);
return convertView;
}
}
public class Post
{
public String title;
public String description;
public String thumbnail; //URL
public Post(String title, String desc, String thumbnail)
{
this.title = title;
this.description = desc;
this.thumbnail = thumbnail;
}
}
}
Declare FeedAdapter adapter and ArrayList<Post> posts as global variable in your public class. They must be declared outside public void onActivityCreated(Bundle savedInstanceState)
what's going on here:
in onActivityCreated you declare local variables without assigning a value to them. Because they are local, they are gone as soon as the method terminates. Declare the variables above the method as a class variable to be able to access them later in onFeed
you do not assign a value to the variables listView and adapter. I assume somewhere else, common practice is doing this in onViewCreated, you set a main view for the fragment. If you don't know how to do this, see this question. Then you can load the listView using findViewById assuming the listView is in the layout you inflate in the fragment. Then you have to create a new FeedAdapter and assign it to the listView using listView.setAdapter(adapter)
Good luck!
try this:
class MyFragment extends Fragment{
ListView listView;
FeedAdapter adapter;
ArrayList<Post> posts;
public void onCreate(Bundle b){
super.onCreate(b);
//My bad listview will only be assigned properly in onCreateView once the view is inflated
posts = new ArrayList<>();
adapter=new FeedAdapter(getActivity(),R.id.yourresouceid,posts); // which ever way your adapter is defined
listView.setAdapter(adapter);
}
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
}
public void onFeed(JSONArray array) {
int lenght = array.length();
for (int i = 0; i < lenght; i++)
{
JSONObject object = array.optJSONObject(i);
posts.add(post);
}
//adapter.addAll(posts); //you don't need to do this, already done when creating your adapter
adapter.notifyDataSetChanged();
}
}
Explanation: The scope of onActivityCreated is only till its closing bracket. Anything declared inside that will not be visible to any outer functions. See scope resolution in java for more details on how this works.
Also you have to initialize things before using them. just declaring it and trying to use it will give NullPointerExceptions
I have an app that calling an API its resulting around 500 rows creation.In my app the row content can update in the detail page. So after update is there any possibility to update the row in the Recycler View without calling the API again.
Activity
AsyncHttpClient client = new AsyncHttpClient();
client.get("URL", new AsyncHttpResponseHandler() {
#Override
public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) {
try {
String jsonStr = new String(responseBody, "UTF-8");
if (jsonStr != null) {
try {
JSONArray jsonArray = new JSONArray(jsonStr);
JSONObject cStatus = jsonArray.getJSONObject(jsonArray.length()-1);
for (int i = 0; i < jsonArray.length(); i++)
{
JSONObject c = jsonArray.getJSONObject(i);
String firstName = c.getString("firstName");
String subDistributerId = c.getString("subDistributerId");
SubdistributorItem item = new SubdistributorItem();
item.setSubDistributorName(firstName);
item.setSubDistributorId(subDistributerId);
ubdistributorItemList.add(item);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
Collections.sort(subdistributorItemList, new Comparator<SubdistributorItem>() {
public int compare(SubdistributorItem o1, SubdistributorItem o2) {
return o1.getSubDistributorName().compareToIgnoreCase(o2.getSubDistributorName());
}
});
adapter = new SubdistributorRecyclerAdapter(getActivity(),subdistributorItemList);
mRecyclerView.setAdapter(adapter);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
});
Adapter Class
public class SubdistributorRecyclerAdapter extends RecyclerView.Adapter<SubdistributorListRowHolder> {
private List<SubdistributorItem> subdistributorItems;
private Context mContext;
private ArrayList<SubdistributorItem> arraylist;
public SubdistributorRecyclerAdapter(Context context, List<SubdistributorItem> subdistributorItems) {
this.subdistributorItems = subdistributorItems;
this.mContext = context;
this.arraylist = new ArrayList<SubdistributorItem>();
this.arraylist.addAll(subdistributorItems);
}
#Override
public SubdistributorListRowHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.subdistributor_list_item, null);
SubdistributorListRowHolder mh = new SubdistributorListRowHolder(v);
layout_subdistributor.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(final View v) {
Intent i = new Intent(mContext, SubdistributorDetail.class);
Log.e("Tag shop ", "ShopKeeper Detail called");
i.putExtra("subDistributorStatus", txt_RechargeSubdistributor.getText().toString());
i.putExtra("subDistributorId", txt_subDistributorId.getText().toString());
mContext.startActivity(i);
}
});
return mh;
}
#Override
public void onBindViewHolder(SubdistributorListRowHolder subDistributorListRowHolder, int i) {
SubdistributorItem subdistributorItem = subdistributorItems.get(i);
Log.e("Tag ", "adapter "+ subdistributorItem.getSubDistributorName());
}
#Override
public int getItemCount() {
return (null != subdistributorItems ? subdistributorItems.size() : 0);
}
}
So can any one please help me to update a single row in a list without calling the API again.
Try using this method, to update a single row.
notifyItemChanged(int position)
Update item in your list subdistributorItems. Then call adapter.notifyItemChanged(int position). You can get a position in ClickListener using
layout_subdistributor.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(final View v) {
if (mh.getAdapterPosition() != RecyclerView.NO_POSITION) {
int position = mh.getAdapterPosition();
// edit your object by calling subdistributorItems.get(position)
}
}
});
Change this
public static class SubdistributorListRowHolder extends RecyclerView.ViewHolder {
private TextView textView_alphabet;
private TextView textView_name;
private TextView textView_tag;
private ImageView imageViewUserImage;
private ImageView imageViewMoreButton;
private LinearLayout linearLayoutMainContent;
public ViewHolder(View itemLayoutView) {
super(itemLayoutView);
textView_alphabet = (TextView) itemLayoutView.findViewById(R.id.textView_alphabet);
textView_name = (TextView) itemLayoutView.findViewById(R.id.textView_name);
textView_tag = (TextView) itemLayoutView.findViewById(R.id.textView_tag);
imageViewUserImage = (ImageView) itemLayoutView.findViewById(R.id.imageViewUserImage);
linearLayoutMainContent = (LinearLayout) itemLayoutView.findViewById(R.id.linearLayoutMainContent);
}
}
#Override
public void onBindViewHolder(SubdistributorListRowHolder subDistributorListRowHolder, int i) {
SubdistributorItem subdistributorItem = subdistributorItems.get(i);
Log.e("Tag ", "adapter "+ subdistributorItem.getSubDistributorName());
subDistributorListRowHolder.itemLayoutView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.e("Tag ", "Position "+ i);
}
});
}
Over here itemLayoutView is the mail layout which is clickable
Modify the SubdistributorListRowHolder like this put all your layout component and find view by id.
getViewForPosition(int position)
Obtain a view initialized for the given position. This method should be used by RecyclerView.LayoutManager implementations to obtain views to represent data from an RecyclerView.Adapter.
The Recycler may reuse a scrap or detached view from a shared pool if one is available for the correct view type. If the adapter has not indicated that the data at the given position has changed, the Recycler will attempt to hand back a scrap view that was previously initialized for that data without rebinding.
description here
Its simple.
Make the changes in the ArrayList that is bonded with the recycler view and call notifyDataSetChanged() on the Recycler View.
My fragment activity used this adapter to display all the result in a listview.
The page will have a title tab and each tab will have the list result. Now the list result I read from internal storage and each time I swipe to next page it will have slight lag or delay, so I am thinking implementing ASYNCTask inside this pageradapter so the experience will be better but I have no idea where to implement. Could you guys point me out??
public class ViewPagerAdapter extends PagerAdapter
{
public ViewPagerAdapter( Context context )
{
//This is where i get my title
for (HashMap<String, String> channels : allchannel){
String title = channels.get(KEY_TITLE);
titles[acc] = title;
acc++;
}
scrollPosition = new int[titles.length];
for ( int i = 0; i < titles.length; i++ )
{
scrollPosition[i] = 0;
}
}
#Override
public String getPageTitle( int position )
{
return titles[position];
}
#Override
public int getCount()
{
return titles.length;
}
#Override
public Object instantiateItem( View pager, final int position )
{
String filename = null;
ListView v = new ListView( context );
final ArrayList<HashMap<String, String>> items = new ArrayList<HashMap<String, String>>();
DatabaseHandler db = new DatabaseHandler(context);
filename = openFile("PAGE1"); //OpenFile function is read file from internal storage
switch(position){
case 0:
filename = openFile("PAGE1");
break;
case 1:
filename = openFile("PAGE2");
break;
case 2:
filename = openFile("PAGE3");
break;
}
try{
//Use json to read internal storage file(Page1/Page2) and display all the result on the list
}
}catch(Exception e){
}
ListAdapter listadapter=new ListAdapter(context, items);
v.setAdapter( listadapter );
((ViewPager)pager ).addView( v, 0 );
return v;
}
#Override
public void destroyItem( View pager, int position, Object view )
{
( (ViewPager) pager ).removeView( (ListView) view );
}
#Override
public boolean isViewFromObject( View view, Object object )
{
return view.equals( object );
}
#Override
public void finishUpdate( View view )
{
}
#Override
public void restoreState( Parcelable p, ClassLoader c )
{
if ( p instanceof ScrollState )
{
scrollPosition = ( (ScrollState) p ).getScrollPos();
}
}
#Override
public Parcelable saveState()
{
return new ScrollState( scrollPosition );
}
#Override
public void startUpdate( View view )
{
}
}
I would suggest doing it like this
#Override
public Object instantiateItem( View pager, final int position )
{
//Some other work related to instantiation of item
AsyncTask<Uri, Void, Bitmap> mLoadTask = new AsyncTask<Uri, Void, Bitmap>() {
//async task for loading images in background
#Override
protected void onPostExecute(Bitmap result) {
pageview[position].setImageBitmap(result);
//post in ui thread
//this way you have a reference object for each item(using position)
//and hence you can start several tasks at the same time
}
#Override
protected Bitmap doInBackground(Uri... params) {
Bitmap bitmap=getBitmap(params[0]);
//here getBitmap returns the bitmap using uri arguement
return bitmap;
}
};
mLoadTask.execute(Uri.withAppendedPath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "" + image_id));
}
This way each item has its own thread and you need not worry no matter how many items get loaded.
EDIT One more thing, you can return pageview[position] from this method right after the AsyncTask code, this way the View will appear blank(smooth scrolling achieved) until AsyncTask completes the background work. But it would still be able to set the Bitmap to the correct View because it has reference inside onPostExecute
I'm doing it in constructor, and it's working fine. Example:
public MyAdapter(Context context) {
this.context = context;
try {
whatIneed = new DoSomeAsyncStuff(this.context).execute().get();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}