I am having Pull to Refresh https://github.com/chrisbanes/Android-PullToRefresh as given in this link. Everything works fine. But when my list item finishes, the loading icon and pull to refresh label is still visible. So, how to disable the scrolling when end of list reached?
mainListView.setOnRefreshListener(new OnRefreshListener() {
#Override
public void onRefresh(PullToRefreshBase refreshView) {
String total_bk_count = subCategory .getTotal_Book_Count();
count_of_book = Integer.parseInt(total_bk_count);
listCountt = mainbooksAdpater.getCount();
Log.e("StroreActivity","Total book count---====----====---+"+count_of_book);
Log.e("StroreActivity","list Count---====----====---+"+listCountt);
if(listCountt < count_of_book)
{
int bookCount = Common.getBookCountNumber();
Common.setBookCount(bookCount+1);
String refresh_Pull_Url = Common.getUrlForeCategoryBooks(id, Common.NUMBER_OF_BOOKS_PER_REQUEST);
Log.e("Rathis to Check url", Common.getUrlForeCategoryBooks(id, Common.NUMBER_OF_BOOKS_PER_REQUEST));
PulltoRefreshAsync onCatBooksTaskScroll = new PulltoRefreshAsync(Common.getUrlForeCategoryBooks(id, Common.NUMBER_OF_BOOKS_PER_REQUEST));
onCatBooksTaskScroll.execute();
Log.e("StroreActivity","Total Book count::" + book_count_no);
}
else
{
mainListView.setMode(Mode.DISABLED);
Toast.makeText(getApplicationContext(), "end of list", Toast.LENGTH_SHORT).show();
}
}
});
Asynctask Class:
public class PulltoRefreshAsync extends AsyncTask<Object,Object,Object> {
int refreshCount;
String refresh_URL;
public PulltoRefreshAsync(String url) {
refresh_URL = url;
}
/*
* PulltoRefreshAsync(int i) { refreshCount = i; }
*/
#Override
protected void onPreExecute() {
super.onPreExecute();
Log.e("Checking Purpose", refresh_URL);
}
#Override
protected String doInBackground(Object... arg0) {
JsonParserRefresh jp = new JsonParserRefresh();
Log.e("StroreActivity","Array to String::" + refresh_URL);
String jsonString = jp.getJSONFromURL(refresh_URL);
Log.e("StroreActivity","JsonString::" + jsonString);
jsonParseForCategoryBooksGridScroll(jsonString);
return null;
}
#Override
protected void onPostExecute(Object result) {
super.onPostExecute(result);
/*
* if(mProgressDialog.isShowing()) { mProgressDialog.dismiss(); }
*/
final MainBooksAdapter mainbooksAdpater = new MainBooksAdapter(
StoreActivity.this, R.layout.aa, mainBooksList);
final int old_pos = mainListView.getRefreshableView()
.getFirstVisiblePosition() + 1;
mainListView.setAdapter(mainbooksAdpater);
tvvisiblebookCount.setText("" + mainbooksAdpater.getCount());
/*if(listCountt < count_of_book)
{
mainListView.setMode(Mode.DISABLED);*/
mainListView.post(new Runnable() {
#Override
public void run() {
mainListView.onRefreshComplete();
mainListView.getRefreshableView().setSelection(old_pos);
}
});
//}
mainbooksAdpater.notifyDataSetChanged();
}
}
For other people who might have similat issue:
you don't have to implement it this way
mainListView.post(new Runnable() {
#Override
public void run() {
mainListView.onRefreshComplete();
mainListView.getRefreshableView().setSelection(old_pos);
}
});
instead do just like this :
mainListView.onRefreshComplete();
one more thing I noticed, instead of saving the old pos value to get back to it, why not just use notifyDataSetChanged it leaves the position of the list the way it is, just try not to re-instanciate you list, i.e: mainBooksList = ..., instead try this:
mainBooksList.clear();
mainBooksList.addAll(YOUR DATA);
adapter.notifyDataSetChanged();
voila!
hope this helps someone
Related
I've been trying to implement load more with asynctask but for some reason when I scroll down quickly it shows me the same items again. For exp if I scroll down my list has (1, 2, 3, 4) and when I scroll more down and load more items it gives me the same items as the previous one (1, 2, 3, 4).
I hope it is clear enough and if not I could try to explain it better.
Here is my code:
private class GetMoreData extends AsyncTask<Void, Integer, List<Item>> {
private GetMoreData() {}
protected List<Item> doInBackground(Void... param1VarArgs) {
return JsonParsingData.searchArticles(keyword,items.size(),20);
}
protected void onPostExecute(final List<Item> param1Info) {
if (param1Info != null) {
adapter.setLoadMore(new IloadMore() {
#Override
public void onLoadMore() {
if (items.size()<total)
{
items.add(null);
adapter.notifyItemInserted(items.size()-1);
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
items.remove(items.size() - 1);
adapter.notifyItemRemoved(items.size());
int index = 1;
int end = index + 20;
if(param1Info.size()<20)
end = param1Info.size();
for(int i = index;i<end;i++)
{
if(param1Info.get(i).getID() != null){
Item item= new Item(param1Info.get(i).getID(),param1Info.get(i).getTitle(),
param1Info.get(i).getImage(), param1Info.get(i).getDatePub(), param1Info.get(i).getLink());
items.add(item);
Log.e("Get More Data ID: "+i+": ", param1Info.get(i).getID());
Log.e("Get More Data Titre: "+i+": ", param1Info.get(i).getTitle());
}
}
loadMore = true;
adapter.notifyDataSetChanged();
adapter.setLoaded();
if(items.size() < total && excMore ) {
new GetMoreData().execute();
}else
Log.e("Tab 1", "" + excMore );
}
},10000);
}else {
Toast.makeText(RechercheActivity.this,"Load data completed !", Toast.LENGTH_SHORT).show();
}
}
});
}
}
protected void onPreExecute() {
super.onPreExecute();
}
}
I am relatively new to RxJava/RxAndroid. I have been using AsyncTask to do my long running tasks before now.
I have converted most of my AsyncTask to RxJava but this one.
The particular problem I am having is calling something like AsyncTask's publishProgress(params); in
the background thread. I need to do this to update the progress of a ProgressBar.
First this is the code in AsyncTask
private static class AddBooksToDatabase extends AsyncTask<String, String, String> {
//dependencies removed
AddBooksToDatabase(AddBooksDbParams params) {
//Removed assignment codes
}
#Override
protected String doInBackground(String... strings) {
//Initializing custom SQLiteOpenHelper and SQLite database
File mFile = new File(mFolderPath);
int booksSize = getFilesInFolder(mFile).size();
String[] sizeList = {String.valueOf(booksSize)};
//The first publishProgress is used to set the max of the progressbar
publishProgress(sizeList);
for (int i = 0; i < booksSize; i++) {
//publishProgress with current item, current file
publishProgress(String.valueOf(i), getFilesInFolder(mFile).get(i).getName());
//Inserting current items in database. Code removed
}
return null;
}
#Override
protected void onPreExecute() {
//Show ProgressBar
}
#Override
protected void onPostExecute(String s) {
//Hide ProgressBar
}
#Override
protected void onProgressUpdate(String... values) {
super.onProgressUpdate(values);
if (values.length == 1) {
//The first call to publishProgress
mProgressBar.setMax(Integer.parseInt(values[0]));
} else {
//Subsequent calls to publish progress
Log.i(TAG, "Current item is " + values[0] + " and current file is " + values[1]);
infoText.setText(values[1]);
mProgressBar.setProgress(Integer.parseInt(values[0]), true);
}
}
#Override
protected void onCancelled() {
cancel(true);
}
}
Code Using RxJava
final Observable<String[]> addBooksObserver = Observable.create(new Observable.OnSubscribe<String[]>() {
#Override
public void call(Subscriber<? super String[]> subscriber) {
subscriber.onNext(setAddSubscription());
subscriber.onCompleted();
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
private String[] setAddSubscription() {
S//Initializing custom SQLiteOpenHelper and SQLite database
File mFile = new File(mFolderPath);
int booksSize = getFilesInFolder(mFile).size();
String[] sizeList = {String.valueOf(booksSize)};
//The first publishProgress is used to set the max of the progressbar
addBooksObserver.doOnNext(addReturnParams(String.valueOf(sizeList.length), null, null));
for (int i = 0; i < booksSize; i++) {
EpubReader reader = new EpubReader();
//publishProgress with current item, current file*
addBooksObserver.doOnNext(addReturnParams(String.valueOf(sizeList.length),
String.valueOf(i), getFilesInFolder(mFile).get(i).getName()));
//Inserting current item in database. Code removed
}
return null;
}
private String[] addReturnParams(String totalItems, String currentItem, String currentFile) {
return new String[]{totalItems, currentItem, currentFile};
}
The problem is that lines addBooksObserver.doOnNext(addReturnParams( are displaying this error
doOnNext (rx.functions.Action1) cannot be applied to (java.lang.String[])
I don't know have any idea how to fix this because I thought that since setAddSubscription() and addReturnParams(String totalItems, String currentItem, String currentFile) are returning String array then this shouldn't be a problem. Please can you help me out?
you just have to pass the values to the onNext method of your subscriber, not the doOnNext method of your observable!
you also have to subscribe to the service. try something like this for your obserable:
Observable.create(new Observable.OnSubscribe<String[]>() {
#Override
public void call(Subscriber<? super String[]> subscriber) {
setAddSubscription(subscriber);
subscriber.onCompleted();
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<String[]>() {
#Override
public void onCompleted() {
// handle 'oparation is done'
}
#Override
public void onError(Throwable e) {
}
#Override
public void onNext(String[] values) {
if (values.length == 1) {
//The first call to publishProgress
mProgressBar.setMax(Integer.parseInt(values[0]));
} else {
//Subsequent calls to publish progress
Log.i(TAG, "Current item is " + values[0] + " and current file is " + values[1]);
infoText.setText(values[1]);
mProgressBar.setProgress(Integer.parseInt(values[0]), true);
}
}
});
you also need to modify your private methods a little bit:
private void setAddSubscription(Subscriber<? super String[]> subscriber) {
//Initializing custom SQLiteOpenHelper and SQLite database
File mFile = new File(mFolderPath);
int booksSize = getFilesInFolder(mFile).size();
String[] sizeList = {String.valueOf(booksSize)};
//The first publishProgress is used to set the max of the progressbar
subscriber.onNext(addReturnParams(String.valueOf(sizeList.length), null, null));
for (int i = 0; i < booksSize; i++) {
EpubReader reader = new EpubReader();
//publishProgress with current item, current file*
subscriber.onNext(addReturnParams(String.valueOf(sizeList.length),
String.valueOf(i), getFilesInFolder(mFile).get(i).getName()));
//Inserting current item in database. Code removed
}
}
private String[] addReturnParams(String totalItems, String currentItem, String currentFile) {
return new String[]{totalItems, currentItem, currentFile};
}
You can use Subject to call onNext() manually like this:
Subject<Event> event = Subject.create();
Now call the onNext() for sending event like:
event.onNext("event");
Finally you can return Observable by using this code:
event.toFlowable(BackpressureStrategy.LATEST)
.toObservable();
Your Observer should be like Observable.create(new Observable.OnSubscribe<String>() & in your call method you should loop through the StringArray & pass it to onNext for example:
#Override
public void call(Subscriber<? super String> subscriber) {
for(String val : setAddSubscription()) {
subscriber.onNext(val);
}
subscriber.onCompleted();
}
now onNext shall return you individual items & onCompleted will be called upon the loop is finished.
Edit
myObserver.subscribe(new Subscriber<String>() {
#Override
public void onCompleted() {
// handle completion.
}
#Override
public void onError(Throwable e) {
}
#Override
public void onNext(String value) {
// do whatever with each value passed to onNext
}
});
Observable.create(emitter -> {
for (int i = 0; i < 10; i++) {
int[] ii = {i, i * 2};
emitter.onNext(ii);
}
emitter.onComplete();
}).observeOn(AndroidSchedulers.mainThread()).subscribeOn(Schedulers.io()).subscribe(o -> {
// update progress
int[] i = (int[]) o;
Toast.makeText(SearchActivity.this, "oftad " + i[0] + " - " + i[1], Toast.LENGTH_SHORT).show();
}, t -> {
// on error
Toast.makeText(SearchActivity.this, t.getMessage(), Toast.LENGTH_SHORT).show();
}, () -> {
// progress tamom shod
Toast.makeText(SearchActivity.this, "completed", Toast.LENGTH_SHORT).show();
});
Actually what i am trying to do is that call an asyncTask several times inside a loop. So, first time the asyncTask will start immediately and from second time onwards, it will check whether the AsyncTask has been finished-if finished than again call it with different values.
Below is my code for the activity:
In onCreate()
btnUpload.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
count_response = 0;
newUploadWithSeparate();
}
});
The newUploadWithSeparate() method:
private void newUploadWithSeparate()
{
responseString_concat = "";
if(filePath.length > 0)
{
for(int i=0;i<filePath.length;i++)
{
count_response = i;
if(i == 0)
{
uploadAsync.execute(filePath[0]);
mHandler = new Handler() {
#Override public void handleMessage(Message msg) {
String s=(String)msg.obj;
Log.d("logIMEI","\n Response from Asynctask: " + s);
str_response_fromAsync = s;
}
};
}
else
{
uploadAsync.getStatus();
while(uploadAsync.getStatus() == AsyncTask.Status.RUNNING) // this while loop is just to keep the loop value waitining for finishing the asyncTask
{
int rx = 0;
}
if(uploadAsync.getStatus() != AsyncTask.Status.RUNNING)
{
if(uploadAsync.getStatus() == AsyncTask.Status.FINISHED)
{
if(str_response_fromAsync != "" || !str_response_fromAsync.equals("") || !str_response_fromAsync.isEmpty())
{
uploadAsync.execute(filePath[i]);
x = i;
mHandler = new Handler() {
#Override public void handleMessage(Message msg)
{
String s=(String)msg.obj;
Log.d("logIMEI","\n Response from Asynctask_" + x + ": " + s);
str_response_fromAsync = s;
}
};
}
}
}
}
}
}
}
And the asyncTask:
private class UploadFileToServer extends AsyncTask<String, Integer, String>
{
#Override
protected void onPreExecute()
{
super.onPreExecute();
}
#Override
protected String doInBackground(String... params)
{
return uploadFile(params[0]);
}
private String uploadFile(String pr)
{
//inside here calling webservice and getting a response string as result.
MyWebsrvcClass mycls = new MyWebsrvcClass();
return responseString_concat = mycls.Call(xxx,yyy) ;
}
#Override
protected void onPostExecute(String result)
{
Log.d("logIMEI" , "\n count_response : "+ count_response + " fileprath_len : " + filePath.length);
Message msg=new Message();
msg.obj=result.toString();
mHandler.sendMessage(msg);
super.onPostExecute(result);
}
}
Now the problem is that its not working as expected. The first time when value of i is equals 0 than the AsyncTask gets called and after that its not getting called anymore.
Plus, when first time AsyncTask is called- its still not directly entering to onPostExecute(). When the loop ends totally and newUploadWithSeparate() method ends then the onPostExecute() is working.
Any solutions for this or any other way to do this job done for using AsyncTask inside loop?
You cannot call execute() on the same object more than once. So create a new instance of UploadFileToServer for each iteration of the loop.
I am trying to scroll to a substring in a string of 1000 lines. I notice a lag in the scroll and UI thread. So I thought to use a AsyncTask but as its executed I get the text but not scroll. Here is my code
private class LongOperation extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... params) {
SharedPreferences score = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
int chapter_number_bookmark = score.getInt("chapter_number", 89);
int verse_number_bookmark = score.getInt("verse_number", 1);
GoToFunction(chapter_number_bookmark,verse_number_bookmark);
return "Executed";
}
#Override
protected void onPostExecute(String result) {
Toast.makeText(getApplicationContext(), "Executed", Toast.LENGTH_SHORT).show();
}
#Override
protected void onPreExecute() {
}
#Override
protected void onProgressUpdate(Void... values) {}
}
The GoToFunction
public void GoToFunction(int chapter, int verse)
{
int scroll_amt;
final TextView shw = (TextView) findViewById(R.id.textViewTab);
SharedPreferences score = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
int chapter_number = chapter;
int verse_number = verse;
String verse_number_str = Integer.toString(verse_number);
SQLiteDatabase as = openOrCreateDatabase("/"+Environment.getExternalStorageDirectory().getPath()+"/tamil/verse", MODE_PRIVATE, null);
Cursor a = as.rawQuery("select * from verse"+chapter_number, null);
a.moveToFirst();
strTitle = a.getString(a.getColumnIndex("title"));
final String strContent_book = a.getString(a.getColumnIndex("content"));
int number = a.getInt(a.getColumnIndex("dialogues"));
tab.setText("\n\n "+strAthi+strTitle+"\n\n "+strVasa+number+"\n\n "+strContent_book);
final int offset_dot = strContent_book.indexOf(verse_number_str_dot);
final int offset_comma = strContent_book.indexOf(verse_number_str_comma);
a.close();
as.close();
if(offset_comma!=-1||offset_dot!=-1)
{
if(offset_comma==-1||(offset_dot<offset_comma))
{
try
{
Toast.makeText(getApplicationContext(), "Athiyayam : "+ chapter_number +" Verse : "+ verse_number, Toast.LENGTH_LONG).show();
**scroll(offset_dot); //Scroll function**
}
catch(Exception e)
{
Log.e("Scroll_comma", "Exception", e);
}
}
else
{
try
{
Toast.makeText(getApplicationContext(), "Athiyayam : "+ chapter_number +" Verse :"+ verse_number, Toast.LENGTH_LONG).show();
scroll(offset_comma);
}
catch(Exception e)
{
Log.e("Scroll", "Exception", e);
}
}
}
else
{
Toast.makeText(getApplicationContext(), "Not found", Toast.LENGTH_LONG).show();
}
}
Scroll Function
public void scroll(final int a)
{
final TextView shw = (TextView) findViewById(R.id.textViewTab);
try
{
mScroll.post(new Runnable() {
#Override
public void run() {
int y = shw.getLayout().getLineForOffset(a); // e.g. I want to scroll to line 40
int n = shw.getLayout().getLineTop(y);
mScroll.scrollTo(0, n);
}
});
}
catch(Exception e)
{
Log.e("scroll", "error", e);
}
}
Here I get the text. But the scroll function doesn't get executed. Also I want to do a spinner activity as the bookmark activity starts and finish as it ends which can be done in PreExecute and PostExecute
paste this code to your layout:
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
>
<!-- "your layout" -->
</ScrollView>
From your code you try to update main thread from doInBackground.
#Override
protected String doInBackground(String... params) {
....
GoToFunction(chapter_number_bookmark,verse_number_bookmark);
.....
}
You can't do that. I'm sure you get Exception in logcat. If you want to update anyways, do that through Handler
Lets say we have
private TextView m_txtLog;
private ScrollView m_sv;
So to scroll to last line should be something like:
m_sv.post(new Runnable() {
public void run() {
m_sv.scrollTo(0, m_txtLog.getHeight());
}
});
If you run it from Service or AsyncTask use Handler like:
static final int LOG_MSG = 1;
private Handler mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
String txt;
switch (msg.what) {
case LOG_MSG:
txt = msg.obj.toString();
m_txtLog.append(txt);
m_sv.post(new Runnable() {
public void run() {
m_sv.scrollTo(0, m_txtLog.getHeight());
}
});
break;
default:
super.handleMessage(msg);
}
}
};
And now we can write from AsyncTask:
mHandler.sendMessage(mHandler.obtainMessage(LOG_MSG, "Agent started" + "\n\n"));
As you can see scrollTo wrapped by handler. By this way it will work.
(Tested)
Using asynctask for scrolling is really not necessary in this case. you can simply run the code in the main thread. It will work fine.
because if the user clicks the scrollview while scrolling by asyntask. there will be unexpected behaviour.
And also specify
1. android:hardwareAccelerated="true" in your activity manifest of scrollview
2. In addition to above step - scrollView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
This will use hardware acceleration to your scrollview for smooth scrolling.
I just tried to implement a progressdialog and I have some issues to change the text during my long and complex calculations.
for (String aString:myStringArray){
Log.v(TAG, aString);
mProgressDialog.incrementProgressBy(1);
mProgressDialog.setMessage(aString);
}
I can clearly see the incrementProgressBy working and my dialog updating, but the message does not change.
Any idea on how to make that work?
Thank a lot.
Just found the answer, that's working fine:
runOnUiThread(changeMessage);
with that code:
private Runnable changeMessage = new Runnable() {
#Override
public void run() {
//Log.v(TAG, strCharacters);
m_ProgressDialog.setMessage(strCharacters);
}
};
I upload pictures to Firebase in a loop and updating the ProgressDialog each image:
(I am in a Fragment, so I use getActivity() before calling to runOnUiThread())
List<Bitmap> bitmaps;
int picCounter = 1;
...
progressDialog = ProgressDialog.show
(getContext(), "sending...", "just a minute", false, false);
new Thread(new Runnable() {
#Override
public void run() {
for (int i = 0; i < bitmaps.size(); i++) {
String filename = String.valueOf(i);
uploadPic(bitmaps.get(i), "img" + filename, new MyCallback() {
#Override
public void onFinish() {
picCounter++;
Objects.requireNonNull(getActivity()).runOnUiThread(new Runnable() {
public void run() {
progressDialog.setTitle ("upoading " + picCounter + "image from " + bitmaps.size());
}
});
}
});
}
}
}).start();
uploadPic method:
public interface MyCallback { void onFinish ();}
private void uploadPic(final Bitmap bitmap, final String fileName, final MyCallback callback) {
... // uploading to firebase and then:
callback.onFinish();
}