android-jamendo源码学习(二)——HomeActivity

精彩继续~~~上一次分析SplashscreenActivity后知道程序跳转到HomeActivity~~下面就详细的分析HomeActivity(从名字大家也看得出来这是这个程序的主页面~程序没有国界啊~大家都喜欢用Home..来做程序的主页面的名字~~o(∩∩)o...)

还是首先看下今天要介绍的Activity的运行图:

 

(一)首先我们先根据布局文件来分析下整个页面的布局:布局文件main.xml

 1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 2     android:orientation="vertical" android:layout_width="fill_parent"
 3     android:layout_height="fill_parent" android:background="#ffffff">
 4 
 5     <com.teleca.jamendo.util.FixedViewFlipper
 6         android:orientation="vertical" android:id="@+id/ViewFlipper"
 7         android:layout_width="fill_parent" android:layout_height="75dip"
 8         android:background="@drawable/gradient_dark_purple">
 9 
10         <!-- (0) Loading -->
11         <LinearLayout android:orientation="vertical"
12             android:layout_width="fill_parent" android:layout_height="fill_parent"
13             android:layout_marginLeft="15dip" android:gravity="left|center_vertical">
14             <com.teleca.jamendo.widget.ProgressBar
15                 android:id="@+id/ProgressBar" android:layout_width="wrap_content"
16                 android:layout_height="wrap_content">
17             </com.teleca.jamendo.widget.ProgressBar>
18         </LinearLayout>
19 
20         <!-- (1) Gallery -->
21         <LinearLayout android:orientation="vertical"
22             android:layout_width="fill_parent" android:layout_height="fill_parent"
23             android:gravity="center">
24             <Gallery android:id="@+id/Gallery" android:layout_width="fill_parent"
25                 android:layout_height="wrap_content" android:spacing="0px" />
26         </LinearLayout>
27 
28         <!-- (2) Failure -->
29         <LinearLayout android:orientation="vertical"
30             android:layout_width="fill_parent" android:layout_height="fill_parent"
31             android:layout_marginLeft="15dip" android:gravity="left|center_vertical">
32             <com.teleca.jamendo.widget.FailureBar
33                 android:id="@+id/FailureBar" android:layout_width="wrap_content"
34                 android:layout_height="wrap_content">
35             </com.teleca.jamendo.widget.FailureBar>
36         </LinearLayout>
37     </com.teleca.jamendo.util.FixedViewFlipper>
38 
39     <android.gesture.GestureOverlayView
40         xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/gestures"
41         android:layout_width="fill_parent" android:layout_height="fill_parent"
42 
43         android:gestureStrokeType="multiple"
44         android:eventsInterceptionEnabled="false" android:orientation="vertical">
45 
46         <ListView android:id="@+id/HomeListView"
47             android:layout_width="fill_parent" android:layout_height="fill_parent"
48             android:divider="#000" />
49     </android.gesture.GestureOverlayView>
50 
51 </LinearLayout>
 
 从布局文件和运行图我们可以看出页面是在主LinearLayout布局内嵌套了com.teleca.jamendo.util.FixedViewFlipper(页面头部用于展示图片部分) android.gesture.GestureOverlayView(手势视图)两个布局,采用垂直显示。下面分别来分析两个布局
1.    com.teleca.jamendo.util.FixedViewFlipper:
 1 public class FixedViewFlipper extends ViewFlipper {
 2 
 3     public FixedViewFlipper(Context context) {
 4         super(context);
 5     }
 6 
 7     public FixedViewFlipper(Context context, AttributeSet attrs) {
 8         super(context, attrs);
 9     }
10 
11     @Override
12     protected void onDetachedFromWindow() {
13 
14         int apiLevel = Build.VERSION.SDK_INT;
15 
16         if (apiLevel >= 7) {
17             try {
18                 super.onDetachedFromWindow();
19             } catch (IllegalArgumentException e) {
20                 Log.w("Jamendo", "Android project  issue 6191  workaround.");
21                 /* Quick catch and continue on api level 7, the Eclair 2.1 */
22             } finally {
23                 super.stopFlipping();
24             }
25         } else {
26             super.onDetachedFromWindow();
27         }
28     }
29 }
 
从上面源码可以看出自定义控件FixedViewFlipper继承了ViewFilpper,有关ViewFilpper官方文档给出了解释:Simple ViewAnimator that will animate between two or more views that have been added to it. Only one child is shown at a time. If requested, can automatically flip between each child at a regular interval.(简单的ViewAnimator用在切换加载到其中的的两个或更多的View,但是每次只能显示一个。如果需要,也可以在特定时间间隔自动切换。------翻译的不好。。。大家原谅。。。。)有关ViewFilpper的详细内容参看官方ViewFlipper文档。
FixedViewFlipper没有什么特别的地方只是重写了onDetachedFromWindow方法,该方法实在View销毁的时候调用。方法内对sdk版本进行了判断::在此我查阅了一些资料个人认为 if (apiLevel >= 7)这里应该是
if (apiLevel == 7) 关于为什么加这个判断大家可以参看我转载的一片博文[转载]onAttachedToWindow () 和 onDetachedFromWindow ()

在FixedViewFlipper中分别包含了 Loading ,Gallery,Failure三个View。其中Loading 是用来显示加载中页面,Gallery是显示加载完成后正常显示的图片,Failure是显示因为网络或其他原因引起的加载失败的界面。下面分别是在三种情况的运行图片:

其中Loading ,Failure使用了自定义布局com.teleca.jamendo.widget.ProgressBar和com.teleca.jamendo.widget.FailureBar都是相对很简单的自定义布局下面给出源码 大家可以简单看一下
ProgressBar
 1 /*
 2  * Copyright (C) 2009 Teleca Poland Sp. z o.o. <android@teleca.com>
 3  *
 4  * Licensed under the Apache License, Version 2.0 (the "License");
 5  * you may not use this file except in compliance with the License.
 6  * You may obtain a copy of the License at
 7  *
 8  *      http://www.apache.org/licenses/LICENSE-2.0
 9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.teleca.jamendo.widget;
18 
19 import com.teleca.jamendo.R;
20 
21 import android.content.Context;
22 import android.util.AttributeSet;
23 import android.view.LayoutInflater;
24 import android.widget.LinearLayout;
25 import android.widget.TextView;
26 
27 /**
28  * Widget notifying user of ongoing action 
29  * 
30  * @author Lukasz Wisniewski
31  */
32 public class ProgressBar extends LinearLayout {
33     
34     protected TextView mTextView;
35     
36     public ProgressBar(Context context, AttributeSet attrs) {
37         super(context, attrs);
38         init();
39     }
40 
41     public ProgressBar(Context context) {
42         super(context);
43         init();
44     }
45     
46     /**
47      * Sharable code between constructors
48      */
49     private void init(){
50         LayoutInflater.from(getContext()).inflate(R.layout.progress_bar, this);
51         
52         mTextView = (TextView)findViewById(R.id.ProgressTextView);
53     }
54     
55     /**
56      * Sets informative text
57      * 
58      * @param resid
59      */
60     public void setText(int resid){
61         mTextView.setText(resid);
62     }
63 
64 }

 

FailureBar
 1 /*
 2  * Copyright (C) 2009 Teleca Poland Sp. z o.o. <android@teleca.com>
 3  *
 4  * Licensed under the Apache License, Version 2.0 (the "License");
 5  * you may not use this file except in compliance with the License.
 6  * You may obtain a copy of the License at
 7  *
 8  *      http://www.apache.org/licenses/LICENSE-2.0
 9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.teleca.jamendo.widget;
18 
19 import com.teleca.jamendo.R;
20 
21 import android.content.Context;
22 import android.util.AttributeSet;
23 import android.view.LayoutInflater;
24 import android.widget.Button;
25 import android.widget.LinearLayout;
26 import android.widget.TextView;
27 
28 /**
29  * Top bar widget notifying user of failure, with possibillity of retry 
30  * 
31  * 
32  * @author Lukasz Wisniewski
33  */
34 public class FailureBar extends LinearLayout{
35     
36     protected TextView mTextView;
37     protected Button mRetryButton;
38     
39     public FailureBar(Context context, AttributeSet attrs) {
40         super(context, attrs);
41         init();
42     }
43 
44     public FailureBar(Context context) {
45         super(context);
46         init();
47     }
48     
49     /**
50      * Sharable code between constructors
51      */
52     private void init(){
53         LayoutInflater.from(getContext()).inflate(R.layout.failure_bar, this);
54         
55         mTextView = (TextView)findViewById(R.id.ProgressTextView);
56         mRetryButton = (Button)findViewById(R.id.RetryButton);
57     }
58     
59     /**
60      * Sets informative text
61      * 
62      * @param resid
63      */
64     public void setText(int resid){
65         mTextView.setText(resid);
66     }
67     
68     /**
69      * Sets action to be performed when Retry button is clicked 
70      * 
71      * @param l
72      */
73     public void setOnRetryListener(OnClickListener l){
74         mRetryButton.setOnClickListener(l);
75     }
76 
77 }

 

2. android.gesture.GestureOverlayView
这部分是用一个手势视图内嵌套了ListView用与现实页面的主体部分。有关GestureOverlayView官方给出了简单的解释:A transparent overlay for gesture input that can be placed on top of other widgets or contain other widgets.(一个透明的叠加的手势输入,可以放在顶部的其他小部件或包含其他小部件。) 官方文档GestureOverlayView
到这里我们了解了这个界面的布局,主要就上面所说的两部分,布局简单明了~~~下面通过HomeActivity的分析来看看是如何实现页面的

HomeActivity

首先给出源码方便大家学习
HomeActivity
  1 /*
  2  * Copyright (C) 2009 Teleca Poland Sp. z o.o. <android@teleca.com>
  3  *
  4  * Licensed under the Apache License, Version 2.0 (the "License");
  5  * you may not use this file except in compliance with the License.
  6  * You may obtain a copy of the License at
  7  *
  8  *      http://www.apache.org/licenses/LICENSE-2.0
  9  *
 10  * Unless required by applicable law or agreed to in writing, software
 11  * distributed under the License is distributed on an "AS IS" BASIS,
 12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  * See the License for the specific language governing permissions and
 14  * limitations under the License.
 15  */
 16 
 17 package com.teleca.jamendo.activity;
 18 
 19 import java.util.ArrayList;
 20 import java.util.Hashtable;
 21 
 22 import org.json.JSONException;
 23 
 24 import com.teleca.jamendo.JamendoApplication;
 25 import com.teleca.jamendo.activity.BrowsePlaylistActivity.Mode;
 26 import com.teleca.jamendo.adapter.ImageAdapter;
 27 import com.teleca.jamendo.adapter.PurpleAdapter;
 28 import com.teleca.jamendo.adapter.PurpleEntry;
 29 import com.teleca.jamendo.adapter.PurpleListener;
 30 import com.teleca.jamendo.adapter.SeparatedListAdapter;
 31 import com.teleca.jamendo.api.Album;
 32 import com.teleca.jamendo.api.JamendoGet2Api;
 33 import com.teleca.jamendo.api.Playlist;
 34 import com.teleca.jamendo.api.PlaylistEntry;
 35 import com.teleca.jamendo.api.Track;
 36 import com.teleca.jamendo.api.WSError;
 37 import com.teleca.jamendo.api.impl.JamendoGet2ApiImpl;
 38 import com.teleca.jamendo.dialog.AboutDialog;
 39 import com.teleca.jamendo.dialog.LoadingDialog;
 40 import com.teleca.jamendo.widget.FailureBar;
 41 import com.teleca.jamendo.widget.OnAlbumClickListener;
 42 import com.teleca.jamendo.widget.ProgressBar;
 43 import com.teleca.jamendo.R;
 44 
 45 import android.app.Activity;
 46 import android.gesture.GestureOverlayView;
 47 import android.content.Context;
 48 import android.content.Intent;
 49 import android.os.AsyncTask;
 50 import android.os.Bundle;
 51 import android.os.Environment;
 52 import android.preference.PreferenceManager;
 53 import android.util.Log;
 54 import android.view.KeyEvent;
 55 import android.view.Menu;
 56 import android.view.MenuInflater;
 57 import android.view.MenuItem;
 58 import android.view.View;
 59 import android.view.Window;
 60 import android.view.View.OnClickListener;
 61 import android.widget.AdapterView;
 62 import android.widget.Gallery;
 63 import android.widget.ListView;
 64 import android.widget.Toast;
 65 import android.widget.ViewFlipper;
 66 import android.widget.AdapterView.OnItemClickListener;
 67 
 68 /**
 69  * Home activity of the jamendo, central navigation place
 70  * 
 71  * @author Lukasz Wisniewski
 72  * @author Marcin Gil
 73  */
 74 public class HomeActivity extends Activity implements OnAlbumClickListener {
 75 
 76     private static final String TAG = "HomeActivity";
 77 
 78     private ViewFlipper mViewFlipper;
 79     private Gallery mGallery;
 80     private ProgressBar mProgressBar;
 81     private FailureBar mFailureBar;
 82     private ListView mHomeListView;
 83     private PurpleAdapter mBrowseJamendoPurpleAdapter;
 84     private PurpleAdapter mMyLibraryPurpleAdapter;
 85     private GestureOverlayView mGestureOverlayView;
 86 
 87     /**
 88      * Launch Home activity helper
 89      * 
 90      * @param c context where launch home from (used by SplashscreenActivity)
 91      */
 92     public static void launch(Context c){
 93         Intent intent = new Intent(c, HomeActivity.class);
 94         intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP );
 95         c.startActivity(intent);
 96     }
 97     
 98     /** Called when the activity is first created. */
 99     @Override
100     public void onCreate(Bundle savedInstanceState) {
101         super.onCreate(savedInstanceState);
102         requestWindowFeature(Window.FEATURE_NO_TITLE);
103         setContentView(R.layout.main);
104 
105         mHomeListView = (ListView)findViewById(R.id.HomeListView);
106         mGallery = (Gallery)findViewById(R.id.Gallery);
107         mProgressBar = (ProgressBar)findViewById(R.id.ProgressBar);
108         mFailureBar = (FailureBar)findViewById(R.id.FailureBar);
109         mViewFlipper = (ViewFlipper)findViewById(R.id.ViewFlipper);
110 
111         mGestureOverlayView = (GestureOverlayView) findViewById(R.id.gestures);
112         mGestureOverlayView.addOnGesturePerformedListener(JamendoApplication
113                 .getInstance().getPlayerGestureHandler());
114 
115         new NewsTask().execute((Void)null);
116     }
117 
118     @Override
119     protected void onRestoreInstanceState(Bundle savedInstanceState) {
120         // commented out, was causing "Wrong state class -- expecting View State" on view rotation
121         // super.onRestoreInstanceState(savedInstanceState);
122     }
123 
124     @Override
125     public void onAlbumClicked(Album album) {
126         PlayerActivity.launch(this, album);
127     }
128 
129     @Override
130     public boolean onCreateOptionsMenu(Menu menu) {
131         MenuInflater inflater = getMenuInflater();
132         inflater.inflate(R.menu.home, menu);
133         return super.onCreateOptionsMenu(menu);
134     }
135     
136     @Override
137     public boolean onPrepareOptionsMenu(Menu menu) {
138         if(JamendoApplication.getInstance().getPlayerEngineInterface() == null || JamendoApplication.getInstance().getPlayerEngineInterface().getPlaylist() == null){
139             menu.findItem(R.id.player_menu_item).setVisible(false);
140         } else {
141             menu.findItem(R.id.player_menu_item).setVisible(true);
142         }
143         return super.onPrepareOptionsMenu(menu);
144     }
145 
146     @Override
147     public boolean onOptionsItemSelected(MenuItem item) {
148         switch(item.getItemId()){
149 
150         case R.id.player_menu_item:
151             PlayerActivity.launch(this, (Playlist)null);
152             break;
153 
154         case R.id.about_menu_item:
155             new AboutDialog(this).show();
156             break;
157 
158         case R.id.settings_menu_item:
159             SettingsActivity.launch(this);
160             break;
161 
162         default:
163 
164         }
165         return super.onOptionsItemSelected(item);
166     }
167 
168     @Override
169     public boolean onKeyDown(int keyCode, KeyEvent event) {
170         // support for search key
171         // TODO remove hardcoded '1' value
172         if(keyCode == KeyEvent.KEYCODE_SEARCH){
173             mHomeListView.setSelection(1);
174             PurpleEntry entry = (PurpleEntry) mHomeListView.getAdapter().getItem(1);
175             entry.getListener().performAction();
176         }
177         return super.onKeyDown(keyCode, event);
178     }
179 
180     @Override
181     protected void onPause() {
182         super.onPause();
183     }
184 
185     @Override
186     protected void onResume() {
187         fillHomeListView();
188         boolean gesturesEnabled = PreferenceManager.getDefaultSharedPreferences(this).getBoolean("gestures", true);
189         mGestureOverlayView.setEnabled(gesturesEnabled);
190         super.onResume();
191     }
192     
193     /**
194      * Fills ListView with clickable menu items
195      */
196     private void fillHomeListView(){
197         mBrowseJamendoPurpleAdapter = new PurpleAdapter(this);
198         mMyLibraryPurpleAdapter = new PurpleAdapter(this);
199         ArrayList<PurpleEntry> browseListEntry = new ArrayList<PurpleEntry>();
200         ArrayList<PurpleEntry> libraryListEntry = new ArrayList<PurpleEntry>();
201         
202         // BROWSE JAMENDO
203         
204         browseListEntry.add(new PurpleEntry(R.drawable.list_search, R.string.search, new PurpleListener(){
205             @Override
206             public void performAction() {
207                 SearchActivity.launch(HomeActivity.this);
208             }
209         }));
210 
211         browseListEntry.add(new PurpleEntry(R.drawable.list_radio, R.string.radio, new PurpleListener(){
212             @Override
213             public void performAction() {
214                 RadioActivity.launch(HomeActivity.this);
215             }
216         }));
217         
218         browseListEntry.add(new PurpleEntry(R.drawable.list_top, R.string.most_listened, new PurpleListener(){
219             @Override
220             public void performAction() {
221                 new Top100Task(HomeActivity.this, R.string.loading_top100, R.string.top100_fail).execute();
222             }
223         }));
224         
225         // MY LIBRARY
226         
227         libraryListEntry.add(new PurpleEntry(R.drawable.list_playlist, R.string.playlists, new PurpleListener(){
228             @Override
229             public void performAction() {
230                 BrowsePlaylistActivity.launch(HomeActivity.this, Mode.Normal);
231             }
232         }));
233         
234         // check if we have personalized client then add starred albums
235         final String userName = PreferenceManager.getDefaultSharedPreferences(this).getString("user_name", null);
236         if(userName != null && userName.length() > 0){
237             libraryListEntry.add(new PurpleEntry(R.drawable.list_cd, R.string.albums, new PurpleListener(){
238                 @Override
239                 public void performAction() {
240                     StarredAlbumsActivity.launch(HomeActivity.this, userName);
241                 }
242             }));
243         }
244         
245         /* following needs jamendo authorization (not documented yet on the wiki)
246          * listEntry.add(new PurpleEntry(R.drawable.list_mail, "Inbox")); 
247          */
248 
249         // show this list item only if the SD Card is present
250         if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
251             libraryListEntry.add(new PurpleEntry(R.drawable.list_download, R.string.download, new PurpleListener(){
252                 @Override
253                 public void performAction() {
254                     DownloadActivity.launch(HomeActivity.this);
255                 }
256             }));
257         }
258         
259 //        listEntry.add(new PurpleEntry(R.drawable.list_star, R.string.favorites, new PurpleListener(){
260 //
261 //            @Override
262 //            public void performAction() {
263 //                Playlist playlist = new DatabaseImpl(HomeActivity.this).getFavorites();
264 //                JamendroidApplication.getInstance().getPlayerEngine().openPlaylist(playlist);
265 //                PlaylistActivity.launch(HomeActivity.this, true);
266 //            }
267 //
268 //        }));
269         
270         // attach list data to adapters
271         mBrowseJamendoPurpleAdapter.setList(browseListEntry);
272         mMyLibraryPurpleAdapter.setList(libraryListEntry);
273         
274         // separate adapters on one list
275         SeparatedListAdapter separatedAdapter = new SeparatedListAdapter(this);
276         separatedAdapter.addSection(getString(R.string.browse_jamendo), mBrowseJamendoPurpleAdapter);
277         separatedAdapter.addSection(getString(R.string.my_library), mMyLibraryPurpleAdapter);
278         
279         mHomeListView.setAdapter(separatedAdapter);
280         mHomeListView.setOnItemClickListener(mHomeItemClickListener);
281     }
282 
283     /**
284      * Launches menu actions
285      */
286     private OnItemClickListener mHomeItemClickListener = new OnItemClickListener(){
287 
288         @Override
289         public void onItemClick(AdapterView<?> adapterView, View view, int index,
290                 long time) {
291             try{
292                 PurpleListener listener = ((PurpleEntry)adapterView.getAdapter().getItem(index)).getListener();
293                 if(listener != null){
294                     listener.performAction();
295                 }
296             }catch (ClassCastException e) {
297                 Log.w(TAG, "Unexpected position number was occurred");
298             }
299         }
300     };
301 
302     /**
303      * Executes news download, JamendoGet2Api.getPopularAlbumsWeek
304      * 
305      * @author Lukasz Wisniewski
306      */
307     private class NewsTask extends AsyncTask<Void, WSError, Album[]> {
308 
309         @Override
310         public void onPreExecute() {
311             mViewFlipper.setDisplayedChild(0);
312             mProgressBar.setText(R.string.loading_news);
313             super.onPreExecute();
314         }
315 
316         @Override
317         public Album[] doInBackground(Void... params) {
318             JamendoGet2Api server = new JamendoGet2ApiImpl();
319             Album[] albums = null;
320             try {
321                 albums = server.getPopularAlbumsWeek();
322             } catch (JSONException e) {
323                 e.printStackTrace();
324             } catch (WSError e){
325                 publishProgress(e);
326             }
327             return albums;
328         }
329 
330         @Override
331         public void onPostExecute(Album[] albums) {
332 
333             if(albums != null && albums.length > 0){
334                 mViewFlipper.setDisplayedChild(1);
335                 ImageAdapter albumsAdapter = new ImageAdapter(HomeActivity.this);
336                 albumsAdapter.setList(albums);
337                 mGallery.setAdapter(albumsAdapter);
338                 mGallery.setOnItemClickListener(mGalleryListener);
339                 mGallery.setSelection(albums.length/2, true); // animate to center
340 
341             } else {
342                 mViewFlipper.setDisplayedChild(2);
343                 mFailureBar.setOnRetryListener(new OnClickListener(){
344 
345                     @Override
346                     public void onClick(View v) {
347                         new NewsTask().execute((Void)null);
348                     }
349 
350                 });
351                 mFailureBar.setText(R.string.connection_fail);
352             }
353             super.onPostExecute(albums);
354         }
355 
356         @Override
357         protected void onProgressUpdate(WSError... values) {
358             Toast.makeText(HomeActivity.this, values[0].getMessage(), Toast.LENGTH_LONG).show();
359             super.onProgressUpdate(values);
360         }
361         
362         
363 
364     }
365 
366     /**
367      * Background task fetching top 100 tracks from the remote server
368      * It's sort of ugly circumvention of Get2 API limitations<br>
369      * 1 rss + 2 json requests 
370      *  
371      * @author Lukasz Wisniewski
372      */
373     private class Top100Task extends LoadingDialog<Void, Playlist>{
374 
375         public Top100Task(Activity activity, int loadingMsg, int failMsg) {
376             super(activity, loadingMsg, failMsg);
377         }
378 
379         @Override
380         public Playlist doInBackground(Void... params) {
381             JamendoGet2Api server = new JamendoGet2ApiImpl();
382             int[] id = null;
383             try {
384                 id = server.getTop100Listened();
385                 // if loading rss failed and no tracks are there - report an error
386                 if (id == null) {
387                     publishProgress(new WSError((String) getResources().getText(R.string.top100_fail)));
388                     return null;
389                 }
390                 Album[] albums = server.getAlbumsByTracksId(id);
391                 Track[] tracks = server.getTracksByTracksId(id, JamendoApplication.getInstance().getStreamEncoding());
392                 if(albums == null || tracks == null)
393                     return null;
394                 Hashtable<Integer, PlaylistEntry> hashtable = new Hashtable<Integer, PlaylistEntry>(); 
395                 for(int i = 0; i < tracks.length; i++){
396                     PlaylistEntry playlistEntry = new PlaylistEntry();
397                     playlistEntry.setAlbum(albums[i]);
398                     playlistEntry.setTrack(tracks[i]);
399                     hashtable.put(tracks[i].getId(), playlistEntry);
400                 }
401 
402                 // creating playlist in the correct order
403                 Playlist playlist = new Playlist();
404                 for(int i =0; i < id.length; i++){
405                     playlist.addPlaylistEntry(hashtable.get(id[i]));
406                 }
407                 return playlist;
408             } catch (JSONException e) {
409                 e.printStackTrace();
410             } catch (WSError e) {
411                 publishProgress(e);
412             }
413             return null;
414         }
415 
416         @Override
417         public void doStuffWithResult(Playlist playlist) {
418             if(playlist.size() <= 0){
419                 failMsg();
420                 return;
421             }
422             
423             PlayerActivity.launch(HomeActivity.this, playlist);
424         }
425 
426     }
427     
428     private OnItemClickListener mGalleryListener = new OnItemClickListener(){
429 
430         @Override
431         public void onItemClick(AdapterView<?> adapterView, View view, int position,
432                 long id) {
433             Album album = (Album) adapterView.getItemAtPosition(position);
434             PlayerActivity.launch(HomeActivity.this, album);
435         }
436         
437     };
438 
439 }

 

首先我们看到OnAlbumClickListener接口,经过调试研究发现这个接口在这里没有用(个人认为),可能是开始用到了 后期优化后忘了删除了,主要用于监听Alum点击事件,现在程序里这个事件实在mGalleryListener中实现的,对于这个接口我们先忽略掉。

    一、首先还是看onCreate方法:

 1 public void onCreate(Bundle savedInstanceState) {
 2         super.onCreate(savedInstanceState);
 3         requestWindowFeature(Window.FEATURE_NO_TITLE);
 4         setContentView(R.layout.main);
 5 
 6         mHomeListView = (ListView)findViewById(R.id.HomeListView);
 7         mGallery = (Gallery)findViewById(R.id.Gallery);
 8         mProgressBar = (ProgressBar)findViewById(R.id.ProgressBar);
 9         mFailureBar = (FailureBar)findViewById(R.id.FailureBar);
10         mViewFlipper = (ViewFlipper)findViewById(R.id.ViewFlipper);
11 
12         mGestureOverlayView = (GestureOverlayView) findViewById(R.id.gestures);
13         mGestureOverlayView.addOnGesturePerformedListener(JamendoApplication
14                 .getInstance().getPlayerGestureHandler());
15 
16         new NewsTask().execute((Void)null);
17     }

 

方法很简洁,主要实现了页面的手势监听mGestureOverlayView和通过执行NewTask 来异步加载album列表,获取成功后填充Gallery显示在页面最上面。
关于jamendo的手势部分在这里先不介绍,大家就知道此处是为了能监听到手势并执行相应手势,有关手势的具体内容稍后会在写一篇专门的博客来介绍。
下面主要介绍NewsTask(),这是一个内部类继承了抽象类AsyncTask:
 1 /**
 2      * Executes news download, JamendoGet2Api.getPopularAlbumsWeek
 3      * 
 4      * @author Lukasz Wisniewski
 5      */
 6     private class NewsTask extends AsyncTask<Void, WSError, Album[]> {
 7 
 8         @Override
 9         public void onPreExecute() {
10             mViewFlipper.setDisplayedChild(0);
11             mProgressBar.setText(R.string.loading_news);
12             super.onPreExecute();
13         }
14 
15         @Override
16         public Album[] doInBackground(Void... params) {
17             JamendoGet2Api server = new JamendoGet2ApiImpl();
18             Album[] albums = null;
19             try {
20                 albums = server.getPopularAlbumsWeek();
21             } catch (JSONException e) {
22                 e.printStackTrace();
23             } catch (WSError e){
24                 publishProgress(e);
25             }
26             return albums;
27         }
28 
29         @Override
30         public void onPostExecute(Album[] albums) {
31 
32             if(albums != null && albums.length > 0){
33                 mViewFlipper.setDisplayedChild(1);
34                 ImageAdapter albumsAdapter = new ImageAdapter(HomeActivity.this);
35                 albumsAdapter.setList(albums);
36                 mGallery.setAdapter(albumsAdapter);
37                 mGallery.setOnItemClickListener(mGalleryListener);
38                 mGallery.setSelection(albums.length/2, true); // animate to center
39 
40             } else {
41                 mViewFlipper.setDisplayedChild(2);
42                 mFailureBar.setOnRetryListener(new OnClickListener(){
43 
44                     @Override
45                     public void onClick(View v) {
46                         new NewsTask().execute((Void)null);
47                     }
48 
49                 });
50                 mFailureBar.setText(R.string.connection_fail);
51             }
52             super.onPostExecute(albums);
53         }
54 
55         @Override
56         protected void onProgressUpdate(WSError... values) {
57             Toast.makeText(HomeActivity.this, values[0].getMessage(), Toast.LENGTH_LONG).show();
58             super.onProgressUpdate(values);
59         }
60         
61         
62 
63     }

 

AsyncTask是官方提供的一步类简化了我们之前使用的Thread 和handlers来异步和在子线程中更细UI,官方文档给出了详细的介绍和例子,不熟悉的童靴们可以先看下官方文档AsyncTask;
AsyncTask 的四步 onPreExecute()doInBackground(Params...),onProgressUpdate(Progress...),;onPostExecute(Result)
1. 在onPreExecute方法中设置mViewFlipper显示第一个view即上面介绍的FixedViewFlipper内的Loading,设置ProgressBar的Text显示文字;
2. public Album[] doInBackground(Void... params)方法中通过封装好的方法从服务器端获取流行的专辑列表,并通过publishProgress(e)和onProgressUpdate将捕获的异常信息在UI线程中显示即更新UI。
   有关JamendoGet2Api的具体实现这里先不介绍,稍后会有专门的博客来介绍,在这里我们只需知道是用来从服务器获取数据就可以了。
3. public void onPostExecute(Album[] albums) 比较重要的一个方法。该方法作用是在UI线程中调动通过doInBackground异步的到的数据(Album[] album)并显示在页面上。
首先通过判断album是否取到了数据,若取到数据则设置mViewFlipper显示第二个view--Gallery来显示album中的数据,若是没有取到数据则显示mViewFlipper显示第三个个view--Failure即加载失败页面。
 3.1 首先看album获取到数据的情况,代码很清晰 首先是设置mViewFlipper显示Gallery,实例化ImageAdapter albumsAdapter并将album列表传递进去,然后gallery设置适配器为albumsAdapter并设置gallery的item点击事件,最后设置gallery选中album中间的item。
ImageAdapter
 1 public class ImageAdapter extends AlbumAdapter {
 2     
 3     int mIconSize;
 4     
 5 
 6     public ImageAdapter(Activity context) {
 7         super(context);
 8         mIconSize = (int)context.getResources().getDimension(R.dimen.icon_size); 
 9     }
10 
11     @Override
12     public View getView(int position, View convertView, ViewGroup parent) {
13         RemoteImageView i;
14 
15         if (convertView == null) {
16             i = new RemoteImageView(mContext);
17             i.setScaleType(RemoteImageView.ScaleType.FIT_CENTER);
18             i.setLayoutParams(new Gallery.LayoutParams(mIconSize, mIconSize));
19         } else {
20             i = (RemoteImageView) convertView;
21         }
22 
23         i.setDefaultImage(R.drawable.no_cd);
24         i.setImageUrl(mList.get(position).getImage());
25 
26         return i;
27     }
28     
29     /**
30      * Class implementing holder pattern,
31      * performance boost
32      * 
33      * @author Lukasz Wisniewski
34      */
35     static class ViewHolder {
36         RemoteImageView image;
37     }
38 }

 

AlbumAdapter
 1 public class AlbumAdapter extends ArrayListAdapter<Album> {
 2     
 3     public AlbumAdapter(Activity context) {
 4         super(context);
 5     }
 6 
 7     @Override
 8     public View getView(int position, View convertView, ViewGroup parent) {
 9         View row=convertView;
10 
11         ViewHolder holder;
12 
13         if (row==null) {
14             LayoutInflater inflater = mContext.getLayoutInflater();
15             row=inflater.inflate(R.layout.album_row, null);
16 
17             holder = new ViewHolder();
18             holder.image = (RemoteImageView)row.findViewById(R.id.AlbumRowImageView);
19             holder.albumText = (TextView)row.findViewById(R.id.AlbumRowAlbumTextView);
20             holder.artistText = (TextView)row.findViewById(R.id.AlbumRowArtistTextView);
21             holder.progressBar = (ProgressBar)row.findViewById(R.id.AlbumRowRatingBar);
22 
23             row.setTag(holder);
24         }
25         else{
26             holder = (ViewHolder) row.getTag();
27         }
28         
29         holder.image.setDefaultImage(R.drawable.no_cd);
30         holder.image.setImageUrl(mList.get(position).getImage(),position, getListView());
31         holder.albumText.setText(mList.get(position).getName());
32         holder.artistText.setText(mList.get(position).getArtistName());
33         holder.progressBar.setMax(10);
34         holder.progressBar.setProgress((int) (mList.get(position).getRating()*10));
35 
36         return row;
37     }
38     
39     /**
40      * Class implementing holder pattern,
41      * performance boost
42      * 
43      * @author Lukasz Wisniewski
44      */
45     static class ViewHolder {
46         RemoteImageView image;
47         TextView albumText;
48         TextView artistText;
49         ProgressBar progressBar;
50     }
51 }

 

ArrayListAdapter
 1 public abstract class ArrayListAdapter<T> extends BaseAdapter{
 2     
 3     protected ArrayList<T> mList;
 4     protected Activity mContext;
 5     protected ListView mListView;
 6     
 7     public ArrayListAdapter(Activity context){
 8         this.mContext = context;
 9     }
10 
11     @Override
12     public int getCount() {
13         if(mList != null)
14             return mList.size();
15         else
16             return 0;
17     }
18 
19     @Override
20     public Object getItem(int position) {
21         return mList == null ? null : mList.get(position);
22     }
23 
24     @Override
25     public long getItemId(int position) {
26         return position;
27     }
28 
29     @Override
30     abstract public View getView(int position, View convertView, ViewGroup parent);
31     
32     public void setList(ArrayList<T> list){
33         this.mList = list;
34         notifyDataSetChanged();
35     }
36     
37     public ArrayList<T> getList(){
38         return mList;
39     }
40     
41     public void setList(T[] list){
42         ArrayList<T> arrayList = new ArrayList<T>(list.length);  
43         for (T t : list) {  
44             arrayList.add(t);  
45         }  
46         setList(arrayList);
47     }
48     
49     public ListView getListView(){
50         return mListView;
51     }
52     
53     public void setListView(ListView listView){
54         mListView = listView;
55     }
56 
57 }

 

这里面比较重要的和难点是在ImageAdapter的实现,看上面的ImageAdapter源码可以看出它继承了AlbumAdapter,而AlbumAdapter继承了ArrayListAdapter,ArrayListAdapter继承了BaseAdapter;通过查看ImageAdapter和AlbumAdapter代码可以看出它们两个都是强制实现了抽象类ArrayListAdapter中的抽象方法 abstract public View getView(int position, View convertView, ViewGroup parent);也就是说ImageAdapter可以看做是直接继承ArrayListAdapter,而继承AlbumAdapter的作用是确定了ArrayListAdapter<T>中T的具体类型为Album;
在ArrayListAdapter中除了实现了BaseAdapter中必须的几个方法还实现了向Adapter中传入List,ListView并对其的操作的函数;在ImageAdapter中实现了Adapter中最重要的getView方法。在getView中将album中每个item显示出来。在ImageAdapter的getView中用了RemoteImageView而不是Android提供的ImageView,RemoteImageView如作者介绍的:ImageView extended class allowing easy downloading of remote images(ImageView的扩展类,可以很容易的下载远程图片;也就是说这个扩展类里提供了下载远程图片的方法);关于RemoteImageView的详细介绍请移步android-jamendo源码学习之ImageView扩展类——RemoteImageView ;

3.2 在看album没有取到数据的情况,设置mViewFlipper.setDisplayedChild(2)使mViewFlipper显示第三个View--Failure即加载失败页面;接着设置mFailureBar的监听事件来捕获点击事件后重新调用new NewsTask().execute((Void)null);来加载album;关于mFailureBar.setOnRetryListener我们可以看一下上面分析main.xml布局时给出的FailureBar的源码,就可以看出mFailureBar.setOnRetryListener其实就是加载失败页面中Retry按钮的点击事件。
4. protected void onProgressUpdate(WSError... values) 方法主要用于将doInBackground传递回的数据在UI主线程中更新显示,此处主要用于当doInBackgrund过程中抛出WSError异常后将异常信息通过Toask呈现出来。

 二、接下来看onResume方法:

1 @Override
2     protected void onResume() {
3         fillHomeListView();
4         boolean gesturesEnabled = PreferenceManager.getDefaultSharedPreferences(this).getBoolean("gestures", true);
5         mGestureOverlayView.setEnabled(gesturesEnabled);
6         super.onResume();
7     }
在这个方法中主要是fillHomeListView()方法的实现,从名字也可以看出这个方法是用来填充ListView的;接着通过PreferenceManager获取配置文件中gestures的值来设置手势是否可用。
下面来详细的看下fillHomeListView(),先看源代码:
 1 /**
 2      * Fills ListView with clickable menu items
 3      */
 4     private void fillHomeListView(){
 5         mBrowseJamendoPurpleAdapter = new PurpleAdapter(this);
 6         mMyLibraryPurpleAdapter = new PurpleAdapter(this);
 7         ArrayList<PurpleEntry> browseListEntry = new ArrayList<PurpleEntry>();
 8         ArrayList<PurpleEntry> libraryListEntry = new ArrayList<PurpleEntry>();
 9         
10         // BROWSE JAMENDO
11         
12         browseListEntry.add(new PurpleEntry(R.drawable.list_search, R.string.search, new PurpleListener(){
13             @Override
14             public void performAction() {
15                 SearchActivity.launch(HomeActivity.this);
16             }
17         }));
18 
19         browseListEntry.add(new PurpleEntry(R.drawable.list_radio, R.string.radio, new PurpleListener(){
20             @Override
21             public void performAction() {
22                 RadioActivity.launch(HomeActivity.this);
23             }
24         }));
25         
26         browseListEntry.add(new PurpleEntry(R.drawable.list_top, R.string.most_listened, new PurpleListener(){
27             @Override
28             public void performAction() {
29                 new Top100Task(HomeActivity.this, R.string.loading_top100, R.string.top100_fail).execute();
30             }
31         }));
32         
33         // MY LIBRARY
34         
35         libraryListEntry.add(new PurpleEntry(R.drawable.list_playlist, R.string.playlists, new PurpleListener(){
36             @Override
37             public void performAction() {
38                 BrowsePlaylistActivity.launch(HomeActivity.this, Mode.Normal);
39             }
40         }));
41         
42         // check if we have personalized client then add starred albums
43         final String userName = PreferenceManager.getDefaultSharedPreferences(this).getString("user_name", null);
44         if(userName != null && userName.length() > 0){
45             libraryListEntry.add(new PurpleEntry(R.drawable.list_cd, R.string.albums, new PurpleListener(){
46                 @Override
47                 public void performAction() {
48                     StarredAlbumsActivity.launch(HomeActivity.this, userName);
49                 }
50             }));
51         }
52         
53         /* following needs jamendo authorization (not documented yet on the wiki)
54          * listEntry.add(new PurpleEntry(R.drawable.list_mail, "Inbox")); 
55          */
56 
57         // show this list item only if the SD Card is present
58         if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
59             libraryListEntry.add(new PurpleEntry(R.drawable.list_download, R.string.download, new PurpleListener(){
60                 @Override
61                 public void performAction() {
62                     DownloadActivity.launch(HomeActivity.this);
63                 }
64             }));
65         }
66         
67         // attach list data to adapters
68         mBrowseJamendoPurpleAdapter.setList(browseListEntry);
69         mMyLibraryPurpleAdapter.setList(libraryListEntry);
70         
71         // separate adapters on one list
72         SeparatedListAdapter separatedAdapter = new SeparatedListAdapter(this);
73         separatedAdapter.addSection(getString(R.string.browse_jamendo), mBrowseJamendoPurpleAdapter);
74         separatedAdapter.addSection(getString(R.string.my_library), mMyLibraryPurpleAdapter);
75         
76         mHomeListView.setAdapter(separatedAdapter);
77         mHomeListView.setOnItemClickListener(mHomeItemClickListener);
78     }
    在最开始的运行图我们可以看到ListView是由Browse Jamendo和My Library两个分栏组成。首先介绍下这种listview显示多分栏的简单实现过程,首先我们要定义一个ListView的适配器Adapter在这个项目中就是SeparatedListAdapter,SeparatedListAdapter可以合并接受其他的分栏adapter:separatedAdapter.addSection(getString(R.string.browse_jamendo), mBrowseJamendoPurpleAdapter);separatedAdapter.addSection(getString(R.string.my_library), mMyLibraryPurpleAdapter);。mBrowseJamendoPurpleAdapter和mMyLibraryPurpleAdapter分别就是我们看到的两个分栏所显示出来的内容。
只是这么简单的说可能不是太明白,我们来看一下上面显示分栏的具体实现工程:方法开始定义了两个适配器mBrowseJamendoPurpleAdapter、mMyLibraryPurpleAdapter和两个为其提供数据的list:browseListEntry、libraryListEntry ;然后从第十行到第六十五行是在重复的操作,给数据源添加PurpleEntry实例项,也就是每个分栏中显示item数据;我们看到在添加数据的时候还实现了PurpleListener中的performAction方法,这是因为PurpleListener是接口类,PurpleEntry实例化就要实现接口的方法,这样做是为了让没给具体的实例的实现处理自己的点击事件,也就是说点击每个Item跳转到不同的Activity;其中两个分栏Adapter没什么特别的都是继承了ArrayListAdapter的PurpleAdapter的实例,我们主要看下实现合并分栏Adapter的SeparatedListAdapter:
 1 public class SeparatedListAdapter extends BaseAdapter {
 2 
 3     public final Map<String,Adapter> sections = new LinkedHashMap<String,Adapter>();
 4     public final ArrayAdapter<String> headers;
 5     public final static int TYPE_SECTION_HEADER = 0;
 6 
 7     public SeparatedListAdapter(Context context) {
 8         headers = new ArrayAdapter<String>(context, R.layout.list_header);
 9     }
10 
11     public void addSection(String section, Adapter adapter) {
12         this.headers.add(section);
13         this.sections.put(section, adapter);
14     }
15 
16     public Object getItem(int position) {
17         for(Object section : this.sections.keySet()) {
18             Adapter adapter = sections.get(section);
19             int size = adapter.getCount() + 1;
20 
21             // check if position inside this section
22             if(position == 0) return section;
23             if(position < size) return adapter.getItem(position - 1);
24 
25             // otherwise jump into next section
26             position -= size;
27         }
28         return null;
29     }
30 
31     public int getCount() {
32         // total together all sections, plus one for each section header
33         int total = 0;
34         for(Adapter adapter : this.sections.values())
35             total += adapter.getCount() + 1;
36         return total;
37     }
38 
39     public int getViewTypeCount() {
40         // assume that headers count as one, then total all sections
41         int total = 1;
42         for(Adapter adapter : this.sections.values())
43             total += adapter.getViewTypeCount();
44         return total;
45     }
46 
47     public int getItemViewType(int position) {
48         int type = 1;
49         for(Object section : this.sections.keySet()) {
50             Adapter adapter = sections.get(section);
51             int size = adapter.getCount() + 1;
52 
53             // check if position inside this section
54             if(position == 0) return TYPE_SECTION_HEADER;
55             if(position < size) return type + adapter.getItemViewType(position - 1);
56 
57             // otherwise jump into next section
58             position -= size;
59             type += adapter.getViewTypeCount();
60         }
61         return -1;
62     }
63 
64     public boolean areAllItemsSelectable() {
65         return false;
66     }
67 
68     public boolean isEnabled(int position) {
69         return (getItemViewType(position) != TYPE_SECTION_HEADER);
70     }
71 
72     @Override
73     public View getView(int position, View convertView, ViewGroup parent) {
74         int sectionnum = 0;
75         for(Object section : this.sections.keySet()) {
76             Adapter adapter = sections.get(section);
77             int size = adapter.getCount() + 1;
78 
79             // check if position inside this section
80             if(position == 0) return headers.getView(sectionnum, convertView, parent);
81             if(position < size) return adapter.getView(position - 1, convertView, parent);
82 
83             // otherwise jump into next section
84             position -= size;
85             sectionnum++;
86         }
87         return null;
88     }
89 
90     @Override
91     public long getItemId(int position) {
92         return position;
93     }
94 
95 }

 

  我们看它实现的主要方法:
  1. addSection(String section, Adapter adapter)方法是用来添加分栏Adapter 两个参数分别是分栏名和对应的Adapter;
  2. getItem(int position) 是用来获取position对应Item;由于是多分栏,方法中根据position和每个分栏的size关系来确定点击是哪个分栏中的对应的item并返回相应的item;在这里只有两个分栏所以程序中的size放   在  了for循环的里面,因为这里的for循环最多会执行两次position -= size也只是在跳往第二个分栏时执行,如果是三个或更多的分栏的话 size就要定义在for循环的外面并切size要加上每个分栏的getCount+1;可能有人  会不明   白这里每个分栏的size为什么是getCount+1而不是getCount,我们看到的页面上每个分栏都有一标题也就是我们看的下面的部分。我们可以看到在for循环中有if(position == 0) return section;而section是A  rrayAdapte   r<String>,所以每个分栏的标题都是ArrayAdapter的一项也占用listview的item;所以我们计算size的时候要+1;

               

  3.getViewTypeCount以int数值类型返回列表拥有的itemview的个数,不是item个数而是不同布局的Itemview数; getItemViewType:以int数值型返回itemView的类型;
  4. isEnabled(int position) 返回true,如果项目在指定的位置不是一个分隔符。说白了就是设置哪个item不能点击,比如我们的分栏标题栏;在getItemViewType中设置了 if(position == 0) return TYPE_SECTIO   N_HEADER 也就是说标题item的type是TYPE_SECTION_HEADER,然后再这个方法中判断getItemViewType(position) != TYPE_SECTION_HEADER 来确定item是否可以点击。
  5. getView(int position, View convertView, ViewGroup parent) Adapter中的核心方法,将数据显示到Listview中。由于有两个分栏所以根据position值来确定显示哪个分栏的内容以及要显示标题:
  if(position == 0) return headers.getView(sectionnum, convertView, parent); 首先显示分栏标题这里转向headers.getView来实现;
  if(position < size) return adapter.getView(position - 1, convertView, parent);分栏的具体内容,根据position转向对应的分栏Adapter去处理;
  整个SeparatedListAdapter写的很清晰,有些方法可能一眼看不太明白,大家可以仔细的看一遍;对于其中的方法有什么不明白的可以参看官方文档 BaseAdapter具体的介绍
 fillHomeListView()方法最后 为mHomeListView设置适配器separatedAdapter和setOnItemClickListener监听事件;
到这里OnResume方法就介绍完了,最后在解释下为什么这些方法要放在OnResume中实现而不是我们常用的OnCreate中,首先我们从下面的Activity的生命周期图可以看出onCreate只是在Activity创建的时候调用,如果当前Activity 在onPause货onStop后没有被kill掉而被再次调用则不会执行onCreate方法。可以看出无论哪种情况都将调用onResume方法,放在onResume中可以保证我们每次调用这个Activity显示的数据都是最新的。

     State diagram for an Android Activity Lifecycle.

三、private class Top100Task extends LoadingDialog<Void, Playlist>

我们还看到在这个Activity中还有一个内部类private class Top100Task extends LoadingDialog<Void, Playlist> 这个是在点击Most listened时从服务器加载数据用的,Top100Task不是通过像之前NewsTask那样直接继承AsyncTask来实现的,而是通过继承一个可以被复用的LoadingDialog<Void, Playlist>类来实现的;我们可以看到Top100Task继承于LoadingDialog继承于AsyncTask,其实实现方法和NewsTask总体是一样的都是通过AsyncTask来实现异步加载数据的,这里就不在赘述了,大家可以参考前面的NewsTask和官方的AsyncTask; 自己来理解下。
Top100Task
 1 /**
 2      * Background task fetching top 100 tracks from the remote server
 3      * It's sort of ugly circumvention of Get2 API limitations<br>
 4      * 1 rss + 2 json requests 
 5      *  
 6      * @author Lukasz Wisniewski
 7      */
 8     private class Top100Task extends LoadingDialog<Void, Playlist>{
 9 
10         public Top100Task(Activity activity, int loadingMsg, int failMsg) {
11             super(activity, loadingMsg, failMsg);
12         }
13 
14         @Override
15         public Playlist doInBackground(Void... params) {
16             JamendoGet2Api server = new JamendoGet2ApiImpl();
17             int[] id = null;
18             try {
19                 id = server.getTop100Listened();
20                 // if loading rss failed and no tracks are there - report an error
21                 if (id == null) {
22                     publishProgress(new WSError((String) getResources().getText(R.string.top100_fail)));
23                     return null;
24                 }
25                 Album[] albums = server.getAlbumsByTracksId(id);
26                 Track[] tracks = server.getTracksByTracksId(id, JamendoApplication.getInstance().getStreamEncoding());
27                 if(albums == null || tracks == null)
28                     return null;
29                 Hashtable<Integer, PlaylistEntry> hashtable = new Hashtable<Integer, PlaylistEntry>(); 
30                 for(int i = 0; i < tracks.length; i++){
31                     PlaylistEntry playlistEntry = new PlaylistEntry();
32                     playlistEntry.setAlbum(albums[i]);
33                     playlistEntry.setTrack(tracks[i]);
34                     hashtable.put(tracks[i].getId(), playlistEntry);
35                 }
36 
37                 // creating playlist in the correct order
38                 Playlist playlist = new Playlist();
39                 for(int i =0; i < id.length; i++){
40                     playlist.addPlaylistEntry(hashtable.get(id[i]));
41                 }
42                 return playlist;
43             } catch (JSONException e) {
44                 e.printStackTrace();
45             } catch (WSError e) {
46                 publishProgress(e);
47             }
48             return null;
49         }
50 
51         @Override
52         public void doStuffWithResult(Playlist playlist) {
53             if(playlist.size() <= 0){
54                 failMsg();
55                 return;
56             }
57             
58             PlayerActivity.launch(HomeActivity.this, playlist);
59         }
60 
61     }
62     
63     private OnItemClickListener mGalleryListener = new OnItemClickListener(){
64 
65         @Override
66         public void onItemClick(AdapterView<?> adapterView, View view, int position,
67                 long id) {
68             Album album = (Album) adapterView.getItemAtPosition(position);
69             PlayerActivity.launch(HomeActivity.this, album);
70         }
71         
72     };
73 
74 }


LoadingDialog
  1 /*
  2  * Copyright (C) 2009 Teleca Poland Sp. z o.o. <android@teleca.com>
  3  *
  4  * Licensed under the Apache License, Version 2.0 (the "License");
  5  * you may not use this file except in compliance with the License.
  6  * You may obtain a copy of the License at
  7  *
  8  *      http://www.apache.org/licenses/LICENSE-2.0
  9  *
 10  * Unless required by applicable law or agreed to in writing, software
 11  * distributed under the License is distributed on an "AS IS" BASIS,
 12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  * See the License for the specific language governing permissions and
 14  * limitations under the License.
 15  */
 16 
 17 package com.teleca.jamendo.dialog;
 18 
 19 import com.teleca.jamendo.activity.PlayerActivity;
 20 import com.teleca.jamendo.api.WSError;
 21 
 22 import android.app.Activity;
 23 import android.app.ProgressDialog;
 24 import android.content.DialogInterface;
 25 import android.content.DialogInterface.OnCancelListener;
 26 import android.os.AsyncTask;
 27 import android.widget.Toast;
 28 
 29 /**
 30  * Wrapper around UserTask & ProgressDialog
 31  * 
 32  * @author Lukasz Wisniewski
 33  */
 34 public abstract class LoadingDialog<Input, Result> extends AsyncTask<Input, WSError, Result>{
 35 
 36     private ProgressDialog mProgressDialog;
 37     protected Activity mActivity;
 38     private int mLoadingMsg;
 39     private int mFailMsg;
 40 
 41     public LoadingDialog(Activity activity, int loadingMsg, int failMsg){
 42         this.mActivity = activity;
 43         this.mLoadingMsg = loadingMsg;
 44         this.mFailMsg = failMsg;
 45     }
 46 
 47     @Override
 48     public void onCancelled() {        
 49         
 50         if( mActivity instanceof PlayerActivity)
 51             {
 52             PlayerActivity pa = (PlayerActivity)mActivity;
 53             pa.doCloseActivity();
 54             }
 55         
 56         failMsg();
 57         super.onCancelled();
 58     }
 59 
 60     @Override
 61     public void onPreExecute() {
 62         String title = "";
 63         String message = mActivity.getString(mLoadingMsg);
 64         mProgressDialog = ProgressDialog.show(mActivity, title, message, true, true, new OnCancelListener(){
 65 
 66             @Override
 67             public void onCancel(DialogInterface dialogInterface) {
 68                 LoadingDialog.this.cancel(true);
 69             }
 70 
 71         });
 72         super.onPreExecute();
 73     }
 74 
 75     @Override
 76     public abstract Result doInBackground(Input... params);
 77 
 78     @Override
 79     public void onPostExecute(Result result) {
 80         super.onPostExecute(result);
 81 
 82         mProgressDialog.dismiss();
 83 
 84         if(result != null){
 85             doStuffWithResult(result);
 86         } else {
 87             
 88             if( mActivity instanceof PlayerActivity)
 89                 {
 90                 PlayerActivity pa = (PlayerActivity)mActivity;
 91                 pa.doCloseActivity();
 92                 }
 93             failMsg();
 94 
 95         }
 96     }
 97     
 98     protected void failMsg(){
 99         Toast.makeText(mActivity, mFailMsg, 2000).show();
100     }
101     
102     /**
103      * Very abstract function hopefully very meaningful name,
104      * executed when result is other than null
105      * 
106      * @param result
107      * @return
108      */
109     public abstract void doStuffWithResult(Result result);
110     
111     @Override
112     protected void onProgressUpdate(WSError... values) {
113         Toast.makeText(mActivity, values[0].getMessage(), Toast.LENGTH_LONG).show();
114         this.cancel(true);
115         mProgressDialog.dismiss();
116         super.onProgressUpdate(values);
117     }
118     
119     public void doCancel()
120     {
121         mProgressDialog.dismiss();
122     }
123 
124 }

 

到此HomeActivity的主要内容就介绍完了~~~大家多多指正~~~~中间写着写着掉了次电。。。有一段没保存。。。重写郁闷。。。

休息~休息一下~~

 

 

转载于:https://www.cnblogs.com/zc-luckystar/archive/2013/01/16/2860986.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值