Skip to content

Commit e0df5ca

Browse files
committed
Made loading of Feed load Asynchronous for the Pipeline Listing screen. First attempt at converting it to a backend service. Some stub code for that. Minor performance imporvement on layout and some color scheme changes.
1 parent d47d6a8 commit e0df5ca

File tree

9 files changed

+282
-85
lines changed

9 files changed

+282
-85
lines changed

.idea/runConfigurations/CITracker.xml

+3-3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

AndroidManifest.xml

+4
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@
1717
<category android:name="android.intent.category.LAUNCHER" />
1818
</intent-filter>
1919
</activity>
20+
<service android:name="com.thoughtworks.studios.driod.citracker.service.LocalService"
21+
android:label="@string/app_name">
22+
23+
</service>
2024
</application>
2125
<uses-sdk android:minSdkVersion="2" />
2226
<uses-permission android:name="android.permission.INTERNET" />

GoFeeds/src/com/thoughtworks/studios/driod/citracker/FeedParserFactory.java

+2-20
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
import com.thoughtworks.studios.driod.citracker.model.Message;
88
import com.thoughtworks.studios.driod.citracker.model.Pipeline;
99

10-
import java.util.ArrayList;
1110
import java.util.Arrays;
1211
import java.util.List;
1312

@@ -27,22 +26,6 @@ private static Pipeline loadSinglePipeline(String pipelineName, String feedUrl,
2726
return new Pipeline(messages, pipelineName, feedUrl);
2827
}
2928

30-
public static List<Pipeline> loadPipelines(Context context) {
31-
String authString = getAuthString(context);
32-
String serverString = getServerString(context);
33-
List<String> pipelineNames = getPipelineString(context);
34-
List<Pipeline> pipelines = new ArrayList<Pipeline>();
35-
for (String name : pipelineNames) {
36-
try {
37-
String serverUrl = String.format(serverString + "/go/api/pipelines/%s/stages.xml", name);
38-
pipelines.add(loadSinglePipeline(name, serverUrl, authString));
39-
} catch (Throwable t) {
40-
Log.e("LOAD FAILED", String.format("Unable to load pipeline %s with auth :%s for url %s", name, authString, serverString), t);
41-
}
42-
}
43-
return pipelines;
44-
}
45-
4629
public static List<Message> loadFeed(String feedUrl, String userAuth) {
4730
FeedParser parser = getParser(feedUrl, userAuth);
4831
long start = System.currentTimeMillis();
@@ -55,18 +38,17 @@ public static List<Message> loadFeed(String feedUrl, String userAuth) {
5538
public static String getAuthString(Context context) {
5639
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
5740
String authString = preferences.getString("username", "") + ":" + preferences.getString("password", "");
58-
Log.i("Using auth", String.format("<<<%s>>>:****", preferences.getString("username", "")));
5941
return authString;
6042
}
6143

6244
public static String getServerString(Context context) {
6345
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
64-
return preferences.getString("serverUrl", "http://go02.thoughtworks.com:8153");
46+
return preferences.getString("serverUrl", "https://cruise01.thoughtworks.com");
6547
}
6648

6749
public static List<String> getPipelineString(Context context) {
6850
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
69-
String pipelineString = preferences.getString("pipeline_names", "cleanArtifacts");
51+
String pipelineString = preferences.getString("pipeline_names", "tlb");
7052
return Arrays.asList(pipelineString.split(","));
7153
}
7254

GoFeeds/src/com/thoughtworks/studios/driod/citracker/activity/PipelineList.java

+135-25
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33
import android.app.AlertDialog;
44
import android.app.Dialog;
55
import android.app.ListActivity;
6-
import android.content.DialogInterface;
7-
import android.content.Intent;
8-
import android.content.SharedPreferences;
6+
import android.content.*;
7+
import android.os.AsyncTask;
98
import android.os.Bundle;
9+
import android.os.IBinder;
1010
import android.preference.PreferenceManager;
1111
import android.util.Log;
1212
import android.view.LayoutInflater;
@@ -16,51 +16,94 @@
1616
import android.widget.EditText;
1717
import android.widget.ListView;
1818
import android.widget.Toast;
19+
import com.thoughtworks.studios.driod.citracker.FeedParser;
1920
import com.thoughtworks.studios.driod.citracker.FeedParserFactory;
2021
import com.thoughtworks.studios.driod.citracker.MainMenuOptions;
2122
import com.thoughtworks.studios.driod.citracker.R;
23+
import com.thoughtworks.studios.driod.citracker.model.Message;
2224
import com.thoughtworks.studios.driod.citracker.model.Pipeline;
25+
import com.thoughtworks.studios.driod.citracker.service.LocalService;
2326
import com.thoughtworks.studios.driod.citracker.view.PipelineListAdapter;
2427

28+
import java.util.ArrayList;
2529
import java.util.List;
2630

2731
/**
2832
* Understands named pipeline and show them with the information from the
2933
* lastest run. Pass/fail
3034
*/
3135
public class PipelineList extends ListActivity {
32-
private List<Pipeline> pipelines;
3336
public static final String SELECTED_PIPELINE_URL_KEY = "com.thoughtworks.studios.driod.citracker.activity.CurrentPipelineName";
37+
private boolean mIsBound;
38+
private PipelineListAdapter pipelineListAdapter;
3439

3540
@Override
3641
public void onCreate(Bundle icicle) {
3742
super.onCreate(icicle);
3843
setContentView(R.layout.main);
39-
reload();
44+
pipelineListAdapter = new PipelineListAdapter(this, R.layout.row);
45+
this.setListAdapter(pipelineListAdapter);
46+
loadPipelines();
47+
pipelineListAdapter.notifyDataSetChanged();
4048
}
4149

42-
@Override
43-
protected void onResume() {
44-
super.onResume();
45-
reload();
46-
}
50+
private void loadPipelines() {
51+
Context applicationContext = getApplicationContext();
52+
List<String> pipelineNames = FeedParserFactory.getPipelineString(applicationContext);
53+
for (String name : pipelineNames) {
54+
new LoadPipelineFeedTask().execute(name);
55+
}
4756

48-
private void reload() {
49-
pipelines = FeedParserFactory.loadPipelines(this);
50-
this.setListAdapter(new PipelineListAdapter(this, R.layout.row, pipelines));
5157
}
5258

53-
@Override
54-
public void onContentChanged() {
55-
super.onContentChanged();
56-
reload();
59+
60+
private class LoadPipelineFeedTask extends AsyncTask<String, String, Pipeline> {
61+
private Pipeline loadSinglePipeline(String pipelineName) {
62+
Context applicationContext = PipelineList.this.getApplicationContext();
63+
String serverString = FeedParserFactory.getServerString(applicationContext);
64+
String serverUrl = String.format(serverString + "/go/api/pipelines/%s/stages.xml", pipelineName);
65+
String authString = FeedParserFactory.getAuthString(applicationContext);
66+
publishProgress("Pipeline List" + "loading feeds" + serverUrl);
67+
FeedParser parser = FeedParserFactory.getParser(serverUrl, authString);
68+
long start = System.currentTimeMillis();
69+
List<Message> messages = new ArrayList<Message>();
70+
try {
71+
messages = parser.parse();
72+
} catch (Throwable t) {
73+
publishProgress(
74+
String.format("Unable to load pipeline %s with auth :%s for url %s",
75+
pipelineName,
76+
authString,
77+
serverUrl));
78+
}
79+
long duration = System.currentTimeMillis() - start;
80+
publishProgress("Go Feeds" + "Parser duration=" + duration);
81+
return new Pipeline(messages, pipelineName, serverUrl);
82+
}
83+
84+
@Override
85+
protected Pipeline doInBackground(String... params) {
86+
return loadSinglePipeline(params[0]);
87+
}
88+
89+
@Override
90+
protected void onProgressUpdate(String... progress) {
91+
Toast.makeText(getApplicationContext(), progress[0], Toast.LENGTH_SHORT).show();
92+
}
93+
94+
@Override
95+
protected void onPostExecute(Pipeline pipeline) {
96+
pipelineListAdapter.add(pipeline);
97+
pipelineListAdapter.notifyDataSetChanged();
98+
}
5799
}
58100

59101
@Override
60102
public boolean onCreateOptionsMenu(Menu menu) {
61103
super.onCreateOptionsMenu(menu);
62104
menu.add(Menu.NONE, MainMenuOptions.ADD_PIPELINE.ordinal(), MainMenuOptions.ADD_PIPELINE.ordinal(), R.string.add_pipeline);
63105
menu.add(Menu.NONE, MainMenuOptions.PREFERENCES.ordinal(), MainMenuOptions.PREFERENCES.ordinal(), R.string.preferences);
106+
menu.add(Menu.NONE, MainMenuOptions.ADD_GO_URL.ordinal(), MainMenuOptions.ADD_GO_URL.ordinal(), R.string.add_go_url);
64107
return true;
65108
}
66109

@@ -75,18 +118,23 @@ protected Dialog onCreateDialog(int id) {
75118
.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
76119
public void onClick(DialogInterface dialog, int whichButton) {
77120
EditText editView = (EditText) textEntryView.findViewById(R.id.pipelinename_edit);
78-
String newPipelineName = editView.getText().toString().trim();
79-
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
80-
String existingPipelines = preferences.getString("pipeline_names", "");
81-
SharedPreferences.Editor editor = preferences.edit();
82-
editor.putString("pipeline_names", existingPipelines + "," + newPipelineName);
83-
editor.commit();
84-
reload();
121+
String userInput = editView.getText().toString();
122+
String newPipelineName = userInput.trim();
123+
updatePipelinesPreferences(newPipelineName);
85124
Toast.makeText(PipelineList.this.getApplicationContext(), String.format("Pipeline %s added.", newPipelineName), Toast.LENGTH_LONG).show();
125+
new LoadPipelineFeedTask().execute(newPipelineName);
86126
}
87127
}).create();
88128
}
89129

130+
private void updatePipelinesPreferences(String newPipelineName) {
131+
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
132+
String existingPipelines = preferences.getString("pipeline_names", "");
133+
SharedPreferences.Editor editor = preferences.edit();
134+
editor.putString("pipeline_names", existingPipelines + "," + newPipelineName);
135+
editor.commit();
136+
}
137+
90138
@Override
91139
public boolean onMenuItemSelected(int featureId, MenuItem item) {
92140
super.onMenuItemSelected(featureId, item);
@@ -100,16 +148,78 @@ public boolean onMenuItemSelected(int featureId, MenuItem item) {
100148
if (option == MainMenuOptions.ADD_PIPELINE) {
101149
showDialog(1);
102150
}
151+
if (option == MainMenuOptions.ADD_GO_URL) {
152+
createService();
153+
}
103154
return false;
104155
}
105156

157+
private LocalService mBoundService;
158+
159+
private void createService() {
160+
doBindService();
161+
}
162+
163+
private ServiceConnection mConnection = new ServiceConnection() {
164+
public void onServiceConnected(ComponentName className, IBinder service) {
165+
// This is called when the connection with the service has been
166+
// established, giving us the service object we can use to
167+
// interact with the service. Because we have bound to a explicit
168+
// service that we know is running in our own process, we can
169+
// cast its IBinder to a concrete class and directly access it.
170+
mBoundService = ((LocalService.LocalBinder) service).getService();
171+
172+
// Tell the user about this for our demo.
173+
Toast.makeText(PipelineList.this, R.string.choose_pipeline,
174+
Toast.LENGTH_SHORT).show();
175+
}
176+
177+
public void onServiceDisconnected(ComponentName className) {
178+
// This is called when the connection with the service has been
179+
// unexpectedly disconnected -- that is, its process crashed.
180+
// Because it is running in our same process, we should never
181+
// see this happen.
182+
mBoundService = null;
183+
Toast.makeText(PipelineList.this, R.string.add_go_url,
184+
Toast.LENGTH_SHORT).show();
185+
}
186+
};
187+
188+
106189
@Override
107190
protected void onListItemClick(ListView l, View v, int position, long id) {
108191
super.onListItemClick(l, v, position, id);
109192
Intent myIntent = new Intent();
110193
myIntent.setClass(getApplicationContext(), MessageList.class);
111-
myIntent.putExtra(SELECTED_PIPELINE_URL_KEY, pipelines.get(position).getPipelineFeedUrl());
194+
Object itemIdAtPosition = l.getItemAtPosition(position);
195+
myIntent.putExtra(SELECTED_PIPELINE_URL_KEY, ((Pipeline) itemIdAtPosition).getPipelineFeedUrl());
112196
startActivity(myIntent);
113197
}
114198

199+
200+
void doBindService() {
201+
// Establish a connection with the service. We use an explicit
202+
// class name because we want a specific service implementation that
203+
// we know will be running in our own process (and thus won't be
204+
// supporting component replacement by other applications).
205+
bindService(new Intent(PipelineList.this,
206+
LocalService.class), mConnection, Context.BIND_AUTO_CREATE);
207+
mIsBound = true;
208+
}
209+
210+
void doUnbindService() {
211+
if (mIsBound) {
212+
// Detach our existing connection.
213+
unbindService(mConnection);
214+
mIsBound = false;
215+
}
216+
}
217+
218+
@Override
219+
protected void onDestroy() {
220+
super.onDestroy();
221+
doUnbindService();
222+
}
223+
224+
115225
}

0 commit comments

Comments
 (0)