ArrayList.indexOf() is not recognizing Objects - android

I have a ParseObject subclass , but everytime I want to get index of it it returns 0 so mListSectionPos returns an array of zero's (hachCode and equals methd implemented thanks to Apache Commons Utils).
It should be String.valueOf(mListItems.indexOf(beer_section)), but instead I'm using mListSectionPos.add(mListItems.indexOf(current_item) - 1); because it's working (more or less). Sometimes it cracks on getCurrentSectionPosition() that also works on indexOf() method.
So my question is: why indexOf() always return 0 in this piece of code?
It's based on https://github.com/bhavyahmehta/ListviewFilter - just adapted for ParseObject lists. Code below is my adaptation of his MainActivity.java that can be found here:
#Override
protected Void doInBackground(ArrayList<PiwoSubclass>... params) {
mListItems.clear();
mListSectionPos.clear();
ArrayList<PiwoSubclass> items = params[0];
if(mItems != null) {
if (mItems.size() > 0) {
String prev_section = "";
for (PiwoSubclass current_item : items) {
if (isCancelled()) break;
String current_section = current_item.getBeerName().substring(0, 1).toUpperCase(Locale.getDefault());
if (!prev_section.equals(current_section)) {
PiwoSubclass beer_section = null;
beer_section = new PiwoSubclass();
beer_section.setBeerName(current_section);
Log.i("ASD-current", beer_section.getBeerName());
mListItems.add(beer_section);
mListItems.add(current_item);
// array list of section positions
mListSectionPos.add(mListItems.indexOf(current_item) - 1); // that want works although it's way around
// TODO why is that error?
Log.i("ASD-listSectionSize", String.valueOf(mListItems.indexOf(beer_section)));
prev_section = current_section;
} else {
mListItems.add(current_item);
}
}
}
}
return null;
}
PiwoSubclass
public class PiwoSubclass extends ParseObject {
private String objectIdP;
private String marka;
private String marka_lowercase;
public PiwoSubclass() {
}
public String getObjectIdfromParse() {
return this.getObjectId();
}
public String getMarka(){
return this.getString("marka");
}
public String getBrewery(){
return this.getString("brewery");
}
public String getBeerName(){
return this.getString("beer_name");
}
public String getMarka_lowercase() {
return this.getString("marka_lowercase");
}
public void setMarka(String value){
put("marka", value);
}
public void setBeerName(String value){
put("beer_name", value);
}
public void setMarka_lowercase(String value){
put("marka_lowercase", value);
}
#Override
public int hashCode() {
return new HashCodeBuilder(17, 31) // two randomly chosen prime numbers
// if deriving: appendSuper(super.hashCode()).
.append(getObjectIdfromParse())
.toHashCode();
}
#Override
public boolean equals(Object obj) {
//return super.equals(obj);
if (!(obj instanceof PiwoSubclass))
return false;
if (obj == this)
return true;
marka_lowercase = getMarka_lowercase();
PiwoSubclass rhs = (PiwoSubclass) obj;
//Log.i("ASD-subclass", marka + "/" + rhs.getMarka());
return new EqualsBuilder()
// if deriving: appendSuper(super.equals(obj)).
.append(marka_lowercase, rhs.getMarka_lowercase())
.isEquals();
}
Now I have IndexOutOfBounds exception from PinnedHeaderAdapter:
public int getCurrentSectionPosition(int position) {
//String listChar = mListItems.get(position).getBeerName().substring(0, 1).toUpperCase(Locale.getDefault());
PiwoSubclass ps = mListItems.get(position); // TODO errorrrrrrrrr
return mListItems.indexOf(ps);
}

First, you check for mItems
if(mItems != null) {
if (mItems.size() > 0) {
but then you work with items
for (PiwoSubclass current_item : items) {
/* ... */
}
and ignore mItems for the rest of the method. I don't see any connection between these two.
It seems indexOf() doesn't return 0 but 1, otherwise you would get an ArrayList full of -1s
mListSectionPos.add(mListItems.indexOf(current_item) - 1);
I guess, somehow you always check for the first current_item, which is the second element in mListItems. If you would check for the beer_section - as it does for current_section in the original code - the code would work as expected.
After looking into ArrayList.indexOf(), the most likely reason is your PiwoSubclass.equals() method compares always equal to the first non-section element, because it hasn't set a beer name or some similar condition.
So, fixing the equals method might work as well.

Related

How to ignore failed request and continue responsing to the next requests?

I have a function that takes an article id list to set on the adapter. Everything works fine until at least one of the requests fails. Then the returned list is empty. How to make it ignore a failing request and move on to the next one? For example, I request 5 articles 1 fail, 4 are okay, so I get a list of 4.
I know, I need to use onErrorResumeNext() here, but I don't know-how.
Interface:
#GET("articles/{id}")
Observable<Articles> getArticle1(#Path("id") int id);
Activity:
private void getMoreArticles(List<Integer> l) {
ApiInterface apiInterface = ApiClient.getApiClientRX().create(ApiInterface.class);
List<Observable<?>> requests = new ArrayList<>();
for (int id : l) {
requests.add(apiInterface.getArticle1(id));
}
Observable.zip(requests, new Function<Object[], List<Articles>>() {
#Override
public List<Articles> apply(#NonNull Object[] objects) {
List<Articles> articlesArrayList = new ArrayList<>();
for (Object response : objects) {
articlesArrayList.add((Articles) response);
}
return articlesArrayList;
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.onErrorResumeNext(Observable.<List<Articles>>empty())
.subscribe(
new Consumer<List<Articles>>() {
#Override
public void accept(List<Articles> articlesList) {
adapter = new Adapter(articlesList, MainActivity.this);
if (fav) recyclerView.setAdapter(adapter);
else addRV().setAdapter(adapter);
adapter.notifyDataSetChanged();
initListener();
swipeRefreshLayout.setRefreshing(false);
}
},
new Consumer<Throwable>() {
#Override
public void accept(Throwable e) throws Exception {
}
}
).isDisposed();
}
I tried to simplify your use case a bit but I hope you got my point. You need to somehow "signal" that there was some problem in your API call and this specific Articles object should be skipped in your .zip() operator's zipper function. You can for example wrap the return value into Optional. When the value is preset, it indicates everything went fine. If not, the API call failed.
class SO69737581 {
private Observable<Articles> getArticle1(int id) {
return Observable.just(new Articles(id))
.map(articles -> {
if (articles.id == 2) { // 1.
throw new RuntimeException("Invalid id");
} else {
return articles;
}
});
}
Observable<List<Articles>> getMoreArticles(List<Integer> ids) {
List<Observable<Optional<Articles>>> requests = new ArrayList<>();
for (int id : ids) {
Observable<Optional<Articles>> articleRequest = getArticle1(id)
.map(article -> Optional.of(article)) // 2.
.onErrorReturnItem(Optional.empty()); // 3.
requests.add(articleRequest);
}
return Observable.zip(requests, objects -> {
List<Articles> articlesArrayList = new ArrayList<>();
for (Object response : objects) {
Optional<Articles> optionalArticles = (Optional<Articles>) response;
optionalArticles.ifPresent(articlesArrayList::add); // 4.
}
return articlesArrayList;
});
}
}
Explanation of interesting parts:
Simulate API error with id = 2
Wrap result of API the call into optional
Return empty optional when an error occurs
Add articles value into result array if the value is present
Verification:
public class SO69737581Test {
#Test
public void failedArticleCallsShouldBeSkipped() {
SO69737581 tested = new SO69737581();
TestObserver<List<Articles>> testSubscriber = tested
.getMoreArticles(Arrays.asList(1, 2, 3, 4))
.test();
List<Articles> result = Arrays.asList(
new Articles(1),
new Articles(3),
new Articles(4)
);
testSubscriber.assertComplete();
testSubscriber.assertValue(result);
}
}
For sake of completeness, this is how I defined Article class:
class Articles {
public int id;
public Articles(int id) {
this.id = id;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Articles articles = (Articles) o;
return id == articles.id;
}
#Override
public int hashCode() {
return Objects.hash(id);
}
}

Adding a number to a List with an already existing duplicate number

/*
ADDING NUMBERS TO ArrayLIST AND IF NEW NUMBER ENTERED SAME AS already EXISTING NUMBER
RESAULT IS DUBLICATE;
*/
private String[] phoneNumbers;
public String addPhoneNumber(String newPhoneNumber) throws SMSDataModelFullException {
String result;
if (numPhoneNumbers == phoneNumbers.length) {
result = FULL;
} else {
boolean exists;
exists = findPhoneNumberIndex(newPhoneNumber) != -1;
if (exists) {
result = DUPLICATE;
} else {
phoneNumbers[numPhoneNumbers] = newPhoneNumber;
numPhoneNumbers++;
result = newPhoneNumber;
}
}
return result;
}
This one is working perfectly to Array. I need some help with Duplicate in existing number only to List
private List<String> phoneNumber;
public String addPhoneNumber(String newPhoneNumber) throws SMSDataModelFullException {
String result;
if (maxNumPhoneNumbers!=0 && phoneNumber.size() >= maxNumPhoneNumbers) {
throw new SMSDataModelFullException(newPhoneNumber);
}
else{
boolean exist;
exist =findPhoneNumberIndex(newPhoneNumber)!= -1;
if(exist)
{
result = DUPLICATE;
}
else{
phoneNumber.add(newPhoneNumber);
}
return newPhoneNumber;
}
}
This one is not working, what I'm doing wrong? The Duplicate in List not showing some reason.
public String addPhoneNumber(String newPhoneNumber) {
String result = newPhoneNumber;
if(!phoneNumber.contains(newPhoneNumber)){ // if it is not already in the list
phoneNumber.add(newPhoneNumber); // add it to the list
}else{
result = "DUPLICATE"; // if number was already in the list result = DUPLICATE
}
return result;
}
You return newPhoneNumber always
return newPhoneNumber;
Do the same as in the first case
...
if (exists) {
result = DUPLICATE;
} else {
phoneNumber.add(newPhoneNumber);
result = newPhoneNumber;
}
}
return result;
Also your findPhoneNumberIndex() can be replaced with phoneNumber.contains(newPhoneNumber)

How to check arraylist contains this particular word in android?

I have ArrayList<String> in that I added 3-4 website names. Like, http://www.google.com, https://www.stackoverflow.com, etc. Now in my application if I type simply "google" then I want to compare that "google" word with the ArrayList<String>.
I am stuck here. Can anyone tell me how can I compare the string with the array object?
Thanks in advance.
To do so, you need to override implementation of contains(). I am giving you a simple example.
Custom ArrayList class
public class MyArrayList extends ArrayList<String> {
private static final long serialVersionUID = 2178228925760279677L;
#Override
public boolean contains(Object o) {
return indexOf(o) >= 0;
}
#Override
public int indexOf(Object o) {
int size = this.size();
if (o == null) {
for (int i = 0; i < size ; i++) {
if (this.get(i) == null) {
return i;
}
}
} else {
for (int i = 0; i < size ; i++) {
if (this.get(i).contains(String.valueOf(o))) {
return i;
}
}
}
return -1;
}
}
How to use
MyArrayList arrayList = new MyArrayList();
arrayList.add("http://www.google.com");
arrayList.add("https://www.stackoverflow.com");
arrayList.add("http://pankajchunchun.wordpress.com");
if (arrayList.contains("google")) {
System.out.println("ArrayList Contains google word");
}
if (arrayList.contains("igoogle")) {
System.out.println("ArrayList Contains igoogle word");
} else {
System.out.println("ArrayList does not Contains igoogle word");
}
Below is output for above code example
ArrayList Contains google word
ArrayList does not Contains igoogle word
See ArrayList Source Code for more custom implementation.
ArrayList.contains() test the the String through equals. From the documentation:
public boolean contains(Object o) Returns true if this list contains
the specified element. More formally, returns true if and only if this
list contains at least one element e such that (o==null ? e==null :
o.equals(e)).
example:
boolean contains = yourArrayListInstance.contains(yourString);
Edit. If you want to check for substring you have to loop on the ArrayList's content and call String.contains
You can iterate through your ArrayList<String> like
public String getWebsiteName(String toMatchString)
{
ArrayList<String> yourArrayList = new ArrayList<String>();
for (String webSiteName : yourArrayList)
{
if (webSiteName.contains(toMatchString))
return webSiteName;
}
return null;
}
and get the matching String
Use a helper function like this
public static boolean containsSubString(ArrayList<String> stringArray, String substring){
for (String string : stringArray){
if (string.contains(substring)) return true;
}
return false;
}

How to apply multiple Filters on an Adapter?

I got a listView with and a search field that calls my Adapter's getFilter().filter(keyword) func.
It is working very nice, but i would like to add an other filter that searches in different tags of my listViews's objects.
So i need two filters for my Adapter, whats the best solution for this?
Thanks,
I suppose that you implemented the filter yourself. As you cant get two filters you could have a field in the filter that defines what kind of filtering should by applied ( you could use multiple filters in your filter).
Set you field of the filter to the value you want before using the filter.
Or:
Use the keyword to choose the filter to apply. Add on the beginning of the keyword some characters which define the filter to apply. With String.beginsWith() you can check which type of filtering has to by applied. This has to be done in the Filter itself. The caller of the getFilter.filter(keyword) has to know what characters have to by added in front of the string.
Apply Multiple Filter in Listview and also use the multi sorting in ListView, try this link:
https://github.com/apurv3039/filter_listview/tree/master
I had a similar need and I've written for myself. The filter are combined with AND operator. Keep it as simple as possible. Not claiming it is perfect but it works for me. You can change according to your need.
The ItemModel
public class ItemModel {
public int ID;
public int rating;
public float avg;
public String name;
public String shortDesc;
public boolean read;
}
And the parser.java
/**
* This class is designed to be simple for parsing a filter of the form
* "object field name: variable type: operator: value"
*
* "ID:int:>:20";"name:string:=:20"
* Where ';' means AND, however this is not parsed here.
* If you need different logic, use the results.O
*
* Multiple filters seperated by ';'
*/
public class Parser {
private static final String TAG = "Parser";
public static boolean isPassingTheFiler(String filter, String field, String val) {
String[] mGroups = parseMainGroups(filter);
for (String mGroup : mGroups) {
Log.e(TAG,"Working on the main Group " +mGroup );
String[] subCommand = parseSubCommand(mGroup);
if ( field.equals(subCommand[0])) {
if (!processCommand(subCommand, val)) {
return false;
}
}
}
return true;
}
/**
* parses that data assuming they are all sperated by `;`
*/
public static String[] parseMainGroups(CharSequence commands) {
String buffer = commands.toString();
String parts[] = buffer.split(";");
return parts;
}
public static String[] parseSubCommand(String subCommand) {
//remove the double quotes.
String buffer = removeDoubleQuotes(subCommand.toString());
String parts[] = buffer.split(":");
return parts;
}
public static String removeDoubleQuotes(String quotedString) {
if ((quotedString.charAt(0) == '\"') && (quotedString.charAt(quotedString.length() - 1) == '\"')) {
return quotedString.substring(1, quotedString.length() - 1);
} else {
Log.e(TAG, quotedString + " doesn't contained in double quotes!\nReturned empty string!!!");
return "";
}
}
public static boolean processCommand(String[] subCommand, String val) {
switch (subCommand[1]) {
case "int":
Log.e("TAG","\tint Filer");
return intStatement(subCommand, val);
case "float":
Log.e("TAG","\tfloat Filer");
return floatStatement(subCommand, val);
case "string":
Log.e("TAG","\tString Filer");
return stringStatement(subCommand, val);
default:
return false;
}
}
/**
* Evaluate the Int statement's correctness with the given INT value
*/
public static boolean intStatement(String[] subCommand, String cVal) {
String operString = subCommand[2];
int iVal;
int val;
try {
iVal = Integer.parseInt(subCommand[3]);
val = Integer.parseInt(cVal);
} catch (NumberFormatException e) {
return false;
}
switch (operString) {
case "=":
return val == iVal;
case "<":
return val < iVal;
case ">":
return val > iVal;
case "<=":
return val <= iVal;
case ">=":
return val >= iVal;
case "!=":
return val != iVal;
case "s" :
//digit search as string. We look into string from that we already have
return cVal.contains(subCommand[3]);
default:
Log.e("Parser", "invalid Integer Operation");
return false;
}
}
public static boolean floatStatement(String[] subCommand, String cVal) {
String operString = subCommand[2];
float iVal;
float val;
try {
iVal = Float.parseFloat(subCommand[3]);
val = Float.parseFloat(cVal);
} catch (NumberFormatException e) {
return false;
}
switch (operString) {
case "=":
return val == iVal;
case "<":
return val < iVal;
case ">":
return val > iVal;
case "<=":
return val <= iVal;
case ">=":
return val >= iVal;
case "!=":
return val != iVal;
case "s" :
//digit search as string. We look into string from that we already have
return cVal.contains(subCommand[3]);
default:
Log.e("Parser", "invalid Integer Operation");
return false;
}
}
public static boolean stringStatement(String[] subCommand, String val) {
String operString = subCommand[2];
switch (operString) {
case "=":
//equality
return val.equals(subCommand[3]);
case "<":
//substring
return val.contains(subCommand[3]);
case "sw":
//prefix
return val.startsWith(subCommand[3]);
case "ew":
//postfix
return val.endsWith(subCommand[3]);
default:
Log.e("Parser", "invalid Integer Operation");
return false;
}
}
}
The private filter class in the adapter.
private class ItemFilter extends Filter {
#Override
protected FilterResults performFiltering(CharSequence constraint) {
String charString = constraint.toString();
String[] parts;
FilterResults filterResults = new FilterResults();
if (charString.isEmpty()) {
filterResults.values = new ArrayList<>(itemList);
} else {
//Parse the main group
parts = parseMainGroups(charString);
if (parts.length < 1) {
filterResults.values = new ArrayList<>(itemList);
} else {
List<ItemModel> filteredList = new ArrayList<>();
for (ItemModel row : itemList) {
if ( !isPassingTheFiler(charString,"ID",""+row.ID)) {
continue;
} else {
Log.e("Filter", "passed on ID" + row.ID);
}
if ( !isPassingTheFiler(charString,"name",""+row.name)) {
continue;
} else {
Log.e("Filter", "passed on name" + row.name);
}
// passed every test asked. If empty they returned true!
filteredList.add(row);
}
filterResults.values = new ArrayList<>(filteredList);
}
}
return filterResults;
}
#Override
protected void publishResults(CharSequence constraint, FilterResults results) {
updateList((List<ItemModel>) results.values);
}
}
And the updateList member funtion for the adapter
public void updateList(List<ItemModel> newList) {
DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(new ItemDiffUtilCallback(newList, itemListFiltered));
itemListFiltered.clear();
itemListFiltered.addAll(newList);
diffResult.dispatchUpdatesTo(this);
Log.e("TAG", "updated with dispatch");
}
And the difutils that helps the good animation
public class ItemDiffUtilCallback extends DiffUtil.Callback {
private List<ItemModel> oldList;
private List<ItemModel> newList;
public ItemDiffUtilCallback(List<ItemModel> newList, List<ItemModel> oldList) {
this.newList = newList;
this.oldList = oldList;
}
#Override
public int getOldListSize() {
return oldList.size();
}
#Override
public int getNewListSize() {
return newList.size();
}
#Override
public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
return oldList.get(oldItemPosition).ID == newList.get(newItemPosition).ID;
}
#Override
public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
return oldList.get(oldItemPosition).equals(newList.get(newItemPosition));
}
#Override
public Object getChangePayload(int oldItemPosition, int newItemPosition) {
return super.getChangePayload(oldItemPosition, newItemPosition);
}

Reusable AsyncTask by any activity

My goal is to have an AsyncTask that
can execute multiple times (one task at a time of course)
its current task can be cancelled
can be used by any activity
can execute many different tasks
does not have any problem with screen rotation (or phonecalls etc)
To achieve that i have created the classes shown below. But my experience with (and understanding of) threads is very limited. And since i don't know of any way to debug multiple threads, there is no way (for me) of knowing if this is going to work or not. So what i'm really asking is: Is this code ok?
And since there is no code that it is currently using this, here's an example use for it:
Data2Get d2g = new Data2Get(this, Data2Get.OpCountNumbers);
d2g.setParam("up2Num", String.valueOf(800));
LongOpsRunner.getLongOpsRunner().runOp(d2g);
So, here we go. This is the interface that every activity that wants to execute a long task (operation - op) should implement:
public interface LongOpsActivity {
public void onTaskCompleted(OpResult result);
}
This is a class to enclose any result of any task:
public class OpResult {
public LongOpsActivity forActivity;
public int opType;
public Object result;
public OpResult(LongOpsActivity forActivity, int opType, Object result){
this.forActivity = forActivity;
this.opType = opType;
this.result = result;
}
}
And finally the big part, the singleton async task class:
import java.util.HashMap;
import java.util.Map.Entry;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
import android.os.AsyncTask;
public class LongOpsRunner extends AsyncTask<Void, OpResult, Void> {
public class Data2Get implements Cloneable {
// one id for each operation
public static final int OpCountNumbers = 1;
public static final int OpCountLetters = 2;
public LongOpsActivity forActivity;
public int opType;
private HashMap<String, String> params = new HashMap<String, String>();
public Data2Get(LongOpsActivity forActivity, int opType) {
this.forActivity = forActivity;
this.opType = opType;
}
public void setParam(String key, String value) {
params.put(key, value);
}
public String getParam(String key) {
return params.get(key);
}
public void clearParams() {
params.clear();
}
#Override
protected Object clone() throws CloneNotSupportedException {
// deep clone
Data2Get myClone = (Data2Get) super.clone();
myClone.clearParams();
for (Entry<String, String> entry : params.entrySet()) {
myClone.setParam(new String(entry.getKey()), new String(entry.getValue()));
}
return myClone;
}
}
private class IntermediateResult extends OpResult {
public IntermediateResult(LongOpsActivity forActivity, int opType, Object result) {
super(forActivity, opType, result);
}
}
// not really needed
private class FinalResult extends OpResult {
public FinalResult(LongOpsActivity forActivity, int opType, Object result) {
super(forActivity, opType, result);
}
}
private final ReentrantLock lock = new ReentrantLock();
private final Condition executeOp = lock.newCondition();
private volatile boolean finished = false;
private volatile boolean waiting = true;
private volatile boolean shouldCancel = false;
private volatile boolean activityHasBeenNotified = true;
private Data2Get startingOpParams = null;
private Data2Get currentOpParams = null;
private FinalResult currentOpResult;
protected Void doInBackground(Void... nothing) {
try {
lock.lockInterruptibly();
do {
waiting = true;
while (waiting) {
executeOp.await();
}
shouldCancel = false;
activityHasBeenNotified = false;
boolean opCancelled = false;
try {
currentOpParams = (Data2Get) startingOpParams.clone();
} catch (CloneNotSupportedException cns) {
// do nothing
}
switch (currentOpParams.opType) {
case Data2Get.OpCountNumbers:
int numberCounter = 0;
int numLoopCount = 0;
while ((!opCancelled) & (numLoopCount <= 5000000)) {
if (!shouldCancel) {
numberCounter = (numberCounter + 1)
% Integer.parseInt(currentOpParams.getParam("up2Num"));
if (numberCounter == 0) {
numLoopCount++;
publishProgress(new IntermediateResult(
currentOpParams.forActivity,
currentOpParams.opType,
"Numbers loop count:" + numLoopCount));
}
} else {
opCancelled = true;
activityHasBeenNotified = true;
}
if (!opCancelled) {
currentOpResult = new FinalResult(
currentOpParams.forActivity,
currentOpParams.opType,
"Numbers loop completed.");
publishProgress(currentOpResult);
}
}
break;
case Data2Get.OpCountLetters:
int letterLoopCount = 0;
char ch = 'a';
while (!opCancelled & (letterLoopCount <= 5000000)) {
if (!shouldCancel) {
ch++;
if (Character.toString(ch).equals(currentOpParams.getParam("up2Letter"))) {
ch = 'a';
letterLoopCount++;
publishProgress(new IntermediateResult(
currentOpParams.forActivity,
currentOpParams.opType,
"Letters loop count:" + letterLoopCount));
}
} else {
opCancelled = true;
activityHasBeenNotified = true;
}
if (!opCancelled) {
currentOpResult = new FinalResult(
currentOpParams.forActivity,
currentOpParams.opType,
"Letters loop completed.");
publishProgress(currentOpResult);
}
}
break;
default:
}
} while (!finished);
lock.unlock();
} catch (InterruptedException e) {
// do nothing
}
return null;
}
public void cancelCurrentOp() {
shouldCancel = true;
}
#Override
protected void onProgressUpdate(OpResult... res) {
OpResult result = res[0];
if (result instanceof IntermediateResult) {
// normal progress update
// use result.forActivity to show something in the activity
} else {
notifyActivityOpCompleted(result);
}
}
public boolean currentOpIsFinished() {
return waiting;
}
public void runOp(Data2Get d2g) {
// Call this to run an operation
// Should check first currentOpIsFinished() most of the times
startingOpParams = d2g;
waiting = false;
executeOp.signal();
}
public void terminateAsyncTask() {
// The task will only finish when we call this method
finished = true;
lock.unlock(); // won't this throw an exception?
}
protected void onCancelled() {
// Make sure we clean up if the task is killed
terminateAsyncTask();
}
// if phone is rotated, use setActivity(null) inside
// onRetainNonConfigurationInstance()
// and setActivity(this) inside the constructor
// and all that only if there is an operation still running
public void setActivity(LongOpsActivity activity) {
currentOpParams.forActivity = activity;
if (currentOpIsFinished() & (!activityHasBeenNotified)) {
notifyActivityOpCompleted(currentOpResult);
}
}
private void notifyActivityOpCompleted(OpResult result) {
if (currentOpParams.forActivity != null) {
currentOpParams.forActivity.onTaskCompleted(result);
activityHasBeenNotified = true;
}
}
private static LongOpsRunner ref;
private LongOpsRunner() {
this.execute();
}
public static synchronized LongOpsRunner getLongOpsRunner() {
if (ref == null)
ref = new LongOpsRunner();
return ref;
}
public Object clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException();
}
}
I hope someone helps with making this work, as it would be very useful not only for me, but many other people out there. Thank you.
Try Loaders. I switched from simple AsyncTasks to AsyncTaskLoaders and they solve lots of problems. If you implement a Loader as a standalone class, it would meet all of your requirements, especially when it comes to rotation which is the biggest issue with old AsyncTask.

Categories

Resources