I'm getting JSON data from a remote API. For this I'm using the Observer pattern. I created an Observer called WordTranslationObserver that gets the JSON data from the callback method. The problem is that I don't know how to get this data in the Main class...
In my Main class I can't implement PropertyChangeListener and use a translationModel.addChangeListener(this) because I'm in a static context, so "this" can't work.
What is the proper way to be able to get my data from translation.getText() in my Main class ?
Main class
public class Main {
public static void main(String[] args) throws IOException {
WordTranslation wordTranslation = new WordTranslation();
WordTranslationObserver myObserver = new WordTranslationObserver(wordTranslation);
wordTranslation.translate("sắt", "vie", "eng");
}
}
Observer
public class WordTranslationObserver implements PropertyChangeListener {
public WordTranslationObserver(WordTranslation translationModel) {
translationModel.addChangeListener(this);
}
#Override
public void propertyChange(PropertyChangeEvent event) {
System.out.println("Changed property: " + event.getPropertyName());
ArrayList<Translation> translations = (ArrayList<Translation>) event.getNewValue();
// Print recieved data from JSON to the console
// I want to be able to get translation.getText() in my Main class
for (Translation translation : translations) {
System.out.println(translation.getText());
}
}
}
Data
public class WordTranslation {
public static final String TRANSLATIONS = "translations";
private static final String BASE_URL = "http://deu.hablaa.com/hs/translation/";
private List<PropertyChangeListener> listener = new ArrayList<PropertyChangeListener>();
ArrayList<Translation> translations;
public void addChangeListener(PropertyChangeListener newListener) {
listener.add(newListener);
}
public void notifyListeners(String property, Translation[] translationArray) {
translations = new ArrayList<>();
// TODO Auto-generated method stub
for (Translation t : translationArray) {
translations.add(t);
}
for (PropertyChangeListener name : listener) {
name.propertyChange(new PropertyChangeEvent(this, "translations", null, translations));
}
}
public void translate(String word, String from, String to) {
final Translation[][] translations = new Translation[1][1];
String url = String.format("%s%s/%s-%s",BASE_URL, word, from, to);// args) "http://xxx";
System.out.println(url);
final Gson gson = new Gson();
// should be a singleton
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url(url)
.build();
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
e.printStackTrace();
}
#Override
public void onResponse(Call call, final Response response) throws IOException {
if (!response.isSuccessful()) {
throw new IOException("Unexpected code " + response);
}
translations[0] = gson.fromJson(response.body().charStream(),Translation[].class);
notifyListeners(TRANSLATIONS,translations[0]);
}
});
}
}
You could have an observer set static variables if you really wanted to, that could be polled for changes but this would defeat the principle of using the observer pattern which is event driven.
Perhaps there is some specific reason why you want this information available in the main class but I would be more inclined to offload any processing onto observers as you have already (cleanly) done, adding new implementations as you need them.
If you just want the information available to your main class (not necessarily in a static context), have your Main class implement PropertyChangeListener and register a new Main() with your WorldTranslation in the same way you have done with the WorldTranslationObserver.
HTH
Related
here is my problem:
i have used MVVM/Repository design pattern like this:
Activity -(Observes)-> ViewModel's LiveData -> Repository -> WebService API (GET Resource)
i have another calls for UPDATING Resource to WebService.
Problem:
after changing resource on the server. how i can make the Resource livedata to update itself with new servers data
i want to force it fetch data from server again because some other data may have been changed.
and i dont want to use local database (Room) and change it because my server data might be changed. and they need to fetch each time.
The Only solution passed my Mind was to create a Livedata Source (as dataVersion) to it.
and increment it after every update like this (pseudo code):
dataVersion = new MutableLiveData();
dataVersion.setValue(0);
// my repository get method hasnt anything to do with the dataVersion.
myData = Transformation.switchmap(dataVersion, versionNum -> { WebServiceRepo.getList() });
and how dataVersion should get updated in ViewModel.
You could extend MutableLiveData to give it manual fetch functionality.
public class RefreshLiveData<T> extends MutableLiveData<T> {
public interface RefreshAction<T> {
private interface Callback<T> {
void onDataLoaded(T t);
}
void loadData(Callback<T> callback);
}
private final RefreshAction<T> refreshAction;
private final Callback<T> callback = new RefreshAction.Callback<T>() {
#Override
public void onDataLoaded(T t) {
postValue(t);
}
};
public RefreshLiveData(RefreshAction<T> refreshAction) {
this.refreshAction = refreshAction;
}
public final void refresh() {
refreshAction.loadData(callback);
}
}
Then you can do
public class YourViewModel extends ViewModel {
private RefreshLiveData<List<Project>> refreshLiveData;
private final GithubRepository githubRepository;
private final SavedStateHandle savedStateHandle;
public YourViewModel(GithubRepository githubRepository, SavedStateHandle savedStateHandle) {
this.githubRepository = githubRepository;
this.savedStateHandle = savedStateHandle;
refreshLiveData = Transformations.switchMap(savedStateHandle.getLiveData("userId", ""), (userId) -> {
githubRepository.getProjectList(userId);
});
}
public void refreshData() {
refreshLiveData.refresh();
}
public LiveData<List<Project>> getProjects() {
return refreshLiveData;
}
}
And then repository can do:
public RefreshLiveData<List<Project>> getProjectList(String userId) {
final RefreshLiveData<List<Project>> liveData = new RefreshLiveData<>((callback) -> {
githubService.getProjectList(userId).enqueue(new Callback<List<Project>>() {
#Override
public void onResponse(Call<List<Project>> call, Response<List<Project>> response) {
callback.onDataLoaded(response.body());
}
#Override
public void onFailure(Call<List<Project>> call, Throwable t) {
}
});
});
return liveData;
}
While i was learning Dagger2 I made a naive service class that provides data assynchronously (in this case jokes from a funny api) but I encountered a problem and I kind of stuck with it. I'm using retrofit2 for requesting data from network.
But I can't figure out how to pull out the joke object retrieved from network (via response.body()), from anonymous internal class, into joke instance variable of the external class. I'm getting NullPointerException:
public class ChuckNorrisJokeService {
private Joke joke;
public String getJoke() {
Retrofit retrofit = new Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.baseUrl("https://api.chucknorris.io")
.build();
JokeService jokeService = retrofit.create(JokeService.class);
Call<Joke> call = jokeService.provideJoke();
call.enqueue(new Callback<Joke>() {
#Override
public void onResponse(Call<Joke> call, Response<Joke> response) {
joke = response.body();
}
#Override
public void onFailure(Call<Joke> call, Throwable t) {
System.out.println(t.getMessage());
}
});
return joke.getContent();
}
}
The Joke class is a simple POJO:
public class Joke {
#SerializedName("value")
private String content;
public String getContent() {
return content;
}
}
P.S. When calling synchronously the result is successful. How can I achieve the same functionality asynchronously?
P.S.S. I read this but it doesn't work for me and is so dirty.
The stacktrace is this:
Exception in thread "main" java.lang.NullPointerException
at com.alic.ChuckNorrisJokeService.getJoke(ChuckNorrisJokeService.java:41)
at com.alic.Application.run(Application.java:11)
at com.alic.Main.main(Main.java:6)
The Application and Main classes are very simple:
public class Application {
private ChuckNorrisJokeService chuckNorrisJokeService;
public Application() {
this.chuckNorrisJokeService = new ChuckNorrisJokeService();
}
public void run() {
System.out.println(chuckNorrisJokeService.getJoke());
}
}
and the Main class:
public class Main {
public static void main(String[] args) {
Application app = new Application();
app.run();
}
}
I have a general sendRequest() method that I use to get a json result back from the server. I'm parsing the result in an instance of the callback right now, but instead I'd much rather just pass in a type to the sendRequest() method so I can parse and handle exceptions before the callback. How can I do this? I've included the relevant code and some comments below.
public void sendRequest(int method, String url, final RequestListener listener) {
StringRequest postRequest = new StringRequest(method, url,
new Response.Listener<String>()
{
#Override
public void onResponse(String response) {
listener.gotResponse(response, null);
// Instead of parsing this into a user object, I'd like to parse it into
// a type that I pass into the sendRequest() method.
try {
User user = User.parseJson(new JSONObject(response));
} catch (JSONException e) {
e.printStackTrace();
}
}
}
First of all please note that out of the box you have JsonObjectRequest which will convert the response directly into a JSONObject which seems to be better than StringRequest in your case, but as you want to go a little bit further I would propose to create a custom request based on a generic unmarshaller.
public interface JsonUnmarshaller<T> {
T parse(JSONObject object) throws JSONException;
}
The custom request could be something like this:
public class JSONRequest extends Request<T> {
private final Listener<T> mListener;
private final JsonUnmarshaller<T> unmarshaller;
public JSONRequest(int method, String url, Listener<T> listener,
ErrorListener errorListener, JsonUnmarshaller<T> unmarshaller) {
super(method, url, errorListener);
mListener = listener;
this.unmarshaller = unmarshaller;
}
#Override
protected void deliverResponse(T response) {
mListener.onResponse(response);
}
#Override
protected Response<T> parseNetworkResponse(NetworkResponse response) {
String parsed;
try {
parsed = new String(
response.data, HttpHeaderParser.parseCharset(response.headers)
);
} catch (UnsupportedEncodingException e) {
parsed = new String(response.data);
}
try {
return Response.success(
unmarshaller.parse(new JSONObject(parsed)),
HttpHeaderParser.parseCacheHeaders(response)
);
} catch (JSONException je) {
return Response.error(new ParseError(je));
}
}
}
Then your method would be:
public <T> void sendRequest(int method, String url, final RequestListener
listener, JsonUnmarshaller<T> unmarshaller) {
JSONRequest postRequest = new JSONRequest(...
Wrote a little something for you here, I think you will be able to apply this to your example:
import java.util.*;
public class Cat{
public static void main(String... args){
Cat cat = new Cat();
cat.send(Dog.class);
cat.send(Mouse.class);
}
public <T extends Parseable> void send(Class<T> clazz){
try{
T t = clazz.newInstance();
t.parse();
} catch(Exception e){
}
}
}
interface Parseable{
void parse();
}
class Dog implements Parseable{
public void parse(){
System.out.println("Dog parse");
}
}
class Mouse implements Parseable{
public void parse(){
System.out.println("Mouse parse");
}
}
Your method is static so you probably can just do T.parseJson(). Not sure if there won't be any problems with transfering generic type to anonymous listener, but I hope it will work.
I'm trying to build a library that basically wraps our api. Basically, the structure im going for is something like this:
MySDK mySDK = new MySDK("username", "password");
mySDK.getPlaylistInfo("3423", 2323, new CustomCallback<>(){
//on response
//on failure
});
So with vanilla Retrofit, an api call usually looks something like the following:
ApiService api = retrofit.create(ApiService.class);
Call<Response> call = api.getPlaylistInfo()
call.enqueue(new Callback<Response>() {
#Override
public void onResponse(Call<Response> call, Response<Response> response) {
//handle response
}
#Override
public void onFailure(Call<Response> call, Throwable t) {
//handle failure
}
});
Basically, how would I wrap retrofits callback system into my own? Note, the reason for needing to do this is to preprocess the data returned from the api before delivering the final response.
I've written something similar so it might help you getting started, this follows an implementation I'v written for Volley, and re-used when I migrated to Retrofit2 so it resembles it (this SO question).
Create a global object (what you would refer to as MySDK) as a singelton class that handles your requests:
create a singleton class, which you instatiate when you're application comes up:
public class NetworkManager
{
private static final String TAG = "NetworkManager";
private static NetworkManager instance = null;
private static final String prefixURL = "http://some/url/prefix/";
//for Retrofit API
private Retrofit retrofit;
private ServicesApi serviceCaller;
private NetworkManager(Context context)
{
retrofit = new Retrofit.Builder().baseUrl(prefixURL).build();
serviceCaller = retrofit.create(ServicesApi.class);
//other stuf if you need
}
public static synchronized NetworkManager getInstance(Context context)
{
if (null == instance)
instance = new NetworkManager(context);
return instance;
}
//this is so you don't need to pass context each time
public static synchronized NetworkManager getInstance()
{
if (null == instance)
{
throw new IllegalStateException(NetworkManager.class.getSimpleName() +
" is not initialized, call getInstance(...) first");
}
return instance;
}
public void somePostRequestReturningString(Object param1, final SomeCustomListener<String> listener)
{
String url = prefixURL + "this/request/suffix";
Map<String, Object> jsonParams = new HashMap<>();
jsonParams.put("param1", param1);
Call<ResponseBody> response;
RequestBody body;
body = RequestBody.create(okhttp3.MediaType.parse(JSON_UTF), (new JSONObject(jsonParams)).toString());
response = serviceCaller.thePostMethodYouWant("someUrlSufix", body);
response.enqueue(new Callback<ResponseBody>()
{
#Override
public void onResponse(Call<ResponseBody> call, retrofit2.Response<ResponseBody> rawResponse)
{
try
{
String response = rawResponse.body().string();
// do what you want with it and based on that...
//return it to who called this method
listener.getResult("someResultString");
}
catch (Exception e)
{
e.printStackTrace();
listener.getResult("Error1...");
}
}
#Override
public void onFailure(Call<ResponseBody> call, Throwable throwable)
{
try
{
// do something else in case of an error
listener.getResult("Error2...");
}
catch (Exception e)
{
throwable.printStackTrace();
listener.getResult("Error3...");
}
}
});
}
public void someGetRequestReturningString(Object param1, final SomeCustomListener<String> listener)
{
// you need it all to be strings, lets say id is an int and name is a string
Call<ResponseBody> response = serviceCaller.theGetMethodYouWant
(String.valueOf(param1.getUserId()), param1.getUserName());
response.enqueue(new Callback<ResponseBody>()
{
#Override
public void onResponse(Call<ResponseBody> call, retrofit2.Response<ResponseBody> rawResponse)
{
try
{
String response = rawResponse.body().string();
// do what you want with it and based on that...
//return it to who called this method
listener.getResult("someResultString");
}
catch (Exception e)
{
e.printStackTrace();
listener.getResult("Error1...");
}
}
#Override
public void onFailure(Call<ResponseBody> call, Throwable throwable)
{
try
{
// do something else in case of an error
listener.getResult("Error2...");
}
catch (Exception e)
{
throwable.printStackTrace();
listener.getResult("Error3...");
}
}
});
}
}
This works with your interface (example with POST and GET request, GET could be without params):
public interface BelongServicesApi
{
#POST("rest/of/suffix/{lastpart}") // with dynamic suffix example
Call<ResponseBody> thePostMethodYouWant(#Path("lastpart") String suffix, #Body RequestBody params);
#GET("rest/of/suffix") // with a fixed suffix example
Call<ResponseBody> theGetMethodYouWant(#Query("userid") String userid, #Query("username") String username);
}
when your application comes up:
public class MyApplication extends Application
{
//...
#Override
public void onCreate()
{
super.onCreate();
NetworkManager.getInstance(this);
}
//...
}
a simple listener interface for your callback (seperate file would do good):
public interface SomeCustomListener<T>
{
public void getResult(T object);
}
and finally, from wherever you want, the context is already in there, just call:
public class BlaBla
{
//.....
public void someMethod()
{
//use the POST or GET
NetworkManager.getInstance().somePostRequestReturningString(someObject, new SomeCustomListener<String>()
{
#Override
public void getResult(String result)
{
if (!result.isEmpty())
{
//do what you need with the result...
}
}
});
}
}
you can use any object with the listener, just parse the response string to a corresponding object, depending on what you need to receive and you can call that from everywhere (onClicks, etc.), just remember the objects need to match between methods.
Hope this Helps!
Im trying to determine when LoopJ has finished all background thread http calls. So that i can then display the results of an array that is populated based on the results of my onSuccess methods.
First off, I have a String[] of file names. I'm then looping through the array and creating loopj connections like such.
ArrayList<String> files_to_update = new ArrayList<String>(file_names.length);
AsyncHttpClient client = new AsyncHttpClient();
for (final String file_name : file_names) {
client.get(BASE_URL + file_name, new AsyncHttpResponseHandler() {
public void onStart() {
Local_Last_Modified_Date = preferences.getString(file_name, "");
}
public void onSuccess(int statusCode, Header[] headers, byte[] response) {
Server_Last_Modified_Date = headers[3].getValue();
}
#Override
public void onFinish() {
if (!Local_Last_Modified_Date.trim().equalsIgnoreCase(Server_Last_Modified_Date.trim())) {
files_to_update.add(file_name);
}
}
});
}
What i'm doing here is comparing 2 date strings, The first Local_Last_Modified_Date is pulled from a preference file and the 2nd is determined by the last-modified date in the header. and then compared in the OnFinish(). This determines if the file needs to be update because the server file is newer than the preference date. Now! i know this is not the best way for comparing dates, however it will work interm for what i'm trying to do.
The issue i'm having is determining that all of the background http calls from loopj have completed so that i can now display the results of array list in a list dialog or whatever ui element i choose. I've tried looping through the arraylist, but because the loopj / http connections are background threads, the loop gets executed prior to the completion of all of the connection and therefore displays an empty or not populated fully array.
Is there a if conditional that i can write to determine if loopj has not finished executing all of the connection and when it has then execute my ui code?
The following code should address your problem:
Class file: UploadRunner.java
public class UploadRunner extends AsyncHttpResponseHandler implements Runnable {
private final AsyncHttpClient client;
private final ArrayList<String> filesList;
private final int filesCount;
private final Handler handler;
private String baseURI;
private boolean isFired;
private int filesCounter;
// Use in case you have no AHC ready beforehand.
public UploadRunner(ArrayList<String> filesList) {
this(new AsyncHttpClient(), filesList);
}
public UploadRunner(
AsyncHttpClient client,
ArrayList<String> filesList,
Handler handler
) {
assert null != client;
assert null != filesList;
assert null != handler;
this.client = client;
this.filesList = filesList;
this.handler = handler;
this.baseURI = "";
this.filesCount = filesList.size();
this.filesCounter = 0;
}
public String getBaseURI() {
return baseURI;
}
public void setBaseURI(String uri) {
baseURI = uri;
}
#Override
public void run() {
// Request to download all files.
for(final String file : filesList) {
client.get(baseURI + file, this);
}
}
#Override
public void onSuccess(int statusCode, Header[] headers, byte[] response) {
// This shouldn't happen really...
if(isFired) {
return;
}
// One more file downloaded.
filesCounter++;
// If all files downloaded, fire the callback.
if(filesCounter >= filesCount) {
isFired = true;
handler.onFinish(getLastModificationDate(headers));
}
}
private String getLastModificationDate(Header[] headers) {
// Simple mechanism to get the date, but maybe a proper one
// should be implemented.
return headers[3].getValue();
}
public static interface Handler {
public void onFinish(String lastModificationDate);
// TODO: Add onError() maybe?
}
}
In this case, you encapsulate the uploading mechanism in one place, plus expose just an interface for calling back a handler when all files are uploaded.
Typical use case:
// TODO: This typically should run in a different thread.
public class MyTask implements UploadRunner.Handler, Runnable {
private final static BASE_URI = "http://www.example.com/";
private final AsyncHttpClient client = new AsyncHttpClient();
private final ArrayList<String> filesList = new ArrayList<>();
#Override
public void run() {
filesList.add("1.png");
filesList.add("2.png");
filesList.add("3.png");
filesList.add("4.png");
filesList.add("5.png");
// Create a new runner.
UploadRunner ur = new UploadRunner(client, filesList, this);
// Set base URI.
ur.setBaseURI(BASE_URI);
// Spring the runner to life.
ur.run();
}
#Override
public void onFinish(String lastModificationDate) {
// All files downloaded, and last modification date is supplied to us.
}
}