Skip to content

Commit da3fc16

Browse files
author
David Weiser
committed
revises Retrofit Stackoverflow example
1 parent 59451de commit da3fc16

11 files changed

Lines changed: 142 additions & 83 deletions

File tree

com.vogella.android.retrofitstackoverflow/app/build.gradle

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,10 @@ android {
1010
versionCode 1
1111
versionName "1.0"
1212
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
13+
resValue("string", "key", project.key)
14+
resValue("string", "client_id", project.client_id)
1315
}
16+
1417
buildTypes {
1518
release {
1619
minifyEnabled false
@@ -25,8 +28,9 @@ dependencies {
2528
exclude group: 'com.android.support', module: 'support-annotations'
2629
})
2730
compile 'com.android.support:appcompat-v7:25.2.0'
31+
compile 'com.android.support:recyclerview-v7:25.2.0'
2832

2933
testCompile 'junit:junit:4.12'
3034
compile 'com.squareup.retrofit2:retrofit:2.1.0'
3135
compile 'com.squareup.retrofit2:converter-gson:2.1.0'
32-
}
36+
}

com.vogella.android.retrofitstackoverflow/app/src/main/java/com/vogella/android/retrofitstackoverflow/Answer.java

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,12 @@
55
public class Answer {
66

77
@SerializedName("answer_id")
8-
private int answerId;
8+
public int answerId;
99

1010
@SerializedName("is_accepted")
11-
private boolean accepted;
11+
public boolean accepted;
1212

13-
private int score;
14-
15-
public int getAnswerId() {
16-
return answerId;
17-
}
18-
19-
public void setAnswerId(int answerId) {
20-
this.answerId = answerId;
21-
}
13+
public int score;
2214

2315
@Override
2416
public String toString() {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package com.vogella.android.retrofitstackoverflow;
2+
3+
import java.util.List;
4+
5+
public class ListWrapper<T> {
6+
List<T> items;
7+
}

com.vogella.android.retrofitstackoverflow/app/src/main/java/com/vogella/android/retrofitstackoverflow/MainActivity.java

Lines changed: 38 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
package com.vogella.android.retrofitstackoverflow;
22

3+
import android.app.Activity;
34
import android.content.Intent;
45
import android.os.Bundle;
5-
import android.support.v7.app.AppCompatActivity;
6+
import android.support.v7.widget.LinearLayoutManager;
7+
import android.support.v7.widget.RecyclerView;
68
import android.util.Log;
79
import android.view.View;
810
import android.widget.AdapterView;
@@ -14,7 +16,8 @@
1416
import com.google.gson.Gson;
1517
import com.google.gson.GsonBuilder;
1618

17-
import java.io.IOException;
19+
import java.util.ArrayList;
20+
import java.util.List;
1821

1922
import okhttp3.ResponseBody;
2023
import retrofit2.Call;
@@ -23,17 +26,15 @@
2326
import retrofit2.Retrofit;
2427
import retrofit2.converter.gson.GsonConverterFactory;
2528

26-
public class MainActivity extends AppCompatActivity {
29+
public class MainActivity extends Activity implements View.OnClickListener {
2730

2831
private StackOverflowAPI stackoverflowAPI;
2932
private String token;
30-
private static final String key = "yourKey";
3133

32-
private Button upvoteButton;
3334
private Button authenticateButton;
3435

3536
private Spinner questionsSpinner;
36-
private Spinner answersSpinner;
37+
private RecyclerView recyclerView;
3738

3839
protected void onCreate(Bundle savedInstanceState) {
3940
super.onCreate(savedInstanceState);
@@ -44,7 +45,7 @@ protected void onCreate(Bundle savedInstanceState) {
4445
@Override
4546
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
4647
Question question = (Question) parent.getAdapter().getItem(position);
47-
stackoverflowAPI.getAnswersForQuestion(question.getQuestionId()).enqueue(answersCallback);
48+
stackoverflowAPI.getAnswersForQuestion(question.questionId).enqueue(answersCallback);
4849
}
4950

5051
@Override
@@ -53,10 +54,11 @@ public void onNothingSelected(AdapterView<?> parent) {
5354
}
5455
});
5556

56-
answersSpinner = (Spinner) findViewById(R.id.answers_spinner);
57-
5857
authenticateButton = (Button) findViewById(R.id.authenticate_button);
59-
upvoteButton = (Button) findViewById(R.id.upvote_button);
58+
59+
recyclerView = (RecyclerView) findViewById(R.id.list);
60+
recyclerView.setHasFixedSize(true);
61+
recyclerView.setLayoutManager(new LinearLayoutManager(MainActivity.this));
6062

6163
createStackoverflowAPI();
6264
stackoverflowAPI.getQuestions().enqueue(questionsCallback);
@@ -65,34 +67,37 @@ public void onNothingSelected(AdapterView<?> parent) {
6567
@Override
6668
protected void onResume() {
6769
super.onResume();
68-
if(token != null){
70+
if (token != null) {
6971
authenticateButton.setEnabled(false);
70-
upvoteButton.setEnabled(true);
7172
}
7273
}
7374

7475
private void createStackoverflowAPI() {
7576
Gson gson = new GsonBuilder()
7677
.setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ")
7778
.create();
79+
7880
Retrofit retrofit = new Retrofit.Builder()
7981
.baseUrl(StackOverflowAPI.BASE_URL)
8082
.addConverterFactory(GsonConverterFactory.create(gson))
8183
.build();
84+
8285
stackoverflowAPI = retrofit.create(StackOverflowAPI.class);
8386
}
8487

85-
public void onClick(View view) {
86-
switch (view.getId()) {
88+
@Override
89+
public void onClick(View v) {
90+
switch (v.getId()) {
91+
case android.R.id.text1:
92+
if (token != null) {
93+
stackoverflowAPI.postUpvoteOnAnswer((Integer) v.getTag(), token, getString(R.string.key), "stackoverflow.com", false, "default").enqueue(upvoteCallback);
94+
} else {
95+
Toast.makeText(this, "You need to authenticate first", Toast.LENGTH_LONG).show();
96+
}
97+
break;
8798
case R.id.authenticate_button:
8899
startActivityForResult(new Intent(this, WebViewActivity.class), 1);
89100
break;
90-
case R.id.upvote_button:
91-
Answer selectedAnswer = (Answer) answersSpinner.getSelectedItem();
92-
if (selectedAnswer != null) {
93-
stackoverflowAPI.postUpvoteOnAnswer(selectedAnswer.getAnswerId(), token, key, "stackoverflow.com", false, "default").enqueue(upvoteCallback);
94-
}
95-
break;
96101
}
97102
}
98103

@@ -103,38 +108,39 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
103108
}
104109
}
105110

106-
Callback<QuestionsList> questionsCallback = new Callback<QuestionsList>() {
111+
Callback<ListWrapper<Question>> questionsCallback = new Callback<ListWrapper<Question>>() {
107112
@Override
108-
public void onResponse(Call<QuestionsList> call, Response<QuestionsList> response) {
113+
public void onResponse(Call<ListWrapper<Question>> call, Response<ListWrapper<Question>> response) {
109114
if (response.isSuccessful()) {
110-
QuestionsList questionList = response.body();
111-
ArrayAdapter<Question> arrayAdapter = new ArrayAdapter<Question>(MainActivity.this, android.R.layout.simple_spinner_dropdown_item, questionList.getItems().toArray(new Question[questionList.getItems().size()]));
115+
ListWrapper<Question> questions = response.body();
116+
ArrayAdapter<Question> arrayAdapter = new ArrayAdapter<Question>(MainActivity.this, android.R.layout.simple_spinner_dropdown_item, questions.items);
112117
questionsSpinner.setAdapter(arrayAdapter);
113118
} else {
114119
Log.d("QuestionsCallback", "Code: " + response.code() + " Message: " + response.message());
115120
}
116121
}
117122

118123
@Override
119-
public void onFailure(Call<QuestionsList> call, Throwable t) {
124+
public void onFailure(Call<ListWrapper<Question>> call, Throwable t) {
120125
t.printStackTrace();
121126
}
122127
};
123128

124-
Callback<AnswersList> answersCallback = new Callback<AnswersList>() {
129+
Callback<ListWrapper<Answer>> answersCallback = new Callback<ListWrapper<Answer>>() {
125130
@Override
126-
public void onResponse(Call<AnswersList> call, Response<AnswersList> response) {
131+
public void onResponse(Call<ListWrapper<Answer>> call, Response<ListWrapper<Answer>> response) {
127132
if (response.isSuccessful()) {
128-
AnswersList answersList = response.body();
129-
ArrayAdapter<Answer> arrayAdapter = new ArrayAdapter<Answer>(MainActivity.this, android.R.layout.simple_spinner_dropdown_item, answersList.getItems().toArray(new Answer[answersList.getItems().size()]));
130-
answersSpinner.setAdapter(arrayAdapter);
133+
List<Object> data = new ArrayList<>();
134+
data.add(questionsSpinner.getSelectedItem());
135+
data.addAll(response.body().items);
136+
recyclerView.setAdapter(new RecyclerViewAdapter(data, MainActivity.this));
131137
} else {
132138
Log.d("QuestionsCallback", "Code: " + response.code() + " Message: " + response.message());
133139
}
134140
}
135141

136142
@Override
137-
public void onFailure(Call<AnswersList> call, Throwable t) {
143+
public void onFailure(Call<ListWrapper<Answer>> call, Throwable t) {
138144
t.printStackTrace();
139145
}
140146
};
@@ -145,6 +151,7 @@ public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response)
145151
if (response.isSuccessful()) {
146152
Toast.makeText(MainActivity.this, "Upvote successful", Toast.LENGTH_LONG).show();
147153
} else {
154+
Log.d("QuestionsCallback", "Code: " + response.code() + " Message: " + response.message());
148155
Toast.makeText(MainActivity.this, "You already upvoted this answer", Toast.LENGTH_LONG).show();
149156
}
150157
}

com.vogella.android.retrofitstackoverflow/app/src/main/java/com/vogella/android/retrofitstackoverflow/Question.java

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,11 @@
44

55
public class Question {
66

7-
private String title;
8-
private String link;
7+
public String title;
8+
public String body;
99

1010
@SerializedName("question_id")
11-
private String questionId;
12-
13-
public String getQuestionId() {
14-
return questionId;
15-
}
16-
17-
public void setQuestionId(String questionId) {
18-
this.questionId = questionId;
19-
}
11+
public String questionId;
2012

2113
@Override
2214
public String toString() {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
package com.vogella.android.retrofitstackoverflow;
2+
3+
import android.support.v7.widget.RecyclerView;
4+
import android.text.Html;
5+
import android.view.LayoutInflater;
6+
import android.view.View;
7+
import android.view.ViewGroup;
8+
import android.widget.TextView;
9+
10+
import java.util.List;
11+
12+
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder> {
13+
private final View.OnClickListener listener;
14+
private List<Object> data;
15+
16+
private static final int VIEW_TYPE_QUESTION = 0;
17+
private static final int VIEW_TYPE_ANSWER = 1;
18+
19+
public class ViewHolder extends RecyclerView.ViewHolder {
20+
public TextView text;
21+
22+
public ViewHolder(View v) {
23+
super(v);
24+
text = (TextView) v.findViewById(android.R.id.text1);
25+
}
26+
}
27+
28+
public RecyclerViewAdapter(List<Object> data, View.OnClickListener onItemClickListener) {
29+
this.data = data;
30+
this.listener = onItemClickListener;
31+
}
32+
33+
@Override
34+
public RecyclerViewAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
35+
View v;
36+
if (viewType == VIEW_TYPE_QUESTION) {
37+
v = LayoutInflater.from(parent.getContext()).inflate(android.R.layout.simple_list_item_1, parent, false);
38+
v.setBackgroundColor(parent.getContext().getResources().getColor(android.R.color.darker_gray));
39+
} else {
40+
v = LayoutInflater.from(parent.getContext()).inflate(android.R.layout.simple_selectable_list_item, parent, false);
41+
v.setOnClickListener(listener);
42+
}
43+
return new ViewHolder(v);
44+
}
45+
46+
@Override
47+
public void onBindViewHolder(RecyclerViewAdapter.ViewHolder holder, int position) {
48+
if (getItemViewType(position) == VIEW_TYPE_QUESTION) {
49+
Question question = ((Question) data.get(position));
50+
holder.text.setText(Html.fromHtml(question.body).toString());
51+
} else {
52+
Answer answer = ((Answer) data.get(position));
53+
holder.text.setText(answer.toString());
54+
holder.itemView.setTag(answer.answerId);
55+
}
56+
}
57+
58+
@Override
59+
public int getItemCount() {
60+
return data.size();
61+
}
62+
63+
@Override
64+
public int getItemViewType(int position) {
65+
if (position == 0) {
66+
return VIEW_TYPE_QUESTION;
67+
} else {
68+
return VIEW_TYPE_ANSWER;
69+
}
70+
}
71+
}

com.vogella.android.retrofitstackoverflow/app/src/main/java/com/vogella/android/retrofitstackoverflow/StackOverflowAPI.java

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,23 @@
11
package com.vogella.android.retrofitstackoverflow;
22

3+
import java.util.List;
4+
35
import okhttp3.ResponseBody;
4-
import retrofit2.Response;
5-
import retrofit2.http.Body;
66
import retrofit2.http.Field;
77
import retrofit2.http.FormUrlEncoded;
88
import retrofit2.http.GET;
9-
import retrofit2.http.Header;
109
import retrofit2.http.POST;
1110
import retrofit2.http.Path;
1211
import retrofit2.Call;
13-
import retrofit2.http.Url;
1412

1513
public interface StackOverflowAPI {
1614
String BASE_URL = "https://api.stackexchange.com";
1715

18-
@GET("/2.2/questions?order=desc&sort=votes&site=stackoverflow&tagged=android")
19-
Call<QuestionsList> getQuestions();
16+
@GET("/2.2/questions?order=desc&sort=votes&site=stackoverflow&tagged=android&filter=withbody")
17+
Call<ListWrapper<Question>> getQuestions();
2018

2119
@GET("/2.2/questions/{id}/answers?order=desc&sort=votes&site=stackoverflow")
22-
Call<AnswersList> getAnswersForQuestion(@Path("id") String questionId);
20+
Call<ListWrapper<Answer>> getAnswersForQuestion(@Path("id") String questionId);
2321

2422
@FormUrlEncoded
2523
@POST("/2.2/answers/{id}/upvote")

com.vogella.android.retrofitstackoverflow/app/src/main/java/com/vogella/android/retrofitstackoverflow/WebViewActivity.java

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,14 @@
99

1010
public class WebViewActivity extends Activity{
1111

12-
private static final String clientId = "yourClientId";
13-
1412
@Override
1513
protected void onCreate(Bundle savedInstanceState) {
1614
super.onCreate(savedInstanceState);
1715

1816
WebView webView = new WebView(this);
1917
webView.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
2018
webView.getSettings().setJavaScriptEnabled(true);
21-
webView.loadUrl("https://stackexchange.com/oauth/dialog?client_id=" + clientId + "&scope=no_expiry,write_access&redirect_uri=https://stackexchange.com/oauth/login_success");
22-
19+
webView.loadUrl("https://stackexchange.com/oauth/dialog?client_id=" + getString(R.string.client_id) + "&scope=no_expiry,write_access&redirect_uri=https://stackexchange.com/oauth/login_success");
2320
webView.setWebViewClient(new WebViewClient(){
2421
@Override
2522
public boolean shouldOverrideUrlLoading(WebView view, String url) {
@@ -35,6 +32,5 @@ public boolean shouldOverrideUrlLoading(WebView view, String url) {
3532
});
3633

3734
setContentView(webView);
38-
3935
}
4036
}

0 commit comments

Comments
 (0)