I am learnign how to handle and to use functional programming in Android. So I developed the below code. I would like to handle the HandlerThread as observable, but when I try to call .start() from
.map() operator I receive the following error:
no instances of type variable(s) R exists so that void conforms to R
please let me know why I am getting this error and how to solve it.
code:
public Single<HandlerThread> getObsInitializedHandlerThread() {
this.mMyHandlerThread = new MyHandlerThread(NAME_MY_HANDLER_THREAD);
return Single.just(this.mMyHandlerThread);
}
#Override
protected void onResume() {
super.onResume();
String TAG_LOG = ActMain.TAG_LOG + "." + "onResume()";
Log.v(TAG_LOG, ":");
this.getObsInitializedHandlerThread()
.map(mMyHandlerThread -> mMyHandlerThread.start());
}
private class MyHandlerThread extends HandlerThread {
public MyHandlerThread(String name) {
super(name);
String TAG_LOG = ActMain.class.getSimpleName() + "." + "MyHandlerThread() Constructor";
Log.v(TAG_LOG, ":");
}
#Override
protected void onLooperPrepared() {
super.onLooperPrepared();
String TAG_LOG = ActMain.class.getSimpleName() + "." + onLoopPrepared()";
Log.v(TAG_LOG, ":");
}
}
In map you allways need to return a value (T) you cant return a void so can you trye
this.getObsInitializedHandlerThread()
.map(mMyHandlerThread ->{
mMyHandlerThread.start();
return mMyHandlerThread;
});
Related
I am using a Roomdatabase and I wish to search get a single object from the database when I give it's name. For that I wrote this Query in the DAO :
#Query("SELECT * FROM kuh_table WHERE name = :kuhName ")
Kuh findKuh(String kuhName);
I call it in the repository this way :
public Kuh findKuh(String kuhName){
final Kuh[] kuh = new Kuh[1];
new Thread(new Runnable() {
volatile boolean running = true;
#Override
public void run() {
if(running!= true) {
return;
}
kuh[0] =kuhDAO.findKuh(kuhName);
running = false;
}
}).start();
return kuh[0];
}
then in my ViewModel this way :
public Kuh findKuh(String kuhName){ return repository.findKuh(kuhName);}
I then initialize my ViewModel in a fragment and try using the method by giving a String like this:
MarkerApiKt.setMarkerTapListener(mapView, (MarkerTapListener) (new MarkerTapListener() {
public void onMarkerTap(#NotNull View view, int x, int y) {
Intrinsics.checkNotNullParameter(view, "view");
if (view instanceof MapMarker) {
MarkerCallout callout = new MarkerCallout(context);
callout.setTitle(((MapMarker) view).getName());
callout.setSubTitle("position: " + ((MapMarker) view).getX() + " , " + ((MapMarker) view).getY());
Kuh kuh = kuhViewModel.findKuh(((MapMarker) view).getName());
Toast.makeText(context, "this is "+ kuh.getName(), Toast.LENGTH_SHORT).show();
but somehow the istance of my object is always null since I end up with a nullpointer exception.
Any idea what I may be doing wrong?
So, as #Olli said, the problem was that my thread in my Repository didn't finish its execution, which is why it returned a null object.
I just changed my code this way and now it works fine
public Kuh findKuh(String kuhName) throws InterruptedException {
final Kuh[] kuh = new Kuh[1];
Thread t1 = new Thread(new Runnable() {
volatile boolean running = true;
#Override
public void run() {
if(running!= true) {
return;
}
kuh[0] =kuhDAO.findKuh(kuhName);
running = false;
}
});
t1.start();
t1.join();
return kuh[0];
}
I am learning RxAndroid api, so I created an example where the input is two integers and the output should be a string containing these integers. for example,
for 1 and two the output should be "1,2" and so on.
in the below code is my attempts to achieve what I am planning to do, but I need guiding and help please.
code:
public class MainActivity extends AppCompatActivity {
private final static String TAG = MainActivity.class.getSimpleName();
private EditText mEditTextValue1 = null;
private EditText mEditTextValue2 = null;
private Button mButtonStartAsyncTask = null;
private rx.Observable<Integer> mAsyncObservable = null;
private TextView mTextViewProcessedValue = null;
Subscriber<String> mAsyncSubscriber = new Subscriber<String>() {
#Override
public void onCompleted() {
Log.w(TAG, "onCompleted(mAsyncSubscriber)");
}
#Override
public void onError(Throwable e) {
Log.w(TAG, "onError(mAsyncSubscriber)");
}
#Override
public void onNext(String next) {
Log.w(TAG, "onNext(mAsyncSubscriber)");
mTextViewProcessedValue.setText();
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initViews();
}
private void initViews() {
mEditTextValue1 = (EditText) findViewById(R.id.editTextValue1);
mEditTextValue2 = (EditText) findViewById(R.id.editTextValue2);
mButtonStartAsyncTask = (Button) findViewById(R.id.buttonStartAsyncTask);
mButtonStartAsyncTask.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Integer value1 = Integer.valueOf(mEditTextValue1.getText().toString());
Integer value2 = Integer.valueOf(mEditTextValue2.getText().toString());
mAsyncObservable = rx.Observable.just(value1, value2)
.delay(3, TimeUnit.SECONDS, AndroidSchedulers.mainThread())
.doOnNext(items-> {
mTextViewProcessedValue = (TextView) findViewById(R.id.textViewProcessedValue);
return value1 + ", " + value2;
})
.doOnCompleted(new Action0() {
#Override
public void call() {
Log.w(TAG, "doOnCompleted");
}
})
//.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe((Action1<? super Integer>) mAsyncSubscriber);
}
});
}
}
The operator you want to use really depends on how many numbers you will have, how many products you want, and what you want to do with the final answer. For this example, we'll use scan(...)
apply a function to each item emitted by an Observable, sequentially, and emit each successive value
Observable.just(value1, value2)
.delay(3, TimeUnit.SECONDS, AndroidSchedulers.mainThread())
.scan("", (string, integer) -> string + "," + integer)
The above will emit once: "{value1},{value2}".
If you add a third value, it will emit twice : "{value1},{value2}" and "{value1},{value2},{value3}"
i'm new with RxJava too ... this might be what you want
io.reactivex.Observable.range(1, 100).subscribe(new DisposableObserver<Integer>() {
List<Integer> list = new ArrayList<>(2);
#Override
public void onNext(Integer integer) {
list.add(integer);
if (list.size() % 2 == 0) {
Log.i(TAG, "onNext: couple int :" + list.get(0) + " ," + list.get(1));
list.clear();
}
}
#Override
public void onError(Throwable e) {
}
#Override
public void onComplete() {
}
});
if you want to emit two values together you may emit a array or list or Pojo.
using zip operator example:
io.reactivex.Observable<Integer> s1 = io.reactivex.Observable.range(1, 100);
io.reactivex.Observable<Integer> s2 = io.reactivex.Observable.range(-100, 100);
io.reactivex.Observable.zip(s1, s2, new BiFunction<Integer, Integer, String >() {
#Override
public String apply(Integer i1, Integer i2) throws Exception {
return i1 + " ," + i2;
}})
.subscribe(System.out::println);
Looking on code what you trying achieve is reading from 2 fields on button click and emit them to observable, is it correct?
Please check this project to replace listener with rxjava bindings:
https://github.com/JakeWharton/RxBinding. Then code would be something like this:
RxView.clicks(button)
.map(event -> {
Integer value1 = Integer.valueOf(mEditTextValue1.getText().toString());
Integer value2 = Integer.valueOf(mEditTextValue2.getText().toString());
return value1 + "," + value2;
})
.subscribe(combinedIntegers ->
mTextViewProcessedValue.setText(combinedIntegers));
Can I use await for async class in android like used in C# ,
int stocktakingId = 0;
if (Stocktaking.SynchCountId == 0) {
stocktakingId = NewStocktaking(Stocktaking, UHFApplication.getInstance().getData("UserID"), _stocktakingType);
Stocktaking.setSynchCountId(stocktakingId);
);
} else {
stocktakingId = Stocktaking.getSynchCountId();
}
I want to await NewStocktakin metod. This callback method. after return NewStocktakin value I must continue below line. its possible ? Because my stocktakingId is return 0.
public int NewStocktaking(Stocktaking stocktaking, String userId, Constants.StocktakingType stocktakingType) {
new NewStocktakingService(count -> count).
execute(
String.valueOf(stocktaking.getName()),
String.valueOf(stocktaking.getRelatedId()),
String.valueOf(userId),
String.valueOf(stocktakingType)
);
return 0;
}
and also inteface metod
public interface AsyncResponseNewStocktaking {
int processFinish(int count);
}
and my async class
public class NewStocktakingService extends AsyncTask<String, Void, ResponseModel> {
AsyncResponseNewStocktaking delegate = null;
NewStocktakingService(AsyncResponseNewStocktaking delegate) {
this.delegate = delegate;
}
#Override
protected ResponseModel doInBackground(String... parameters) {
RequestHandler requestHandler = new RequestHandler();
ResponseModel responseModel = requestHandler.getRequestGet(UHFApplication.getInstance().apiUrl + "/api/MobileService/NewStocktaking?" +
"stocktakingName=" + URLEncoder.encode(parameters[0]) +
"&relatedID=" + parameters[1] +
"&userID=" + parameters[2] +
"&stocktakingType=" + parameters[3]);
return responseModel;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected void onPostExecute(ResponseModel responseModel) {
super.onPostExecute(responseModel);
if (HttpURLConnection.HTTP_OK == responseModel.httpStatus) {
int count = Integer.parseInt(responseModel.responseString);
delegate.processFinish(count);
} else {
delegate.processFinish(0);
}
}
}
if you want the value of Your AsyncTask class. You can await using the .get() method.
So your final code should be like:
public int NewStocktaking(Stocktaking stocktaking, String userId, Constants.StocktakingType stocktakingType) {
return new NewStocktakingService(count -> count).
execute(
String.valueOf(stocktaking.getName()),
String.valueOf(stocktaking.getRelatedId()),
String.valueOf(userId),
String.valueOf(stocktakingType)
).get();
}
But that will require you to make your AsynTask return Integer. Checking your code, you anyways dont use the other properties of the ResponeModel so you can make onBackground() return Integer!
I am using Realm + Retrofit2
I am trying to implement following :
UI asks DataManger for data.
DataManger returns cached data, and checks if data has expired then calls for fresh data.
When fresh data is saved in Realm NetworkManager triggers event which is captured by UI for updating data.
Issue
When NetworkHelper saves the data in Realm, after commitTransaction() due to onChangeListeners of RealmObjects, the code in DataManger onCall() part is executed again, which again calls NetworkHelper for new data, which subsequently again saves data from the network and process goes into infinite loop. I tried gitHubUser.removeChangeListeners() at multiple points but it still not working. Please point out anything fundamentally being wrong or the correct way to implement with Realm.
Implemented codes are as follows:
DataManager
public Observable<GitHubUser> getGitHubUser(final String user){
return databaseHelper.getGitHubUser(user).doOnNext(new Action1<GitHubUser>() {
#Override
public void call(GitHubUser gitHubUser) {
if(gitHubUser==null || !isDataUpToDate(CACHE_TIME_OUT,gitHubUser.getTimestamp())){
if(gitHubUser!=null)
System.out.println("isDataUpToDate = " + isDataUpToDate(CACHE_TIME_OUT,gitHubUser.getTimestamp()));
networkHelper.getGitHubUserRxBus(user);
}
}
});
}
DataBaseHelper
public Observable<GitHubUser> saveGitHubUser(GitHubUser user, String userId) {
realmInstance.beginTransaction();
user.setUserId(userId);
user.setTimestamp(System.currentTimeMillis());
GitHubUser userSaved = realmInstance.copyToRealm(user);
Observable<GitHubUser> userSavedObservable = userSaved.asObservable();
realmInstance.commitTransaction();
return userSavedObservable;
}
public Observable<GitHubUser> getGitHubUser(String user){
System.out.println("DatabaseHelper.getGitHubUser");
GitHubUser result = realmInstance.where(GitHubUser.class).contains("userId",user, Case.INSENSITIVE).findFirst();
if(result != null){
return result.asObservable();
}else{
return Observable.just(null);
}
}
NetworkHelper
public void getGitHubUserRxBus(final String user){
System.out.println("NetworkHelper.getGitHubUserRxBus");
retroFitService.user(user)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.flatMap(new Func1<GitHubUser, Observable<GitHubUser>>() {
#Override
public Observable<GitHubUser> call(GitHubUser gitHubUser) {
System.out.println("NetworkHelper.call");
return databaseHelper.saveGitHubUser(gitHubUser,user);
}
}).subscribe(new Action1<GitHubUser>() {
#Override
public void call(GitHubUser gitHubUser) {
if (rxBus.hasObservers()) {
System.out.println("NetworkHelper.call");
rxBus.send(gitHubUser);
}
}
});
}
Activity
subscription.add(dataManager.getGitHubUser("gitHubUserName")
.subscribe(new Subscriber<GitHubUser>() {
#Override
public void onCompleted() {
System.out.println("LoginActivity.call" + " OnComplete");
}
#Override
public void onError(Throwable e) {
System.out.println("throwable = [" + e.toString() + "]");
}
#Override
public void onNext(GitHubUser gitHubUser) {
System.out.println("LoginActivity.call" + " OnNext");
if (gitHubUser != null) {
sampleResponseText.setText(gitHubUser.getName() + " timestamp " + gitHubUser.getTimestamp());
}
onCompleted();
}
}));
subscription.add(rxBus.toObserverable().subscribe(new Action1<Object>() {
#Override
public void call(Object o) {
if(o instanceof GitHubUser){
GitHubUser gitHubUser = ((GitHubUser)o);
sampleResponseText.setText(gitHubUser.getName() + " time " + gitHubUser.getTimestamp());
}
}
}));
UPDATE
Finally Solved it by following in DataManger:
return Observable.concat(databaseHelper.getGitHubUser(user).take(1),
networkHelper.getGitHubUser(user))
.takeUntil(new Func1<GitHubUser, Boolean>() {
#Override
public Boolean call(GitHubUser gitHubUser) {
boolean result = gitHubUser!=null && isDataUpToDate(CACHE_TIME_OUT,gitHubUser.getTimestamp());
System.out.println("isDataUpToDate = " + result);
return result;
}
});
I think you have a loop going in your code:
1) You create an observable from a RealmResults in getGithubUser().Realm observables will emit every time you change data that might effect them.
2) You call networkHelper.getGitHubUserRxBus(user) after retrieving the user from Realm.
3) When getting a user from the network, you save it to Realm, which will trigger the Observable created in 1) to emit again, which creates your cycle.
To break it, you can do something like result.asObservable().first() in getGitHubUser() as that will only emit once and then complete, but it depends on your use case if that is acceptable.
when my Async task is executed it completely crashes the app
Here is the code to the class. It sits inside of my main activity class.
I'm new to threading, so sorry if I've done something ridiculous lol, I don't fully understand it.
EDIT:
private class TeamSearchTask extends AsyncTask<String,Void,Void> {
CharSequence nfo;
String [] matches;
protected Void doInBackground(String... teamNumber)
{
//Team information ------------------------------------------------------------------------------------
//Array of team data
String [] data = APIconnection.getTeams(teamNumber[0], "");
//Display basic team info
nfo = ("\nFormal Team Name:\n" + data[1] +
"\n\nLocation:\n" + data [3] + ", " + data[4] + ", " + data[5] +
"\n\nRookie Year:\n" + data[6] +
"\n\nRobot Name:\n" + data[7] +
"\n\nWebsite:\n" + data[8] + "\n\n\n\n\n\n\n\n\n");
//Make match archive --------------------------------------------------------------------------------------
String [] events = APIconnection.getEventIdsByYear(year1);
String [] matches = new String [(events.length*11)];;
for (int i = 0; i<events.length; i++)
{
matches[(i*11) + i] = APIconnection.getMatches2(teamNumber[0], events[i] ,"","")[i];
}
return null;
}
protected void onProgressUpdate(Void...voids )
{}
protected void onPostExecute(Void result) {
info.setText(nfo);
matchArchive(matches);
}
}
titlets.setText(ttl.toString());
Don't touch UI elements in different thread then UI-thread. You can use Activity::runInUiThread(Runnable r) or Handler::post(Runnable r). In second case, handler should be paired with UI-thread.
private class TeamSearchTask extends AsyncTask<String,Void,Void> {
private String[] data;
protected Void doInBackground(String... teamNumber) {
// Do your background work! No UI-stuff here!!
data = APIconnection.getTeams(teamNumber[0], "");
return null;
}
protected void onPostExecute(Void result) {
// Do all UI related stuff here, it's executed when the doInBackground is finished
}
}
edit: My bad, fixed the error with onPostExecute. You need to use Void instead of Long as you use
extends AsyncTask<String,Void,Void>
which means input parameter is String, Progress parameter type (in onProgressUpdate) and the 3rd one is for the Result.