精彩继续~~~上一次分析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显示的数据都是最新的。
三、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的主要内容就介绍完了~~~大家多多指正~~~~中间写着写着掉了次电。。。有一段没保存。。。重写郁闷。。。
休息~休息一下~~