Avoid duplicate callings of CallBack<T>, Retrofit - android

I am working with the data of the GitHub api, using Retrofit. In one activity, I need need 2 references to the Retrofit Builder, hence - 2 callbacks. The calss' definition so far is:
public class UserScreen extends Activity implements Callback<GitHubUser>, Callback<GitHubRepos>
How can the duplicate class be avoided? My definition for the methods of the User call looks like that:
public void loadData(View view) {
Gson gson = new GsonBuilder()
.setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ")
.create();
retrofit = new Retrofit.Builder()
.baseUrl(GitHubUserAPI.ENDPOINT)
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
// prepare call in Retrofit 2.0
GitHubUserAPI githubUserAPI = retrofit.create(GitHubUserAPI.class);
Call<GitHubUser> callUser = githubUserAPI.getUser(newString);
callUser.enqueue(this);
Call<GitHubUser> callAvatar = githubUserAPI.getAvatar(newString);
callAvatar.enqueue(this);
Call<GitHubUser> callFollowers = githubUserAPI.getFollowers(newString);
callFollowers.enqueue(this);
}
#Override
public void onResponse(Call<GitHubUser> call, final Response<GitHubUser> response) {
final int code = response.code();
if (code == 200) {
final GitHubUser user = response.body();
userNameTV.setText(user.getName());
followersTV.setText("Followers: " + user.getFollowers());
followingTV.setText("Following: " + user.getFollowing());
ImageDownloader task = new ImageDownloader();
Bitmap myImage;
try {
myImage = task.execute(user.getAvatar()).get();
avatarImg.setImageBitmap(myImage);
avatarImg.getLayoutParams().height=150;
avatarImg.getLayoutParams().width=150;
} catch (Exception e) {
e.printStackTrace();
}
}
}
public class ImageDownloader extends AsyncTask<String, Void, Bitmap> {
#Override
protected Bitmap doInBackground(String... urls) {
try {
URL url = new URL(urls[0]);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.connect();
InputStream inputStream = connection.getInputStream();
Bitmap myBitmap = BitmapFactory.decodeStream(inputStream);
return myBitmap;
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
#Override
public void onFailure(Call<GitHubUser> call, Throwable t) {
Toast.makeText(this, "Nope", Toast.LENGTH_LONG).show();
}
Thank you!

Related

Method must be called from main thread,currenty inferred thread is worker

I am trying to change the wallpaper of Android every 15 minutes or something like this. A user can choose the time and I am running a periodic work using Workmanager.
PeriodicWorkRequest periodicWorkRequest = new PeriodicWorkRequest.Builder(SomeWorker.class, 15, TimeUnit.MINUTES).build();
WorkManager.getInstance().enqueue(periodicWorkRequest);
This way I am calling my Worker Class. The working class is this
public class SomeWorker extends Worker {
Context context = getApplicationContext();
private String URL;
#NonNull
#Override
public Result doWork() {
new FetchWallpaper().execute();
return Result.SUCCESS;
}
private class FetchWallpaper extends AsyncTask<Void, Void, Void>
{
#Override
protected Void doInBackground(Void... voids) {
try
{
URL = "myurl.com";
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url(URL)
.build();
Response responses = null;
try {
responses = client
.newCall(request)
.execute();
String jsonData = responses.body().string();
JSONArray jsonArr = new JSONArray(jsonData);
JSONObject c = jsonArr.getJSONObject(new Random().nextInt(jsonArr.length()));
String imageUrl = c.getString("wallpaper");
Bitmap result= Picasso.with(getApplicationContext())
.load(imageUrl)
.get();
WallpaperManager wallpaperManager = WallpaperManager.getInstance(getApplicationContext());
try {
wallpaperManager.setBitmap(result);
} catch (Exception ex) {
ex.printStackTrace();
}
} catch (Exception e) {
e.printStackTrace();
}
Date currentTime = Calendar.getInstance().getTime();
}
catch (Exception e)
{
Date currentTime = Calendar.getInstance().getTime();
}
return null;
}
}}
On that Particular line,
new FetchWallpaper().execute();
I am getting the error saying it must call from the main thread. I am new to Android, I don't know if this is the good approach.
Please let me know if there is any better approach to perform such kind of task.
The Worker class already calls doWork on a background thread - you don't need to use AsyncTask at all.
Just move everything from your doInBackground method directly into the Worker's doWork.
You can not update UI from doInBackground method. If you want to do something on UI you must do that on Main UI thread. So write setBitmap code in onPostExecute method as onPostExecute on on Main UI Thread.
To do that set third parameter of AsyncTask as String
AsyncTask<Void, Void, String>
So that return type of doInBackground method will be String
protected String doInBackground(Void... voids)
...
...
return imageUrl;
}
And Your onPostExecute method will be like
#Override
protected void onPostExecute(String imageUrl) {
super.onPostExecute(imageUrl);
Bitmap result= Picasso.with(getApplicationContext())
.load(imageUrl)
.get();
WallpaperManager wallpaperManager = WallpaperManager.getInstance(getApplicationContext());
try {
wallpaperManager.setBitmap(result);
} catch (Exception ex) {
ex.printStackTrace();
}
}
new AsyncTask<Void, Bitmap, Bitmap>() {
#Override
protected Bitmap doInBackground(Void... params) {
Bitmap bitmap = null;
try {
InputStream inputStream;
inputStream = new java.net.URL(url).openStream();
bitmap = BitmapFactory.decodeStream(inputStream);
}catch (Exception e) {
logAppE(TAG, "BITMAP ERROR -> " + e.getMessage());
}
return bitmap
}
#Override
protected void onPostExecute(Bitmap s) {
try {
Glide.with(context).asGif().load(s).into(imgViewGIF);
} catch (Exception e) {
logAppE(TAG, "BITMAP -> " + e.getMessage());
}
}
}.execute();

How do I change wallpaper periodically using WorkManager?

I am trying to change the wallpaper of Android, in some periodic interval.
I used WorkManager to run a worker, that downloads the wallpaper in the background and sets it.
As long as the app is running, the wallpaper is changed. When I close the wallpaper, it stops. I am using PeriodcWork in Workmanager.
This is my code
public class OneTimeWorker extends Worker {
Context context = getApplicationContext();
private String URL;
#NonNull
#Override
public Result doWork() {
new FetchWallpaper().execute();
return Result.SUCCESS;
}
private class FetchWallpaper extends AsyncTask<Void, Void, Bitmap>
{
#Override
protected Bitmap doInBackground(Void... voids) {
String imageUrl="";
Bitmap result = null;
try
{
URL = "myurl.com";
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url(URL)
.build();
Response responses = null;
try {
responses = client
.newCall(request)
.execute();
String jsonData = responses.body().string();
JSONArray jsonArr = new JSONArray(jsonData);
JSONObject c = jsonArr.getJSONObject(new Random().nextInt(jsonArr.length()));
imageUrl = c.getString("wallpaper");
result = Picasso.with(getApplicationContext())
.load(imageUrl)
.get();
} catch (Exception e) {
e.printStackTrace();
}
}
catch (Exception e)
{
}
return result;
}
#Override
protected void onPostExecute(Bitmap bitmap) {
super.onPostExecute(bitmap);
WallpaperManager wallpaperManager = WallpaperManager.getInstance(getApplicationContext());
try {
wallpaperManager.setBitmap(bitmap);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
}
You better use Android-Job by Evernote.
Internally uses WorkManager, provides smooth, nice - chained methods & reliability while it's easy to implement.
Automatically chooses between JobManager/WorkManager/GCM/AlarmManager to ensure that your code must execute.
I myself using this and it's good.

Use of an API toke in my android app

I got an api token for my api but don't know how to implement it in my code...
this is the code i have for reaching my api:
public class DataVoetbalWebservice extends AsyncTask<VoetbalDataInterface, Void, JSONArray> {
private static final int CONNECTION_TIMEOUT = 12000;
private static final int DATARETRIEVAL_TIMEOUT = 12000;
VoetbalDataInterface listener;
private ProgressDialog dialog;
Context context;
public void setActivity(Context context) {
this.context = context;
dialog = new ProgressDialog(context);
}
#Override
protected void onPreExecute() {
dialog.setMessage("De Verschillende competities ophalen, even geduld aub.");
dialog.show();
}
#Override
protected JSONArray doInBackground(VoetbalDataInterface... params) {
listener = params[0];
// execute search
disableConnectionReuseIfNecessary();
HttpURLConnection urlConnection = null;
try {
// create connection
//URL urlToRequest = new URL("http://datatank.stad.gent/4/bevolking/geboortes.json?%2Fbevolking%2Fgeboortes=");
URL urlToRequest = new URL("http://api.football-data.org/v1/competitions");
urlConnection = (HttpURLConnection)
urlToRequest.openConnection();
urlConnection.setConnectTimeout(CONNECTION_TIMEOUT);
urlConnection.setReadTimeout(DATARETRIEVAL_TIMEOUT);
// handle issues
int statusCode = urlConnection.getResponseCode();
if (statusCode == HttpURLConnection.HTTP_UNAUTHORIZED) {
} else if (statusCode != HttpURLConnection.HTTP_OK) {
// handle any other errors, like 404, 500,..
}
// create JSON object from content
InputStream in = new BufferedInputStream(
urlConnection.getInputStream());
return new JSONArray(getResponseText(in));
} catch (MalformedURLException e) {
// URL is invalid
Log.d("Info", e.getMessage());
} catch (SocketTimeoutException e) {
// data retrieval or connection timed out
Log.d("Info", e.getMessage());
} catch (IOException e) {
// could not read response body
// (could not create input stream)
Log.d("Info", e.getMessage());
} catch (JSONException e) {
// response body is no valid JSON string
Log.d("Info", e.getMessage());
} finally {
if (urlConnection != null) {
urlConnection.disconnect();
}
}
return null;
}
#Override
protected void onPostExecute(JSONArray json) {
if (dialog.isShowing()) {
dialog.dismiss();
}
ArrayList <Competitie> competities = new ArrayList<>();
try {
for (int i = 0; i < json.length(); i++) {
Competitie competitie = new Competitie();
JSONObject jsonObject = json.getJSONObject(i);
competitie.setId(jsonObject.getInt("id"));
competitie.setCaption(jsonObject.getString("caption"));
competitie.setLeague(jsonObject.getString("league"));
competitie.setYear(jsonObject.getString("year"));
competitie.setCurrentMatchday(jsonObject.getInt("currentMatchday"));
competitie.setNumberOfMatchdays(jsonObject.getInt("numberOfMatchdays"));
competitie.setNumberOfTeams(jsonObject.getInt("numberOfTeams"));
competitie.setNumberOfGames(jsonObject.getInt("numberOfGames"));
JSONObject links = jsonObject.getJSONObject("_links");
JSONObject teams = links.getJSONObject("teams");
JSONObject stand = links.getJSONObject("leagueTable");
competitie.setTeamString(teams.getString("href"));
competitie.setStandUrl(stand.getString("href"));
competities.add(competitie);
}
} catch (JSONException e) {
e.printStackTrace();
}
listener.updateScreenCompetities(competities);
}
/**
* required in order to prevent issues in earlier Android version.
*/
private static void disableConnectionReuseIfNecessary() {
// see HttpURLConnection API doc
if (Integer.parseInt(Build.VERSION.SDK)
< Build.VERSION_CODES.FROYO) {
System.setProperty("http.keepAlive", "false");
}
}
private static String getResponseText(InputStream inStream) {
// very nice trick from
// http://weblogs.java.net/blog/pat/archive/2004/10/stupid_scanner_1.html
return new Scanner(inStream).useDelimiter("\\A").next();
}
}
where do i add the token so i can contact the api?..
because for know i can't read anymore data because the request capacity is full. i already got my api token emailed to me.
This is the documentation for the api, how do i add the request header?
Documentation about token use
thanks in advance
EDIT
added this line of code and now it works!
urlConnection.setRequestProperty("X-Auth-Token","6a0c52afadac44f5bc65bd0dcfb363c2");

"Standard simple" interfaces in Java?

So here in Java I've written a typical class, to send json to a rest server. (I'll include the whole class below for clarity.) So that's a file "Fetcher.java"
Now for the callback you need an interface. The interface is trivial, just one function with a string.
public interface FetcherInterface {
public void fetcherDone(String result);
}
Annoyingly you need a whole file for that, "FetcherInterface.java"
So this interface is nothing but "one callback with a string". Often all you need is just "one callback with no arguments".
In fact ........ are there some sort of standard interfaces I can use, or something like that?
It seems kind of annoying to have to put in a whole interface for such a simple "standard" interface.
What's the deal on this? What's the javaly solution?
It seems you CAN NOT put it in the same file:
Perhaps I misunderstand something there. If you could put it in the same file, that would be convenient at least.
(Lambdas are not yet practically available. Anyway, sometimes you want an interface.)
Just for clarity, here's how you call the class
JSONObject j = new JSONObject();
try {
j.put("height", 2.1);
j.put("width", 2.5);
j.put("command", "blah");
} catch (JSONException e) {
e.printStackTrace();
}
new Fetcher("mobile/login", j, new FetcherInterface() {
#Override
public void fetcherDone(String result) {
Log.d("DEV","all done");
doSomething(result);
}
}
).execute();
or indeed
public class HappyClass extends Activity implements FetcherInterface {
...
private void someCall() {
JSONObject j = new JSONObject();
try {
j.put("height", 2.1);
j.put("width", 2.5);
j.put("command", "blah");
} catch (JSONException e) {
e.printStackTrace();
}
new Fetcher("mobile/data", j, this).execute();
devBlank();
}
#Override
public void fetcherDone(String result) {
Log.d("DEV","all done" +result);
doSomething(result);
}
Here's the whole class... Fetcher.java file
public class Fetcher extends AsyncTask<Void, Void, String> {
private String urlTail;
private JSONObject jsonToSend;
private FetcherInterface callback;
// initializer...
Fetcher(String ut, JSONObject toSend, FetcherInterface cb) {
urlTail = ut;
jsonToSend = toSend;
callback = cb;
}
#Override
protected String doInBackground(Void... params) {
HttpURLConnection urlConnection = null; // declare outside try, to close in finally
BufferedReader reader = null; // declare outside try, to close in finally
String rawJsonResultString = null;
String json = jsonToSend.toString();
Log.d("DEV","the json string in Fetcher is " +json);
try {
URL url = new URL("https://falcon.totalfsm.com/" + urlTail);
Log.d("DEV","the full URL in Fetcher is " +url);
// open a json-in-the-body type of connection.......
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod("POST");
urlConnection.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
urlConnection.setDoOutput(true);
urlConnection.setDoInput(true);
urlConnection.setConnectTimeout(5000);
// urlConnection.setDoOutput(false); // can be important?
urlConnection.connect();
OutputStream os = urlConnection.getOutputStream();
os.write(json.getBytes("UTF-8"));
os.close();
// annoyingly, you have to choose normal versus error stream...
InputStream inputStream;
int status = urlConnection.getResponseCode();
if (status != HttpURLConnection.HTTP_OK)
inputStream = urlConnection.getErrorStream();
else
inputStream = urlConnection.getInputStream();
if (inputStream == null) { // nothing to do.
return null;
}
StringBuffer buffer = new StringBuffer();
reader = new BufferedReader(new InputStreamReader(inputStream));
String line;
while ((line = reader.readLine()) != null) { // adding newlines makes debugging easier
buffer.append(line + "\n");
}
if (buffer.length() == 0) { // stream was empty
return null;
}
rawJsonResultString = buffer.toString();
return rawJsonResultString;
} catch (IOException e) {
Log.e("PlaceholderFragment", "Error ", e);
return null;
} finally{
if (urlConnection != null) {
urlConnection.disconnect();
}
if (reader != null) {
try {
reader.close();
} catch (final IOException e) {
Log.e("PlaceholderFragment", "Error closing stream", e);
}
}
}
}
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
Log.d("DEV", "Fetcher done");
if (s==null) {
Log.d("DEV","applying anti-null measures in Fetcher!");
s = "message from app communications layer: 'null' returned from servers for that call at " +urlTail;
}
callback.fetcherDone(s);
}
}
I feel bad answering my own question, but as there were no other answers this info may be helpful.
DaveNewton and Rowtang have supplied the exact answers here:
(Point 1) If you want a genuinely public interface, it goes in its own file. That's how Java works. There's no alternative.
(Point 2) Normally, use protected interface and declare the interface inside the class. It can then be used throughout the app.
So...
public class Fetcher extends AsyncTask<Void, Void, String> {
protected interface FetcherInterface {
public void fetcherDone(String result);
}
private String urlTail;
private JSONObject jsonToSend;
private FetcherInterface callback;
Fetcher(String ut, JSONObject toSend, FetcherInterface cb) {
urlTail = ut;
jsonToSend = toSend;
callback = cb;
}
#Override
protected String doInBackground(Void... params) {
....
(c# programmers would maybe call it "IFetcher".)

Making HTTP request using OkHttp library inside doInBackground() of AsyncTask blocks UI operation

I was trying making OkHttp request in AsyncTask using call.execute() -- Synchronous call.
I have two buttons in my layout. Pressing button1 starts AsyncTask, that executes OkHttp request.call.execute().
And pressing button2, I just update a TextView.
Observation: While AsyncTask is running, I can not update TextView.
But, if I don't use AsyncTask and use OkHttpClient.newCall().enqueue() method,then I can update TextView by pressing button2.
Any answer for "Why using AsyncTask in this case not working"?
Source Code Sample:
bpost = (Button) findViewById(R.id.bpost);
bpost.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
i++;
tv.setText(""+i);
}
});
bstart.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
OkHttpHandler handler = new OkHttpHandler();
byte[] image = new byte[0];
try {
image = handler.execute(url).get();
if (image != null && image.length > 0) {
Bitmap bitmap = BitmapFactory.decodeByteArray(image, 0, image.length);
imageView.setImageBitmap(bitmap);
tv.setText("Total btytes download: " + image.length);
}
} catch (Exception e) {
tv.setText("sorry, something went wrong!");
}
}
public class OkHttpHandler extends AsyncTask<String, Void, byte[]> {
OkHttpClient client = new OkHttpClient();
#Override
protected byte[] doInBackground(String... params) {
Request.Builder builder = new Request.Builder();
builder.url(params[0]);
Request request = builder.build();
try {
Response response = client.newCall(request).execute();
return response.body().bytes();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
This is because get() method of AsyncTask waits for the computation to finish in doInBackground method and then retrieves its result. See this link.
This will make your main UIThread in wait mode until doInBackground finish its execution or there is some exception occur(i.e. CancellationException,ExecutionException and InterruptedException).
You should use onPostExecute(Result) override method of AsyncTask.
private class OkHttpHandler extends AsyncTask<String, Void, byte[]> {
OkHttpClient client = new OkHttpClient();
#Override
protected byte[] doInBackground(String... params) {
Request.Builder builder = new Request.Builder();
builder.url(params[0]);
Request request = builder.build();
try {
Response response = client.newCall(request).execute();
return response.body().bytes();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(byte[] bytes) {
super.onPostExecute(bytes);
try {
if (bytes != null && bytes.length > 0) {
Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
imageView.setImageBitmap(bitmap);
tv.setText("Total btytes download: " + bytes.length);
}
} catch (Exception e) {
tv.setText("sorry, something went wrong!");
}
}
}

Categories

Resources