Endless RecyclerView with Asynctask using EndlessRecyclerOnScrollListener - java

I have an activity which searches for a query (using async task and server side PHP) and gives out a list in recycler view, Now i want to implement endless/infinite scrolling when user reaches bottom. I have tried to do that using EndlessScrollListener. There are two problems i need help with.
first, the new list recreates itself instead of appending to the old list.
second, the current_page int variable keeps its value from the previous search and scroll, means when running AsyncTask for second time, the current_page int variable still retains the value from the first time and does not reset.
public class MainActivity extends AppCompatActivity {
// CONNECTION_TIMEOUT and READ_TIMEOUT are in milliseconds
public static final int CONNECTION_TIMEOUT = 10000;
public static final int READ_TIMEOUT = 15000;
private RecyclerView mRVFish;
private AdapterFish mAdapter;
private LinearLayoutManager mLayoutManager;
private String searchQuery;
SearchView searchView = null;
private String query;
private EndlessRecyclerOnScrollListener mScrollListener = null;
private SwipeRefreshLayout mSwipeRefreshLayout = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRVFish = (RecyclerView) findViewById(R.id.fishPriceList);
mLayoutManager = new LinearLayoutManager(MainActivity.this);
mRVFish.setLayoutManager(mLayoutManager);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// adds item to action bar
getMenuInflater().inflate(R.menu.search_main, menu);
// Get Search item from action bar and Get Search service
MenuItem searchItem = menu.findItem(R.id.action_search);
SearchManager searchManager = (SearchManager) MainActivity.this.getSystemService(Context.SEARCH_SERVICE);
if (searchItem != null) {
searchView = (SearchView) searchItem.getActionView();
}
if (searchView != null) {
searchView.setSearchableInfo(searchManager.getSearchableInfo(MainActivity.this.getComponentName()));
searchView.setIconified(false);
}
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
return super.onOptionsItemSelected(item);
}
// Every time when you press search button on keypad an Activity is recreated which in turn calls this function
#Override
protected void onNewIntent(Intent intent) {
// Get search query and create object of class AsyncFetch
if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
query = intent.getStringExtra(SearchManager.QUERY);
if (searchView != null) {
searchView.clearFocus();
}
int startrow =0;
String type="";
String filetype="";
AsyncFetch myTask = new AsyncFetch(query, startrow, type, filetype);
myTask.execute();
mScrollListener = new EndlessRecyclerOnScrollListener(mLayoutManager) {
#Override
public void onLoadMore(int current_page) {
int startrow=current_page;
String type="";
String filetype="";
AsyncFetch myTask = new AsyncFetch(query, startrow, type, filetype);
myTask.execute();
}
};
mRVFish.addOnScrollListener(mScrollListener);
// enable pull down to refresh
mSwipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.swipeRefreshLayout);
mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
#Override
public void onRefresh() {
int startrow =0;
String type="";
String filetype="";
AsyncFetch myTask = new AsyncFetch(query, startrow, type, filetype);
myTask.execute();
// after refresh is done, remember to call the following code
if (mSwipeRefreshLayout != null && mSwipeRefreshLayout.isRefreshing()) {
mSwipeRefreshLayout.setRefreshing(false); // This hides the spinner
}
}
});
}
}
// Create class AsyncFetch
private class AsyncFetch extends AsyncTask<String, String, String> {
ProgressDialog pdLoading = new ProgressDialog(MainActivity.this);
HttpURLConnection conn;
URL url = null;
String searchQuery;
int startrow;
String type;
String filetype;
public AsyncFetch(String searchQuery, int startrow, String type, String filetype){
this.searchQuery=searchQuery;
this.startrow = startrow;
this.type = type;
this.filetype=filetype;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
//this method will be running on UI thread
pdLoading.setMessage("\tLoading...");
pdLoading.setCancelable(false);
pdLoading.show();
}
#Override
protected String doInBackground(String... params) {
try {
// Enter URL address where your php file resides
url = new URL("http://someurl/json/search.php");
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return e.toString();
}
try {
// Setup HttpURLConnection class to send and receive data from php and mysql
conn = (HttpURLConnection) url.openConnection();
conn.setReadTimeout(READ_TIMEOUT);
conn.setConnectTimeout(CONNECTION_TIMEOUT);
conn.setRequestMethod("POST");
// setDoInput and setDoOutput to true as we send and recieve data
conn.setDoInput(true);
conn.setDoOutput(true);
// add parameter to our above url
Uri.Builder builder = new Uri.Builder().appendQueryParameter("searchQuery", searchQuery).appendQueryParameter("startrow", String.valueOf(startrow));
String query = builder.build().getEncodedQuery();
OutputStream os = conn.getOutputStream();
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(os, "UTF-8"));
writer.write(query);
writer.flush();
writer.close();
os.close();
conn.connect();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
return e1.toString();
}
try {
int response_code = conn.getResponseCode();
// Check if successful connection made
if (response_code == HttpURLConnection.HTTP_OK) {
// Read data sent from server
InputStream input = conn.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(input));
StringBuilder result = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
result.append(line);
}
// Pass data to onPostExecute method
return (result.toString());
} else {
return("Connection error");
}
} catch (IOException e) {
e.printStackTrace();
return e.toString();
} finally {
conn.disconnect();
}
}
#Override
protected void onPostExecute(String result) {
//this method will be running on UI thread
pdLoading.dismiss();
List<DataFish> data=new ArrayList<>();
pdLoading.dismiss();
if(result.equals("no rows")) {
Toast.makeText(MainActivity.this, "No Results found for entered query", Toast.LENGTH_LONG).show();
}else{
try {
JSONArray jArray = new JSONArray(result);
// Extract data from json and store into ArrayList as class objects
for (int i = 0; i < jArray.length(); i++) {
JSONObject json_data = jArray.getJSONObject(i);
DataFish fishData = new DataFish();
try {
fishData.fileName = URLDecoder.decode(json_data.getString("file"), "UTF-8");
} catch (Exception e) {
Toast.makeText(MainActivity.this, e.toString(), Toast.LENGTH_LONG).show();
fishData.fileName=json_data.getString("file");
}
fishData.linkName = json_data.getString("link");
fishData.reg_date = json_data.getString("reg_date");
fishData.fileSize = json_data.getString("filesize");
data.add(fishData);
}
mAdapter = new AdapterFish(MainActivity.this, data);
mRVFish.setAdapter(mAdapter);
if(jArray.length()>19)
mScrollListener.setLoading(false);
else
mScrollListener.setLoading(true);
} catch (JSONException e) {
// You to understand what actually error is and handle it appropriately
Toast.makeText(MainActivity.this, e.toString(), Toast.LENGTH_LONG).show();
Toast.makeText(MainActivity.this, result.toString(), Toast.LENGTH_LONG).show();
}
}
}
}
}
EndlessRecyclerOnScrollListener.java
public abstract class EndlessRecyclerOnScrollListener extends
RecyclerView.OnScrollListener {
public static String TAG = EndlessRecyclerOnScrollListener.class.getSimpleName();
private int previousTotal = 0; // The total number of items in the dataset after the last load
private boolean loading = false; // True if we are still waiting for the last set of data to load.
private int visibleThreshold = 0; // The minimum amount of items to have below your current scroll position before loading more.
int firstVisibleItem, visibleItemCount, totalItemCount;
private int current_page = 20;
private LinearLayoutManager mLayoutManager;
public EndlessRecyclerOnScrollListener(LinearLayoutManager linearLayoutManager) {
this.mLayoutManager = linearLayoutManager;
}
#Override
public void onScrolled(RecyclerView mRVFish, int dx, int dy) {
super.onScrolled(mRVFish, dx, dy);
if(dy < 0) {
return;
}
// check for scroll down only
visibleItemCount = mRVFish.getChildCount();
totalItemCount = mLayoutManager.getItemCount();
firstVisibleItem = mLayoutManager.findFirstVisibleItemPosition();
// to make sure only one onLoadMore is triggered
synchronized (this) {
if (!loading && (totalItemCount - visibleItemCount) <= (firstVisibleItem + visibleThreshold)) {
// End has been reached, Do something
current_page=current_page+20;
onLoadMore(current_page);
loading = true;
}
}
}
public void setLoading(boolean loading) {
this.loading = loading;
}
public abstract void onLoadMore(int current_page);
}

first, the new list recreates itself instead of appending to the old list.
If you set a new adapter you swap the content of the recycler view. I think you do it in the following code
mAdapter = new AdapterFish(MainActivity.this, data);
mRVFish.setAdapter(mAdapter);
To append the data you need to add new elements to the adapter's dataset (dataset where you get data to bind views in your adapter) and then call adapter.notifyDataSetChanged() or better adapter.notifyItemRangeInserted(int positionStart, int itemCount)
There are also a number of tools to optimize adding the elements, like DiffUtil
second, the current_page int variable keeps its value from the previous search and scroll, means when running AsyncTask for second time
Not sure what was library developer's idea here, but the easiest way would be to just create a method in the EndlessRecyclerOnScrollListener similar to:
public void resetPage() {
current_page = 20;
}
And call it before invoking new search.

Related

how do I get the value of a list outside the asynchronous method?

I've done a search on another stackoverflow post for 2 hours but still can not solve this problem. I have a variable called copyAudioListIqro with List String datatype in DetailMemilihIqro Activity class. When the variable called audioIqros in the AsyncTask class (precisely in the onPostExecute method) this list has a value from my json and I want to copy audioIqros variable to copyAudioListIqro via updateData method (outside the asynctask class). When I see the log monitor on updateData method I can see the value from copyAudioListIqro, but the problem is, when I access it via readDataAudioURL method(outside the asynctask class) copyAudioListIqro variable becomes null.
What is the solution for this problem?
Thank you
Here is the overall DetailMemilihIqro class
public class DetailMemilhIqro extends AppCompatActivity {
private ProgressDialog pDialog;
private List<ModelAudioIqro> audioIqros;
private List<String> copyAudioListIqro;
private AudioAdapter mAdapter;
private RecyclerView recyclerView;
private String TAG = DetailMemilihIqro.class.getSimpleName();
Context context;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_detail_memilih_iqro);
recyclerView = (RecyclerView) findViewById(R.id.rvCVAudioIqro);
pDialog = new ProgressDialog(this);
audioIqros = new ArrayList<>();
mAdapter = new AudioAdapter(getApplicationContext(), audioIqros);
context = getApplicationContext();
copyAudioListIqro = new ArrayList<>();
recyclerView.setLayoutManager(new LinearLayoutManager(context));
recyclerView.setItemAnimator(new DefaultItemAnimator());
recyclerView.setAdapter(mAdapter);
Bundle getPosition = getIntent().getExtras();
int position = getPosition.getInt("positionUserClicked");
Log.d(TAG, "Position User clicked " + position);
if (position == 0) {
String endpoint = "http://latihcoding.com/jsonfile/audioiqro1.json";
new DownloadTask().execute(endpoint);
} else if (position == 1) {
String endpoint = "http://latihcoding.com/jsonfile/audioiqro2.json";
new DownloadTask().execute(endpoint);
} else if (position == 2) {
String endpoint = "http://latihcoding.com/jsonfile/audioiqro3.json";
new DownloadTask().execute(endpoint);
}
readDataAudioURL();
}
public void updateData(List<String> pathUrl) {
for (int i = 0; i < pathUrl.size(); i++) copyAudioListIqro.add(pathUrl.get(i));
Log.d(TAG, "updateData Method " + copyAudioListIqro.toString());
}
public void readDataAudioURL() {
Log.d(TAG, "readDataAudioURL Method " + copyAudioListIqro.toString());
}
public class DownloadTask extends AsyncTask<String, Void, List<String>> {
List<String> modelAudioIqroList;
#Override
protected void onPreExecute() {
super.onPreExecute();
pDialog.setMessage("Downloading json...");
pDialog.show();
}
#Override
protected List<String> doInBackground(String... strings) {
modelAudioIqroList = new ArrayList<>();
int result;
HttpURLConnection urlConnection;
try {
URL url = new URL(strings[0]);
urlConnection = (HttpURLConnection) url.openConnection();
int statusCode = urlConnection.getResponseCode();
// 200 represents HTTP OK
if (statusCode == 200) {
BufferedReader r = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
StringBuilder response = new StringBuilder();
String line;
while ((line = r.readLine()) != null) {
response.append(line);
}
parseResult(response.toString());
result = 1; // Successful
Log.d(TAG, "Result " + result);
} else {
//"Failed to fetch data!";
result = 0;
Log.d(TAG, "Result " + result);
}
} catch (Exception e) {
Log.d(TAG, e.getLocalizedMessage());
}
return modelAudioIqroList; //"Failed to fetch data!";
}
#Override
protected void onPostExecute(List<String> audioIqros) {
super.onPostExecute(audioIqros);
pDialog.hide();
if (!audioIqros.isEmpty()) {
updateData(modelAudioIqroList);
} else {
Toast.makeText(context, "Empty", Toast.LENGTH_SHORT).show();
}
}
private void parseResult(String result) {
try {
JSONArray response = new JSONArray(result);
for (int i = 0; i < response.length(); i++) {
JSONObject object = response.getJSONObject(i);
ModelAudioIqro modelAudioIqro = new ModelAudioIqro();
modelAudioIqro.setName(object.getString("name"));
modelAudioIqro.setUrl(object.getString("url"));
String path = modelAudioIqro.getUrl();
Log.d(TAG, "String path " + path);
modelAudioIqroList.add(path);
}
} catch (JSONException e) {
e.printStackTrace();
}
mAdapter.notifyDataSetChanged();
}
}
}
Log for the copyAudioListIqro in the updateDataMethod
Log for the copyAudioListIqro in the readDataAudioURL
readDataAudioURL() call, that is a plain Log call, should be moved. Infact the task is asynch by nature, so oblivously the variable copyAudioListIqro won't have been initialized right after the task's start (.execute() method).
You're doing right, anyway, in notyfiying dataset change to list...You should just move it to postExecute as well...
I suggest to move all "after network" code to that postExecute, so that UI can be updated asynchronously ONLY when data is available and without blocking main thread. You can 'read' variables in the inner class, so just declare them final:
#Override
protected void onPostExecute(List<String> audioIqros) {
super.onPostExecute(audioIqros);
pDialog.hide();
if (!audioIqros.isEmpty()) {
updateData(modelAudioIqroList);
//data is now updated, notify datasets and/or send broadcast
mAdapter.notifyDataSetChanged();
readDataAudioURL();
} else {
Toast.makeText(context, "Empty", Toast.LENGTH_SHORT).show();
}
}
A more elaborate pattern would include broadcast receiver and intents, but I guess this is out of this question's scope.

Unable to fetch return value from a method in Java

I want to create a sidebar using values fetch from my servers.
But the values that I am trying to fetch from the method which holds the return value is causing error. I am unable to call this method.
Here's the code:
public class MainActivity extends AppCompatActivity {
private ListView mDrawerList;
private DrawerLayout mDrawerLayout;
private ArrayAdapter<String> mAdapter;
private ActionBarDrawerToggle mDrawerToggle;
private String mActivityTitle;
public String returnnumfromAsyncTask;
private TextView setTextValue;
private TextView textViewid;
private Button buttonHit;
private String var;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mDrawerList = (ListView)findViewById(R.id.navList);
mDrawerLayout = (DrawerLayout)findViewById(R.id.drawer_layout);
mActivityTitle = getTitle().toString();
addDrawerItems();
setupDrawer();
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setHomeButtonEnabled(true);
/*textViewid = (TextView)findViewById(R.id.textViewid);
buttonHit = (Button)findViewById(R.id.buttonHit);
buttonHit.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
new JSONTask().execute("http://xyz.co/tests/ems/query.php");
}
});*/
}
private void addDrawerItems() {
new JSONTask().execute("http://xyz.co/tests/ems/query.php");
JSONTask json = new JSONTask();
String myArray = json.myMethod();
String[] osArray = { "Android", "iOS", "Windows", "OS X", "Linux" };
mAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, osArray);
mDrawerList.setAdapter(mAdapter);
mDrawerList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Toast.makeText(MainActivity.this, "Time for an upgrade!", Toast.LENGTH_SHORT).show();
}
});
}
private void setupDrawer() {
mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout, R.string.drawer_open, R.string.drawer_close) {
/** Called when a drawer has settled in a completely open state. */
public void onDrawerOpened(View drawerView) {
super.onDrawerOpened(drawerView);
getSupportActionBar().setTitle("Navigation!");
invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
}
/** Called when a drawer has settled in a completely closed state. */
public void onDrawerClosed(View view) {
super.onDrawerClosed(view);
getSupportActionBar().setTitle(mActivityTitle);
invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
}
};
mDrawerToggle.setDrawerIndicatorEnabled(true);
mDrawerLayout.setDrawerListener(mDrawerToggle);
}
#Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
// Sync the toggle state after onRestoreInstanceState has occurred.
mDrawerToggle.syncState();
}
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
mDrawerToggle.onConfigurationChanged(newConfig);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
// Activate the navigation drawer toggle
if (mDrawerToggle.onOptionsItemSelected(item)) {
return true;
}
return super.onOptionsItemSelected(item);
}
public class JSONTask extends AsyncTask<String,String,String> {
#Override
protected String doInBackground(String... params) {
HttpURLConnection connection = null;
BufferedReader reader = null;
try {
URL url = new URL(params[0]);
connection = (HttpURLConnection)url.openConnection();
connection.connect();
// connecting to the url
//Reading the data in bytes stream
InputStream stream = connection.getInputStream();
reader = new BufferedReader(new InputStreamReader(stream));
//Reading the data by creating a buffer
StringBuffer buffer = new StringBuffer();
String line="";
while((line = reader.readLine())!= null){
buffer.append(line);
}
String finalJson = buffer.toString();
JSONObject parentObject = new JSONObject(finalJson);
List<String> list = new ArrayList<String>();
JSONArray array = parentObject.getJSONArray("kitten");
for(int i = 0 ; i < array.length() ; i++){
list.add(array.getJSONObject(i).getString("if")+"\n");
}
/*String finalObject = parentObject.getString("name");
JSONArray parentArray = parentObject.getJSONArray("kitten");
StringBuffer finalBufferedData = new StringBuffer();
for(int i=0;i<parentArray.length();i++) {
JSONObject finalObject = parentArray.getJSONObject(i);
int curr = finalObject.getInt("name");
//int bus = finalObject.getInt("bus");
finalBufferedData.append(curr + "\n" );
}*/
//return finalBufferedData.toString();
return list.toString();
// setting text view from the url
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
} finally{
if(connection !=null) {
connection.disconnect();
}
try {
if (reader != null)
{
reader.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
//textViewid.setText(result);
myMethod(result);
}
public String myMethod(String result){
return result;
}
}
}
Notice the line:
String myArray = json.myMethod();
It tries to call a function myMethod() which returns a string value or rather an array which I get by executing asynctask.
But somehow I am not able to call myMethod from JSON asynctask function.
So my primary question is how to call a method which returns a value and thereby use it in my code?
Thanks in advance
AsyncTask.doInBackground() runs asynchronously.
You should run JSONTask like so:
private void addDrawerItems() {
new JSONTask().execute("http://xyz.co/tests/ems/query.php");
}
And move code that uses result of this task to JSONTask.onPostExecute():
public class JSONTask extends AsyncTask<String,String,String[]> {
#Override
protected String[] doInBackground(String... params) {
HttpURLConnection connection = null;
BufferedReader reader = null;
try {
URL url = new URL(params[0]);
connection = (HttpURLConnection)url.openConnection();
connection.connect();
//connecting to the url
//Reading the data in bytes stream
InputStream stream = connection.getInputStream();
reader = new BufferedReader(new InputStreamReader(stream));
// Reading the data by creating a buffer
StringBuffer buffer = new StringBuffer();
String line="";
while((line = reader.readLine())!= null){
buffer.append(line);
}
String finalJson = buffer.toString();
JSONObject parentObject = new JSONObject(finalJson);
List<String> list = new ArrayList<String>();
JSONArray array = parentObject.getJSONArray("kitten");
for(int i = 0 ; i < array.length() ; i++){
list.add(array.getJSONObject(i).getString("if")+"\n");
}
return list.toArray(new String[list.size()]);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
} finally{
if(connection !=null) {
connection.disconnect();
}
try {
if (reader != null)
{
reader.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
#Override
protected void onPostExecute(String[] result) {
mAdapter = new ArrayAdapter<String>(MainActivity.this, android.R.layout.simple_list_item_1, result);
mDrawerList.setAdapter(mAdapter);
mDrawerList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Toast.makeText(MainActivity.this, "Time for an upgrade!", Toast.LENGTH_SHORT).show();
}
});
}
}
Because doInBackground method of JSONTask class executed in background Thread,so:
JSONTask json = new JSONTask();
String myArray = json.myMethod();
these lines are executing just after call of execute method.
EITHER
use AsyncTask.get() method which will freeze UI Thread until doInBackground method execution not completed.
OR
Best way is use onPostExecute for setting Adapter for ListView.
EDIT :
As question in comment:
How do I use onPostExecute to sett adapter for ListView?
If JSONTask class is inner-class of MainActivity class then you can access all variables of MainActivity class in JSONTask directly.just move related code in onPostExecute method.
and if JSONTask class is separate class then pass Activity Context to JSONTask for accessing UI elements from normal java class as:
1. Add a constructor to JSONTask class for getting Activity Context as:
private Context mContext;
private ListView mDrawerList;
JSONTask(Context mContext, ListView mDrawerList){
this.mContext=mContext;
this.mDrawerList=mDrawerList;
}
2. Pass MainActivity.this as parameter when creating object of JSONTask class:
JSONTask objJSONTask=new JSONTask(MainActivity.this);
objJSONTask.execute("http://xyz.co/tests/ems/query.php");
3. Now use mContext and mDrawerList to show ListView in onPostExecute

java.lang.ArrayIndexOutOfBoundsException: length=1; index=1 ERROR

I have an issue with my app when retrieving data from array.
SchedulePage:
public class SchedulePage extends Activity {
List<MyTask> tasks;
List<Test_Sched> SchedList;
// Intent intent = getIntent();
// String Username = intent.getStringExtra("Username2");
int Count = 0;
String SendCount = "";
TextView endtv, durationtv;
//storage of Test_Name
private static ArrayList<String> Test_Name = new ArrayList<String>();
//storage of x values in array private
private static ArrayList<Integer> Duration = new ArrayList<Integer>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_schedule_page);
endtv = (TextView) findViewById(R.id.Endtv);
durationtv = (TextView) findViewById(R.id.Durationtv);
//Use this to Create Layouts Dynamically
//RelativeLayout relativeLayout = new RelativeLayout(this);
tasks = new ArrayList<>();
GetSchedule();
//GridView gv = (GridView) findViewById(R.id.grid);
//gv.setAdapter(new ImageAdapter(getApplicationContext()));
//Storing test name Arraylist in a array
final String [] web = Test_Name.toArray(new String[Test_Name.size()]);
//Storing images in a array
ArrayList<Integer> imagesAL = new ArrayList<Integer>();
for(int i = 0; i < Test_Name.size(); i++){
// String testname = web[i];
String lf = "One Leg(Left)", rf = "One Leg(Right)", sf = "Separate Foot", sbsf= "Side By Side Foot", tthr ="Toe To Heel(Right)", tthl ="Toe To Heel(Left)";
if(lf.equals(Test_Name.get(i))){
imagesAL.add(R.drawable.leftfoot);
}
if(rf.equals(Test_Name.get(i))){
imagesAL.add(R.drawable.rightfoot);
}
if(sf.equals(Test_Name.get(i))){
imagesAL.add(R.drawable.feetapart);
}
if(sbsf.equals(Test_Name.get(i))){
imagesAL.add(R.drawable.sidebysidefoot);
}
if(tthr.equals(Test_Name.get(i))){
imagesAL.add(R.drawable.righttoetoleftheel);
}
if(tthl.equals(Test_Name.get(i))){
imagesAL.add(R.drawable.lefttoetorightheel);
}
}
Integer [] imageId = imagesAL.toArray(new Integer[imagesAL.size()]);
ImageAdapter adapter = new ImageAdapter(SchedulePage.this, web, imageId);
GridView grid;
grid=(GridView)findViewById(R.id.grid);
grid.setAdapter(adapter);
grid.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
Toast.makeText(SchedulePage.this, "You Clicked at " +web[+ position], Toast.LENGTH_SHORT).show();
}
});
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.schedule_page, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
//Login Stuff
public static ArrayList<Integer> getDuration() {
return Duration;
}
public static ArrayList<String> getTestName() {
return Test_Name;
}
private void GetSchedule(){
String jsonOutput = "http://172.20.34.112/IBBTS_WebService_MobileAndDevice/Service1.asmx/GetSchedule";
if (isOnline()) {
//while(End == "not yet"){
requestData(jsonOutput);
//}
}else {
Toast.makeText(SchedulePage.this, "Network isn't available", Toast.LENGTH_LONG).show();
}
}
private static String doJSONHTTPCall(String urlStr) {
String output2 = "";
try {
URL url;
try {
url = new URL(urlStr);
}
catch (MalformedURLException e) {
throw e;
}
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setRequestProperty("Accept", "application/json");
BufferedReader br = new BufferedReader(new InputStreamReader(
(conn.getInputStream())));
String output;
while ((output = br.readLine()) != null) {
output2 += output;
}
conn.disconnect();
}
catch (MalformedURLException e) {
e.printStackTrace();
}
catch (IOException e) {
e.printStackTrace();
}
return output2;
}
private void requestData(String uri) {
//Send the integer to String
Bundle gt=getIntent().getExtras();
String usernamePass =gt.getString("userName2");
SendCount = Integer.toString(Count);
RequestPackage p = new RequestPackage();
p.setMethod("GET");
p.setUri(uri);
p.setParam("Username", usernamePass);
MyTask task = new MyTask();
task.execute(p);
}
protected void updateDisplay(){
if (SchedList != null) {
for (Test_Sched test_Sched : SchedList) {
Duration.add(test_Sched.getDuration());
Test_Name.add(test_Sched.getTest_Name());
Count++;
}
}
}
protected boolean isOnline() {
ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo netInfo = cm.getActiveNetworkInfo();
if (netInfo != null && netInfo.isConnectedOrConnecting()) {
return true;
} else {
return false;
}
}
private class MyTask extends AsyncTask<RequestPackage, String, String>{
#Override
protected void onPreExecute() {
//updateDisplay("Starting Task");
if (tasks.size() == 0) {
//progress.setVisibility(View.VISIBLE);
}
tasks.add(this);
}
#Override
protected String doInBackground(RequestPackage... params) {
String content = HttpManager.getData(params[0]);
return content;
}
#Override
protected void onPostExecute(String result) {
SchedList = ScheduleJSONParser.parseFeed(result);
updateDisplay();
tasks.remove(this);
if (tasks.size() == 0) {
//progress.setVisibility(View.INVISIBLE);
}
}
#Override
protected void onProgressUpdate(String... values) {
//updateDisplay(values[0]);
}
}
}
ScheduleJSONParsor
public class ScheduleJSONParser {
public static List<Test_Sched> parseFeed(String content) {
try {
JSONArray ar = new JSONArray(content);
List<Test_Sched> SchedList = new ArrayList<>();
for (int i = 0; i < ar.length(); i++) {
JSONObject obj = ar.getJSONObject(i);
Test_Sched test_Sched = new Test_Sched();
test_Sched.setDuration(Integer.parseInt(obj.getString("Duration")));
test_Sched.setTest_Name(obj.getString("Test_Name"));
SchedList.add(test_Sched);
}
return SchedList;
} catch (JSONException e) {
e.printStackTrace();
return null;
}
}}
The logcat does not indicate which line has the error and I find it difficult to troubleshoot.
The idea is that it retrieves the schedule from the database and pass it to an array. then the app will display image buttons for each of the exercise name.
Also when I click the schedulePage button from the main menu, it shows up blank and I have to re-click the schedulePage the second time. The second time shows the arrayoutofbounds error..
any help would be appreciated.
The reason is this both lines
GetSchedule();
final String [] web = Test_Name.toArray(new String[Test_Name.size()]);
in GetSChedule() you are running thread in background and from response of webservice you are filling Test_Name array. But before calling webservice you are copying Test_Name data to web array, so your web[] will be blank because there is no data in Test_Name.
Make web[] global
String [] web;
fill it in updateDisplay()
protected void updateDisplay(){
if (SchedList != null) {
for (Test_Sched test_Sched : SchedList) {
Duration.add(test_Sched.getDuration());
Test_Name.add(test_Sched.getTest_Name());
Count++;
}
web = Test_Name.toArray(new String[Test_Name.size()]);
}
}

Gridview is refreshed from start when scrollbar reaches end

This happens while loading data in gridview. This is my fragment containing scroll listener over gridview. But whenever i reload the data then whole gridview reload and scroll starts from top not from where the data is loaded. I am using single gridview.
public class Women_Ethnic_Fragment extends Fragment {
private static String url = "http://------/-------";
private int mVisibleThreshold = 5;
private int mCurrentPage = 0;
private int mPreviousTotal = 0;
private boolean mLoading = true;
private boolean mLastPage = false;
public Women_Ethnic_Fragment() {
}
#Override
public View onCreateView(LayoutInflater inflater,
ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(
R.layout.gridview_fragment, container,
false);
setRetainInstance(true);
arrayList = new ArrayList<Items>();
gridView = (GridView) rootView.findViewById(R.id.gridView1);
new LoadData().execute(url);
//scrolling portion
gridView.setOnScrollListener(new OnScrollListener() {
#Override
public void onScroll(AbsListView view,
int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
if (mLoading) {
if (totalItemCount > mPreviousTotal) {
mLoading = false;
mPreviousTotal = totalItemCount;
mCurrentPage++;
if (mCurrentPage + 1 > 50) {
mLastPage = true;
}
}
}
if (!mLastPage
&& !mLoading
&& (totalItemCount - visibleItemCount) <= (firstVisibleItem + mVisibleThreshold)) {
//new asynctask called
new LoadData()
.execute("http://-------/---------");
mLoading = true;
}
}
#Override
public void onScrollStateChanged(AbsListView view,
int scrollState) {
}
});
return rootView;
}
//my asynctask
private class LoadData extends AsyncTask<String,
Void, Void> {
#Override
protected void onPostExecute(Void result) {
tp.dismiss();
adap = new Grid_View_Adatper(getActivity().getApplicationContext(),
arrayList);
gridView.setAdapter(adap);
super.onPostExecute(result);
}
#Override
protected void onPreExecute() {
tp = new TransparentProgressDialog(getActivity(),
R.drawable.spinner);
tp.setCancelable(false);
tp.setCanceledOnTouchOutside(false);
tp.show();
super.onPreExecute();
}
#Override
protected Void doInBackground(String... urls) {
try {
HttpClient client = new DefaultHttpClient();
HttpGet httpget = new HttpGet(urls[0]);
HttpResponse response = client.execute(httpget);
HttpEntity entity = response.getEntity();
String data = EntityUtils.toString(entity);
JSONArray json = new JSONArray(data);
for (int i = 0; i < json.length(); i++) {
JSONObject e = json.getJSONObject(i);
String name = e.getString("name");
String price = e.getString("price");
String image = e.getString("image");
String code = e.getString("sku");
tems = new Items(name, price, image, code);
arrayList.add(tems);
}
} catch (JSONException e) {
e.printStackTrace();
} catch (ClientProtocolException e) {
} catch (IOException e) {
} catch (RuntimeException e) {
}
return null;
}
}
Please help someone.
Thanks in advane.
The problem is you instantiate adapter over and over again. Instead check your adapter first, if it is not null, then set your data, then notify dataset changes.
if (adapter == null) {
adapter = new GridViewAdapter...
gridView.setAdapter(adapter)
}
// list refers the list inside in your adapter
list.addAll(newList); // or do your implementation
adapter.notifyDataSetChanged();

Trouble upgrading my RSS feed reader app, from AsycTask to AsyncTaskLoader behavior

Hello I implemented a simple RSS Feed reader using an AsyncTask, and It works perfectly.
I am trying upgrade my little APP to work with an ASYNCTASKLOADER, to learn how to use Loaders.
Notice the two lines of code on the:
public void onCreate(Bundle savedInstanceState){
of the RSSMain class...
new getRSSFeeds().execute();
getLoaderManager().initLoader(0, null, callBacks1);
By un/commenting these two lines I decide which mode to try my app with.
When I attempt to read RSS Feeds with getLoaderManager, all I get is a blank Activity.
My code is attached. I must have some conceptual mistake on my code, since I am new to all these things. Does somebody now how to solve it?
Take into account I started programming for Android 3 weeks ago, and my code
may be far from perfect, so any comments towards improvement are welcome!
public class RSSMain extends ListActivity {
private ArrayList<rssentry> itemlist2 = null; //LIST OF ALL RSS FEEDS
private RSSListAdaptor2 rssadaptor2 = null; //A SINGLE RSS POST
private String sourceurl=null;
public final static String EXTRA_MESSAGE = "com.example.rssjosh.MESSAGE"; //DECLARE PAYLOAD MESSAGE FOR THE ACTIVITY-CALLING INTENT
private static final int LENGTH_SHORT = 0;
private static final int LENGTH_LONG = 1;
String toastxt="empty...";
Toast toast;
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
//LoaderManager lmanager = getLoaderManager().initLoader(0, null, new RSSLoaderCallback, getBaseContext());
//getLoaderManager().initLoader(0, savedInstanceState, new RSSLoader(null));
sourceurl="http://stackoverflow.com/feeds/tag?tagnames=android&sort=newest";
itemlist2 = new ArrayList<rssentry>();
getLoaderManager().initLoader(0, null, callBacks1); //CREATES AND INITS. LOADER (ASYNCTASKLOADER MODE)
//new getRSSFeeds().execute();
}
#Override
protected void onListItemClick(ListView l, View v, int position, long id) {
super.onListItemClick(l, v, position, id);
String s=null;
rssentry data = itemlist2.get(position); //GET THE RSSENTRY THAT WAS TOUCHED BY THE USER
//TEMPORARY TOAST TO CHECK CORRECT STRING FORMATION
//String toastxt="XD!";
//int duration = Toast.LENGTH_LONG; //toastxt=toastxt+data.title+"\n"+data.published+"\n"+data.link+"\n"+data.summary.substring(30,140)+"\n";
//FORM THE HTML TEXT TO BE SENT TO THE SIGLE-RSSFEED DISPLAY ACTIVITY
StringBuilder htmlString = new StringBuilder();
htmlString.append(data.title+"$");
htmlString.append("Published on: "+data.published+"$");
htmlString.append(data.summary+"$");
htmlString.append("URL: "+data.link+"$");
Intent intent = new Intent(this,Rssactivity.class);
//LOADS THE INTENT WITH THE <HTML> PAYLOAD
intent.putExtra(EXTRA_MESSAGE, htmlString.toString()); ///public final static String EXTRA_MESSAGE = "com.example.rssjosh.MESSAGE"; DECLARED ABOVE
startActivity(intent); //LAUNCHES INTENT
}
//SERVICE METHOD TO private String retrieveRSSFeed2(String urlToRssFeed)
// _URLstring -> INPUT_STREAM
private InputStream downloadUrl(String urlString) throws IOException {
URL url = new URL(urlString);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setReadTimeout(10000 /* milliseconds */);
conn.setConnectTimeout(15000 /* milliseconds */);
conn.setRequestMethod("GET");
conn.setDoInput(true);
// STARTS QUERYING THE STREAM
conn.connect();
InputStream stream = conn.getInputStream();
return stream;
}
//URL -> (INPUT_STREAM) -> List<rssentry> entries
//THIS VARIANT OF THE RETRIEVERSSFEED2 METHOD, RETURNS RESULT IN A STRING FORMAT (OPTIONAL METHOD)
private ArrayList<rssentry> retrieveRSSFeed2Str(String urlToRssFeed) throws XmlPullParserException, IOException
{
ArrayList<rssentry> itemlist = new ArrayList<rssentry>();
//INSTANTIATES A NEW PARSER "parsero", AND AN EMPTY RSSENTRY ARRAYLIST
InputStream stream = null;
//List<rssentry> entries = null; UPGRADED TO PUBLIC CLASS ATTRIBUTE
xmlparser parsero = new xmlparser();
//This Try does URL->Stream
try {
stream = downloadUrl(urlToRssFeed); //OBTAIN A CHARACTER STREAM FROM THE rssURL
itemlist = parsero.parse(stream); //PARSE STREAM AND STORE rssENTRIES IN THE "ENTRIES" ARRAYLIST <rssentry>
} finally {
if (stream != null) {
stream.close(); //CLOSE STREAM AFTER USING IT
}
}
return itemlist;
}
//GETS RSS FEED IN ASYNCHRONOUS MODE
class ATLgetfeeds extends AsyncTaskLoader <ArrayList<rssentry>>{
private ArrayList<rssentry> rsslist=null;
private ProgressDialog progress = null;
public ATLgetfeeds(Context context) {
super(context);
}
#Override
protected void onStartLoading() {
if (rsslist != null)
deliverResult(rsslist); // Use the cache
else
forceLoad();
}
#Override
public ArrayList<rssentry> loadInBackground() {
try {
itemlist2 = null; //<=THIS LIST IS TO BE LOADED WITH THE RSS URL BELOW
rsslist = retrieveRSSFeed2Str("http://stackoverflow.com/feeds/tag?tagnames=android&sort=newest"); //SETS ITEMLIST2
} catch (XmlPullParserException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
//LOADS DATA INTO RSSADAPTER (PARSER2)
rssadaptor2 = new RSSListAdaptor2(RSSMain.this, R.layout.rssitemview,rsslist);
return null;
}
#Override
public void deliverResult(ArrayList<rssentry> data) {
rsslist = data; // Caching
super.deliverResult(data);
}
#Override
protected void onReset() {
super.onReset();
// Stop the loader if it is currently running
onStopLoading();
rsslist = null;
}
#Override
public void onCanceled(ArrayList<rssentry> data) {
// Attempt to cancel the current async load
super.onCanceled(data);
rsslist = null;
}
protected void onPreExecute() {
progress = ProgressDialog.show( RSSMain.this, null, "RSSJosh Loading..."); //LOADING MESSAGE
// super.onPreExecute();
}
protected void onPostExecute(Void result) {
itemlist2=rsslist;
setListAdapter(rssadaptor2);
progress.dismiss(); //Dismisses loading progress dialog
//s super.onPostExecute(result);
}
}
//GETS RSS FEED IN ASYNCHRONOUS MODE
private class getRSSFeeds extends AsyncTask<Void, Void, Void>
{
private ProgressDialog progress = null;
ArrayList<rssentry> atlist = new ArrayList<rssentry>();
#Override
protected Void doInBackground(Void... params) {
try {
itemlist2 = null; //<=THIS LIST IS TO BE LOADED WITH THE RSS URL BELOW
atlist = retrieveRSSFeed2Str("http://stackoverflow.com/feeds/tag?tagnames=android&sort=newest");
} catch (XmlPullParserException e) {
e.printStackTrace(); // TODO Auto-generated catch block
} catch (IOException e) {
e.printStackTrace(); // TODO Auto-generated catch block
}
//LOADS DATA INTO UI RSSADAPTER (PARSER2)
rssadaptor2 = new RSSListAdaptor2(RSSMain.this, R.layout.rssitemview,atlist);
return null;
}
#Override
protected void onCancelled() {
super.onCancelled();
}
#Override
protected void onPreExecute() {
progress = ProgressDialog.show( RSSMain.this, null, "RSSJosh Loading..."); //LOADING MESSAGE
super.onPreExecute();
}
#Override
protected void onPostExecute(Void result) {
setListAdapter(rssadaptor2);
itemlist2=atlist;
progress.dismiss(); //Dismisses loading progress dialog
super.onPostExecute(result);
}
#Override
protected void onProgressUpdate(Void... values) {
super.onProgressUpdate(values);
}
}
//RSS ADAPTER (TYPE2) FOR STACK-OVERFLOW RSSFEEDS
private class RSSListAdaptor2 extends ArrayAdapter<rssentry>{
private List<rssentry> objects = null;
public RSSListAdaptor2(Context context, int textviewid, List<rssentry> objects) {
super(context, textviewid, objects);
this.objects = objects;
}
#Override
public int getCount() {
return ((null != objects) ? objects.size() : 0);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public rssentry getItem(int position) {
return ((null != objects) ? objects.get(position) : null);
}
public View getView(int position, View convertView, ViewGroup parent) {
View view = convertView;
if(null == view)
{
LayoutInflater vi = (LayoutInflater)RSSMain.this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = vi.inflate(R.layout.rssitemview, null);
}
rssentry data = objects.get(position);
if(null != data)
{ //CREATE TEXTVIEW OBJECTS FORTITLE, DATE AND DESCRIPTION DATA
TextView title = (TextView)view.findViewById(R.id.txtTitle);
TextView date = (TextView)view.findViewById(R.id.txtDate);
TextView description = (TextView)view.findViewById(R.id.txtDescription);
//PUT TEXT ON TITLE AND DATE VIEWS
title.setText(data.title);
date.setText("Published on: " + data.published); //PREVIOUSLY date.setText("on " + data.date);
//PREPARE AND LOAD TEXT FOR THE SUMMARY VIEW
String txt=null;
//Clean and trim summary string before displaying
txt=data.summary.toString().substring(30,data.summary.toString().length());
if (txt.length()>=300)
txt=txt.substring(0,299)+"..."; ///DISPLAY A SUMMARY OF 300 CHARACTERS MAX, IN THE RSS HEADLINES
description.setText(txt); //PUT TEXT
}
return view;
}
}
LoaderManager.LoaderCallbacks<ArrayList<rssentry>> callBacks1 = new LoaderManager.LoaderCallbacks<ArrayList<rssentry>>() {
/* Implement the three callback methods here */
public android.content.Loader<ArrayList<rssentry>> onCreateLoader( //START LOADING
int arg0, Bundle arg1) {
// TODO Auto-generated method stub
android.content.Loader<ArrayList<rssentry>> rsslist=null;
//TEMPORARY TOAST TO DEBUG CORRECT STRING FORMATION
toastxt="Toastiee! Preparing for ATL Task";
toast = Toast.makeText(getBaseContext(), toastxt, LENGTH_SHORT);
toast.show();
ATLgetfeeds a= new ATLgetfeeds(getBaseContext());
//TEMPORARY TOAST TO DEBUG CORRECT STRING FORMATION
toastxt="Toastiee! ATL Task created";
toast = Toast.makeText(getBaseContext(), toastxt, LENGTH_SHORT);
toast.show();
return rsslist;
}
#Override
public void onLoadFinished( //START LOADING
android.content.Loader<ArrayList<rssentry>> arg0,
ArrayList<rssentry> arg1) {
// TODO Auto-generated method stub
}
#Override
public void onLoaderReset(android.content.Loader<ArrayList<rssentry>> arg0) {
// TODO Auto-generated method stub
}
};
}

Categories