http://mikewang.blog.51cto.com/3826268/737713
1:欢迎页面(SplashView)的实现
实现方法有两种:
1,使用Activity的跳转,SplashView为第一个Activity,解析放在此Activity,解析完成后,跳转至MainActivity,在此不赘述。
2,
使用帧布局,让splash view覆盖在main view之上。先显示splash view(在此过程中执行耗时操作),后显示main view。注意的问题是:多线程之间的切换。(刷UI只能在Main Thread)。
Splash view 可以用一个线性布局(嵌套一个
ImageView和一个动态显示),
Image为公司
logo,动态显示可以选择
ProgressBar或者
Animation。
以下为截图:
![](https://i-blog.csdnimg.cn/blog_migrate/9bedc3f9a533a0a5a45389f9676e009f.jpeg)
代码如下:
new Thread() {
public
void run() {
String strJSON = getJSON();
if (strJSON !=
null) {
mAlbums = parseAlbumJSON(strJSON);
runOnUiThread(
new Runnable() {
public
void run() {
mGalleryAdapter.notifyDataSetChanged();
mSplashView.setVisibility(View.GONE);
mMainView.setVisibility(View.VISIBLE);
initGallery();
}
});
}
else {
// 得不到专辑地址!
return;
}
};
}.start();
注释图片:在此不能完整显示,可以下载后看,很清楚。
![](https://i-blog.csdnimg.cn/blog_migrate/e31ce5de7abc9b388f5231de863018ca.jpeg)
2:ListView分栏的实现
ListView分栏(
Columnar ListView)的好处在于,区分内容,便于用户操作选择。核心思想是:在指定位置插入标题内容。
实现方法如下:
1,
实现Adapter的areAllItemsEnabled()方法和isEnabled()方法,确定内容
显然,ListView的Item中,标题不可被操作,内容部分可响应点击(click)和长按(longClick)时间。设置如下:
@Override
public boolean areAllItemsEnabled() {
// TODO Auto-generated method stub
return false ;
}
@Override
public boolean isEnabled( int position) {
// TODO Auto-generated method stub
if (position == 0 || position == 4) { //
return false ;
} else {
return true ;
}
}
public boolean areAllItemsEnabled() {
// TODO Auto-generated method stub
return false ;
}
@Override
public boolean isEnabled( int position) {
// TODO Auto-generated method stub
if (position == 0 || position == 4) { //
return false ;
} else {
return true ;
}
}
2,在
ListView要显示的内容中,添加两个标题内容。如增加数组长度或
StringArray长度等。
3,
在getView()方法中,做判断,代码如下:
![](https://i-blog.csdnimg.cn/blog_migrate/04eb74a8b395a529d8cf83d7138393d6.png)
![](https://i-blog.csdnimg.cn/blog_migrate/04eb74a8b395a529d8cf83d7138393d6.png)
![](https://i-blog.csdnimg.cn/blog_migrate/04eb74a8b395a529d8cf83d7138393d6.png)
![](https://i-blog.csdnimg.cn/blog_migrate/04eb74a8b395a529d8cf83d7138393d6.png)
![](https://i-blog.csdnimg.cn/blog_migrate/04eb74a8b395a529d8cf83d7138393d6.png)
![](https://i-blog.csdnimg.cn/blog_migrate/04eb74a8b395a529d8cf83d7138393d6.png)
4,效果如下:
![](https://i-blog.csdnimg.cn/blog_migrate/8d72c94e3d73805248e2521cddcf6d14.jpeg)
三:欢迎页面的实现Plus
- <activity android:name=".activity.SplashscreenActivity" >
- <intent-filter>
- <action android:name="android.intent.action.MAIN" >
- </action>
- <category android:name="android.intent.category.LAUNCHER" >
- </category>
- </intent-filter>
- </activity>
- requestWindowFeature(Window.FEATURE_NO_TITLE);
- endAnimation = AnimationUtils.loadAnimation(this, R.anim.fade_out);
- endAnimation.setFillAfter(true);//动画播放完毕,停在最后一帧
- final TutorialDialog dlg = new TutorialDialog(this);
- dlg.setOnDismissListener(new DialogInterface.OnDismissListener() {
- @Override
- public void onDismiss(DialogInterface dialog) {
- CheckBox cb = (CheckBox) dlg.findViewById(R.id.toggleFirstRun);
- if (cb != null && cb.isChecked()) {
- SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(SplashscreenActivity.this);
- prefs.edit().putBoolean(FIRST_RUN_PREFERENCE, false).commit();
- }
- int activeCount = Thread.activeCount();
- Log.d("animation", "activeCount before is:" + activeCount);
- endAnimationHandler.removeCallbacks(endAnimationRunnable);
- activeCount = Thread.activeCount();
- Log.d("animation", "activeCount after is:" + activeCount);
- endAnimationHandler.postDelayed(endAnimationRunnable, 2000);
- }
- });
- dlg.show();
- endAnimation.setAnimationListener(new AnimationListener() {
- @Override
- public void onAnimationStart(Animation animation) { }
- @Override
- public void onAnimationRepeat(Animation animation) { }
- @Override
- public void onAnimationEnd(Animation animation) {
- HomeActivity.launch(SplashscreenActivity.this);
- SplashscreenActivity.this.finish();
- }
- });
- @Override
- public void onAnimationEnd(Animation animation) {
- HomeActivity.launch(SplashscreenActivity.this);
- SplashscreenActivity.this.finish();
- }
- public static void launch(Context c){
- Intent intent = new Intent(c, HomeActivity.class);
- intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP );
- c.startActivity(intent);
- }
- public class Calc extends Activity {
- public static final String PREFS_NAME = "MyPrefsFile";
- @Override
- protected void onCreate(Bundle state){
- super.onCreate(state);
- . . .
- // Restore preferences
- SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);
- boolean silent = settings.getBoolean("silentMode", false);
- setSilent(silent);
- }
- @Override
- protected void onStop(){
- super.onStop();
- // We need an Editor object to make preference changes.
- // All objects are from android.context.Context
- SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);
- SharedPreferences.Editor editor = settings.edit();
- editor.putBoolean("silentMode", mSilentMode);
- // Commit the edits!
- editor.commit();
- }
- }
- private final void initialize(final Context context) {
- setContentView(R.layout.tutorial);
- setTitle(R.string.tutorial_title);
- Button mCloseButton = (Button)findViewById(R.id.closeTutorial);
- if (mCloseButton != null) {
- mCloseButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- dismiss();
- }
- });
- }
- }
- endAnimationHandler.removeCallbacks(endAnimationRunnable);
- endAnimationHandler.postDelayed(endAnimationRunnable, 1500);
四:Home页面的实现
- <com.teleca.jamendo.util.FixedViewFlipper
- android:id="@+id/ViewFlipper"
- android:layout_width="fill_parent"
- android:layout_height="75dip"
- android:background="@drawable/gradient_dark_purple"
- android:orientation="vertical" >
- <!-- (0) Loading -->
- <LinearLayout
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:layout_marginLeft="15dip"
- android:gravity="left|center_vertical"
- android:orientation="vertical" >
- <com.teleca.jamendo.widget.ProgressBar
- android:id="@+id/ProgressBar"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content" >
- </com.teleca.jamendo.widget.ProgressBar>
- </LinearLayout>
- <!-- (1) Gallery -->
- <LinearLayout
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:gravity="center"
- android:orientation="vertical" >
- <Gallery
- android:id="@+id/Gallery"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:spacing="0px" />
- </LinearLayout>
- <!-- (2) Failure -->
- <LinearLayout
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:layout_marginLeft="15dip"
- android:gravity="left|center_vertical"
- android:orientation="vertical" >
- <com.teleca.jamendo.widget.FailureBar
- android:id="@+id/FailureBar"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content" >
- </com.teleca.jamendo.widget.FailureBar>
- </LinearLayout>
- </com.teleca.jamendo.util.FixedViewFlipper>
- public class FailureBar extends LinearLayout{
- protected TextView mTextView;
- protected Button mRetryButton;
- public FailureBar(Context context, AttributeSet attrs) {
- super(context, attrs);
- init();
- }
- public FailureBar(Context context) {
- super(context);
- init();
- }
- /**
- * Sharable code between constructors
- */
- private void init(){
- LayoutInflater.from(getContext()).inflate(R.layout.failure_bar, this);
- mTextView = (TextView)findViewById(R.id.ProgressTextView);
- mRetryButton = (Button)findViewById(R.id.RetryButton);
- }
- /**
- * Sets informative text
- *
- * @param resid
- */
- public void setText(int resid){
- mTextView.setText(resid);
- }
- /**
- * Sets action to be performed when Retry button is clicked
- *
- * @param l
- */
- public void setOnRetryListener(OnClickListener l){
- mRetryButton.setOnClickListener(l);
- }
- }
- private OnItemClickListener mGalleryListener = new OnItemClickListener(){
- @Override
- public void onItemClick(AdapterView<?> adapterView, View view, int position,
- long id) {
- Album album = (Album) adapterView.getItemAtPosition(position);
- PlayerActivity.launch(HomeActivity.this, album);
- Log.d("album_click", "done in GalleryListener");
- }
- };
- public interface PurpleListener {
- /**
- * Callback to be invoked when PurpleEntry is selected
- */
- public void performAction();
- }
- public PurpleEntry(Integer drawable, Integer text, PurpleListener listener) {
- mDrawable = drawable;
- mTextId = text;
- mListener = listener;
- }
- browseListEntry.add(new PurpleEntry(R.drawable.list_search, R.string.search, new PurpleListener(){
- @Override
- public void performAction() {
- SearchActivity.launch(HomeActivity.this);
- }
- }));
- <android.gesture.GestureOverlayView
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/gestures"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:eventsInterceptionEnabled="false"
- android:gestureStrokeType="multiple"
- android:orientation="vertical" >
- <ListView
- android:id="@+id/HomeListView"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:divider="#000" />
- </android.gesture.GestureOverlayView>
- @Override
- protected void onResume() {
- fillHomeListView();
- boolean gesturesEnabled = PreferenceManager.getDefaultSharedPreferences(this).getBoolean("gestures", true);
- mGestureOverlayView.setEnabled(gesturesEnabled);
- super.onResume();
- }
- mGestureOverlayView = (GestureOverlayView) findViewById(R.id.gestures);
- mGestureOverlayView.addOnGesturePerformedListener(JamendoApplication
- .getInstance().getPlayerGestureHandler());
- public class WSError extends Throwable {
- /**
- *
- */
- private static final long serialVersionUID = 1L;
- private String message;
- public WSError() {
- }
- public WSError(String message) {
- this.message = message;
- }
- public void setMessage(String message) {
- this.message = message;
- }
- public String getMessage() {
- return message;
- }
- }
- try {
- // execute request
- try {
- httpResponse = httpClient.execute(httpGet);//apache http step3:
- } catch (UnknownHostException e) {
- throw new WSError("Unable to access " + e.getLocalizedMessage());
- } catch (SocketException e){
- throw new WSError(e.getLocalizedMessage());
- }
- public class RequestCache {
- // TODO cache lifeTime
- private static int CACHE_LIMIT = 10;
- @SuppressWarnings("unchecked")
- private LinkedList history;
- private Hashtable<String, String> cache;
- @SuppressWarnings("unchecked")
- public RequestCache(){
- history = new LinkedList();
- cache = new Hashtable<String, String>();
- }
- @SuppressWarnings("unchecked")
- public void put(String url, String data){
- history.add(url);
- // too much in the cache, we need to clear something
- if(history.size() > CACHE_LIMIT){
- String old_url = (String) history.poll();
- cache.remove(old_url);
- }
- cache.put(url, data);
- }
- public String get(String url){
- return cache.get(url);
- }
- }
- public static String doGet(String url) throws WSError{
- String data = null;
- if(requestCache != null){
- data = requestCache.get(url);
- if(data != null){
- Log.d(JamendoApplication.TAG, "Caller.doGet [cached] "+url);
- return data;
- }
- }
- URI encodedUri = null;
- HttpGet httpGet = null;
- try {
- encodedUri = new URI(url);
- httpGet = new HttpGet(encodedUri);//apache http step2:
- } catch (URISyntaxException e1) {
- // at least try to remove spaces
- String encodedUrl = url.replace(' ', '+');
- httpGet = new HttpGet(encodedUrl);
- e1.printStackTrace();
- }
- // initialize HTTP GET request objects
- HttpClient httpClient = new DefaultHttpClient();//apache http step1:
- HttpResponse httpResponse;
- try {
- // execute request
- try {
- httpResponse = httpClient.execute(httpGet);//apache http step3:
- } catch (UnknownHostException e) {
- throw new WSError("Unable to access " + e.getLocalizedMessage());
- } catch (SocketException e){
- throw new WSError(e.getLocalizedMessage());
- }
- //apche http step4:
- // request data
- HttpEntity httpEntity = httpResponse.getEntity();//apache http step5:
- if(httpEntity != null){
- InputStream inputStream = httpEntity.getContent();
- data = convertStreamToString(inputStream);
- // cache the result
- if(requestCache != null){
- requestCache.put(url, data);
- }
- }
- } catch (ClientProtocolException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- }
- Log.d(JamendoApplication.TAG, "Caller.doGet "+url);
- return data;
- }
- @Override
- protected void onResume() {
- fillHomeListView();
- boolean gesturesEnabled = PreferenceManager.getDefaultSharedPreferences(this).getBoolean("gestures", true);
- mGestureOverlayView.setEnabled(gesturesEnabled);
- super.onResume();
- }
- new NewsTask().execute((Void)null);
- /**
- * Fills ListView with clickable menu items
- */
- private void fillHomeListView(){
- mBrowseJamendoPurpleAdapter = new PurpleAdapter(this);
- mMyLibraryPurpleAdapter = new PurpleAdapter(this);
- ArrayList<PurpleEntry> browseListEntry = new ArrayList<PurpleEntry>();
- ArrayList<PurpleEntry> libraryListEntry = new ArrayList<PurpleEntry>();
- // BROWSE JAMENDO
- browseListEntry.add(new PurpleEntry(R.drawable.list_search, R.string.search, new PurpleListener(){
- @Override
- public void performAction() {
- SearchActivity.launch(HomeActivity.this);
- }
- }));
- browseListEntry.add(new PurpleEntry(R.drawable.list_radio, R.string.radio, new PurpleListener(){
- @Override
- public void performAction() {
- RadioActivity.launch(HomeActivity.this);
- }
- }));
- browseListEntry.add(new PurpleEntry(R.drawable.list_top, R.string.most_listened, new PurpleListener(){
- @Override
- public void performAction() {
- new Top100Task(HomeActivity.this, R.string.loading_top100, R.string.top100_fail).execute();
- }
- }));
- // MY LIBRARY
- libraryListEntry.add(new PurpleEntry(R.drawable.list_playlist, R.string.playlists, new PurpleListener(){
- @Override
- public void performAction() {
- BrowsePlaylistActivity.launch(HomeActivity.this, Mode.Normal);
- }
- }));
- // check if we have personalized client then add starred albums
- final String userName = PreferenceManager.getDefaultSharedPreferences(this).getString("user_name", null);
- if(userName != null && userName.length() > 0){
- libraryListEntry.add(new PurpleEntry(R.drawable.list_cd, R.string.albums, new PurpleListener(){
- @Override
- public void performAction() {
- StarredAlbumsActivity.launch(HomeActivity.this, userName);
- }
- }));
- }
- /* following needs jamendo authorization (not documented yet on the wiki)
- * listEntry.add(new PurpleEntry(R.drawable.list_mail, "Inbox"));
- */
- // show this list item only if the SD Card is present
- if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
- libraryListEntry.add(new PurpleEntry(R.drawable.list_download, R.string.download, new PurpleListener(){
- @Override
- public void performAction() {
- DownloadActivity.launch(HomeActivity.this);
- }
- }));
- }
- // listEntry.add(new PurpleEntry(R.drawable.list_star, R.string.favorites, new PurpleListener(){
- //
- // @Override
- // public void performAction() {
- // Playlist playlist = new DatabaseImpl(HomeActivity.this).getFavorites();
- // JamendroidApplication.getInstance().getPlayerEngine().openPlaylist(playlist);
- // PlaylistActivity.launch(HomeActivity.this, true);
- // }
- //
- // }));
- // attach list data to adapters
- mBrowseJamendoPurpleAdapter.setList(browseListEntry);
- mMyLibraryPurpleAdapter.setList(libraryListEntry);
- // separate adapters on one list
- SeparatedListAdapter separatedAdapter = new SeparatedListAdapter(this);
- separatedAdapter.addSection(getString(R.string.browse_jamendo), mBrowseJamendoPurpleAdapter);
- separatedAdapter.addSection(getString(R.string.my_library), mMyLibraryPurpleAdapter);
- mHomeListView.setAdapter(separatedAdapter);
- mHomeListView.setOnItemClickListener(mHomeItemClickListener);
- }
- @Override
- public boolean onPrepareOptionsMenu(Menu menu) {
- if(JamendoApplication.getInstance().getPlayerEngineInterface() == null || JamendoApplication.getInstance().getPlayerEngineInterface().getPlaylist() == null){
- menu.findItem(R.id.player_menu_item).setVisible(false);
- } else {
- menu.findItem(R.id.player_menu_item).setVisible(true);
- }
- return super.onPrepareOptionsMenu(menu);
- }
五:Adpter框架
- public void onPostExecute(Album[] albums) {
- if(albums != null && albums.length > 0){
- mViewFlipper.setDisplayedChild(1);
- ImageAdapter albumsAdapter = new ImageAdapter(HomeActivity.this);
- albumsAdapter.setList(albums);
- mGallery.setAdapter(albumsAdapter);
- mGallery.setOnItemClickListener(mGalleryListener);
- mGallery.setSelection(albums.length/2, true); // animate to center
- } else {
- mViewFlipper.setDisplayedChild(2);
- mFailureBar.setOnRetryListener(new OnClickListener(){
- @Override
- public void onClick(View v) {
- new NewsTask().execute((Void)null);
- }
- });
- mFailureBar.setText(R.string.connection_fail);
- }
- super.onPostExecute(albums);
- }
- public void setList(T[] list){
- ArrayList<T> arrayList = new ArrayList<T>(list.length);
- for (T t : list) {
- arrayList.add(t);
- }
- setList(arrayList);
- }
- public void setList(ArrayList<T> list){
- this.mList = list;
- notifyDataSetChanged();//刷新ui
- }
- @Override
- abstract public View getView(int position, View convertView, ViewGroup parent);//抽象方法
- public void setList(ArrayList<T> list){
- this.mList = list;
- notifyDataSetChanged();//刷新ui
- }
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- RemoteImageView i;
- if (convertView == null) {
- i = new RemoteImageView(mContext);
- i.setScaleType(RemoteImageView.ScaleType.FIT_CENTER);
- i.setLayoutParams(new Gallery.LayoutParams(mIconSize, mIconSize));
- } else {
- i = (RemoteImageView) convertView;
- }
- i.setDefaultImage(R.drawable.no_cd);
- i.setImageUrl(mList.get(position).getImage());
- return i;
- }
- public void setImageUrl(String url){
- // Log.d("img_url", "img_url is :" + url);
- if (mUrl != null && mUrl.equals(url) && (mCurrentlyGrabbedUrl == null ||//1:url赋给全局变量mUrl,两者相等且都为空,但是未执行,所以mCurrentlyGrabbedUrl为空
- (mCurrentlyGrabbedUrl != null && !mCurrentlyGrabbedUrl.equals(url)))) {//2:第n(n>1)次执行时,并未完成downloadTask
- mFailure++;
- if(mFailure > MAX_FAILURES){//超过指定重连次数
- Log.e(JamendoApplication.TAG, "Failed to download "+url+", falling back to default image");
- loadDefaultImage();
- return;
- }
- } else {
- mUrl = url;
- mFailure = 0;
- }
- updateCacheSize();
- if (mCacheSize>0 && (url.contains(ALBUMS) || url.contains(RADIOS))) {//只有两类路径图片需要缓存
- String fileName = convertUrlToFileName(url);
- String dir = getDirectory(fileName);
- Log.d("img_url", "dir is :" + dir);
- String pathFileName = dir + "/" + fileName;
- Log.d("img_url", "pathFileName is :" + pathFileName);
- Bitmap tbmp = BitmapFactory.decodeFile(pathFileName);//从指定文件保存路径解码处图片
- if (tbmp == null) {
- Log.d(JamendoApplication.TAG, "Image is not present, try to download");
- try{
- new DownloadTask().execute(url);
- } catch (RejectedExecutionException e) {
- // do nothing, just don't crash
- }
- } else {
- Log.i(JamendoApplication.TAG, "Loading album cover from file");
- this.setImageBitmap(tbmp);
- updateFileTime(dir,fileName );
- }
- removeAlbumCoversCache(dir, fileName);//对专辑图片的缓存处理:比较大120k
- removeRadioCoversCache(dir, fileName);//对广播图片的缓存处理:比较小8k
- }
- else {
- Log.i(JamendoApplication.TAG, "File not cached supported" + url);
- ImageCache imageCache = JamendoApplication.getInstance()
- .getImageCache();
- if (imageCache.isCached(url)) {
- this.setImageBitmap(imageCache.get(url));
- } else {
- try {
- Log.i(JamendoApplication.TAG, "Image is not present, try to download");
- new DownloadTask().execute(url);
- } catch (RejectedExecutionException e) {
- // do nothing, just don't crash
- }
- }
- }
- }
六:缓存
- /*
- * Copyright (C) 2009 Teleca Poland Sp. z o.o. <android@teleca.com>
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- package com.teleca.jamendo.api.util;
- import java.util.Hashtable;
- import java.util.LinkedList;
- /**
- * @author Lukasz Wisniewski
- */
- public class RequestCache {
- // TODO cache lifeTime
- private static int CACHE_LIMIT = 10;//保存最近十次的请求数据,key为url
- @SuppressWarnings("unchecked")
- private LinkedList history;
- private Hashtable<String, String> cache;
- @SuppressWarnings("unchecked")
- public RequestCache(){
- history = new LinkedList();
- cache = new Hashtable<String, String>();
- }
- @SuppressWarnings("unchecked")
- public void put(String url, String data){
- history.add(url);
- // too much in the cache, we need to clear something
- if(history.size() > CACHE_LIMIT){
- String old_url = (String) history.poll();
- cache.remove(old_url);
- }
- cache.put(url, data);
- }
- public String get(String url){
- return cache.get(url);
- }
- }
- public class ImageCache extends WeakHashMap<String, Bitmap> {
- private static final long serialVersionUID = 1L;
- public boolean isCached(String url){
- return containsKey(url) && get(url) != null;
- }
- }
- public void setImageUrl(String url){
- // Log.d("img_url", "img_url is :" + url);
- if (mUrl != null && mUrl.equals(url) && (mCurrentlyGrabbedUrl == null ||//1:url赋给全局变量mUrl,两者相等且都为空,但是未执行,所以mCurrentlyGrabbedUrl为空
- (mCurrentlyGrabbedUrl != null && !mCurrentlyGrabbedUrl.equals(url)))) {//2:第n(n>1)次执行时,并未完成downloadTask
- mFailure++;
- if(mFailure > MAX_FAILURES){//超过指定重连次数
- Log.e(JamendoApplication.TAG, "Failed to download "+url+", falling back to default image");
- loadDefaultImage();
- return;
- }
- } else {
- mUrl = url;
- mFailure = 0;
- }
- updateCacheSize();
- if (mCacheSize>0 && (url.contains(ALBUMS) || url.contains(RADIOS))) {//只有两类路径图片需要缓存
- String fileName = convertUrlToFileName(url);
- String dir = getDirectory(fileName);
- Log.d("img_url", "dir is :" + dir);
- String pathFileName = dir + "/" + fileName;
- Log.d("img_url", "pathFileName is :" + pathFileName);
- Bitmap tbmp = BitmapFactory.decodeFile(pathFileName);//从指定文件保存路径解码处图片
- if (tbmp == null) {
- Log.d(JamendoApplication.TAG, "Image is not present, try to download");
- try{
- new DownloadTask().execute(url);
- } catch (RejectedExecutionException e) {
- // do nothing, just don't crash
- }
- } else {
- Log.i(JamendoApplication.TAG, "Loading album cover from file");
- this.setImageBitmap(tbmp);
- updateFileTime(dir,fileName );
- }
- removeAlbumCoversCache(dir, fileName);//对专辑图片的缓存处理:比较大120k
- removeRadioCoversCache(dir, fileName);//对广播图片的缓存处理:比较小8k
- }
- else {
- Log.i(JamendoApplication.TAG, "File not cached supported" + url);
- ImageCache imageCache = JamendoApplication.getInstance()
- .getImageCache();
- if (imageCache.isCached(url)) {
- this.setImageBitmap(imageCache.get(url));
- } else {
- try {
- Log.i(JamendoApplication.TAG, "Image is not present, try to download");
- new DownloadTask().execute(url);
- } catch (RejectedExecutionException e) {
- // do nothing, just don't crash
- }
- }
- }
- }
- removeAlbumCoversCache(dir, fileName);//对专辑图片的缓存处理:比较大120k
- removeRadioCoversCache(dir, fileName);//对广播图片的缓存处理:比较小8k
- private void removeAlbumCoversCache(String dirPath, String filename) {
- if (!filename.contains(ALBUM_COVER_MARKER)) {
- return;
- }
- File dir = new File(dirPath);
- File[] files = dir.listFiles();
- if (files == null) {
- // possible sd card is not present/cant write
- return;
- }
- int dirSize = 0;
- for (int i = 0; i < files.length; i++) {
- if (files[i].getName().contains(ALBUM_COVER_MARKER)) {//计算出指定路径指定类型文件大小:只计算出大图片的大小,小的不用计算,简化
- dirSize += files[i].length();
- }
- }
- if (dirSize > mCacheSize * MB || FREE_SD_SPACE_NEEDED_TO_CACHE > freeSpaceOnSd()) {
- int removeFactor = (int) ((0.4 * files.length) + 1);//移出缓存文件夹的四分之一文件
- Arrays.sort(files, new FileLastModifSort());//按照从老到新的顺序排列
- Log.i(JamendoApplication.TAG, "Clear some album covers cache files ");
- for (int i = 0; i < removeFactor; i++) {//移出选定数量的缓存文件(其中只删除占空间比较大的专辑图片,抓大舍小)
- if (files[i].getName().contains(ALBUM_COVER_MARKER)) {
- files[i].delete();
- }
- }
- }
- }
- private void removeRadioCoversCache(String dirPath, String filename) {
- if (filename.contains(ALBUM_COVER_MARKER)) {//筛选出非专辑图片类图片
- return;
- }
- File file = new File(dirPath, filename);
- if (file.lastModified() != 0
- && System.currentTimeMillis() - file.lastModified() > mTimeDiff) {//清除缓存(下载)超过指定天数的文件,即所有的Radio类图片,只保存最近45天内的文件
- Log.i(JamendoApplication.TAG, "Clear some album or radio thumbnail cache files ");
- file.delete();
- }
- }
七:搜索页面实现及数据加载
- public abstract class LoadingDialog<Input, Result> extends AsyncTask<Input, WSError, Result>
- @Override
- public void onPreExecute() {
- String title = "";
- String message = mActivity.getString(mLoadingMsg);
- mProgressDialog = ProgressDialog.show(mActivity, title, message, true, true, new OnCancelListener(){
- @Override
- public void onCancel(DialogInterface dialogInterface) {
- LoadingDialog.this.cancel(true);
- }
- });
- super.onPreExecute();
- }
- @Override
- public void onCancelled() {
- if( mActivity instanceof PlayerActivity)
- {
- PlayerActivity pa = (PlayerActivity)mActivity;
- pa.doCloseActivity();
- }
- failMsg();
- super.onCancelled();
- }
- @Override
- public abstract Result doInBackground(Input... params);
- @Override
- public void onPostExecute(Result result) {
- super.onPostExecute(result);
- mProgressDialog.dismiss();
- if(result != null){
- doStuffWithResult(result);
- } else {
- if( mActivity instanceof PlayerActivity)
- {
- PlayerActivity pa = (PlayerActivity)mActivity;
- pa.doCloseActivity();
- }
- failMsg();
- }
- }
- /**
- * Very abstract function hopefully very meaningful name,
- * executed when result is other than null
- *
- * @param result
- * @return
- */
- public abstract void doStuffWithResult(Result result);
- protected void failMsg(){
- Toast.makeText(mActivity, mFailMsg, 2000).show();
- }
- @Override
- protected void onProgressUpdate(WSError... values) {
- Toast.makeText(mActivity, values[0].getMessage(), Toast.LENGTH_LONG).show();
- this.cancel(true);
- mProgressDialog.dismiss();
- super.onProgressUpdate(values);
- }
- <com.teleca.jamendo.util.FixedViewFlipper
- android:id="@+id/SearchViewFlipper"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:layout_weight="1"
- android:background="#fff" >
- <ListView
- android:id="@+id/SearchListView"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:divider="#000" />
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:text="@string/no_results" >
- </TextView>
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:text="@string/search_list_hint" >
- </TextView>
- </com.teleca.jamendo.util.FixedViewFlipper>
- AlbumAdapter albumAdapter = new AlbumAdapter(SearchActivity.this);
- albumAdapter.setList(albums);
- albumAdapter.setListView(mSearchListView);
- mAdapter = albumAdapter;
- catch (JSONException e) {
- e.printStackTrace();
- } catch (WSError e) {
- publishProgress(e);
- this.cancel(true);
- }
- @Override
- public void doStuffWithResult(Integer result) {
- mSearchListView.setAdapter(mAdapter);
- if(mSearchListView.getCount() > 0){
- mViewFlipper.setDisplayedChild(0); // display results
- } else {
- mViewFlipper.setDisplayedChild(1); // display no results message
- }
- // results are albums
- if(mSearchMode.equals(0) || mSearchMode.equals(1) || mSearchMode.equals(3)){
- mSearchListView.setOnItemClickListener(mAlbumClickListener);
- }
- // results are playlists
- if(mSearchMode.equals(2)){
- mSearchListView.setOnItemClickListener(mPlaylistClickListener);
- }
- }
- @SuppressWarnings("unchecked")
- @Override
- protected void onRestoreInstanceState(Bundle savedInstanceState) {
- mSearchMode = (SearchMode) savedInstanceState.getSerializable("mode");
- if(mSearchMode != null){
- if(mSearchMode.equals(SearchMode.Artist)
- || mSearchMode.equals(SearchMode.Tag)
- || mSearchMode.equals(SearchMode.UserStarredAlbums)){
- AlbumAdapter adapter = new AlbumAdapter(this);
- adapter.setList((ArrayList<Album>) savedInstanceState.get("values"));
- mSearchListView.setAdapter(adapter);
- mSearchListView.setOnItemClickListener(mAlbumClickListener);
- }
- if(mSearchMode.equals(SearchMode.UserPlaylist)) {
- PlaylistRemoteAdapter adapter = new PlaylistRemoteAdapter(this);
- adapter.setList((ArrayList<PlaylistRemote>) savedInstanceState.get("values"));
- mSearchListView.setAdapter(adapter);
- mSearchListView.setOnItemClickListener(mPlaylistClickListener);
- }
- mViewFlipper.setDisplayedChild(savedInstanceState.getInt("flipper_page"));
- }
- super.onRestoreInstanceState(savedInstanceState);
- }
- @Override
- protected void onSaveInstanceState(Bundle outState) {//保存上次的搜索结果,返回时还在
- if(mSearchMode != null){
- outState.putSerializable("mode", mSearchMode);
- if(mSearchMode.equals(SearchMode.Artist)
- || mSearchMode.equals(SearchMode.Tag)
- || mSearchMode.equals(SearchMode.UserStarredAlbums)){
- AlbumAdapter adapter = (AlbumAdapter)mSearchListView.getAdapter();
- outState.putSerializable("values", adapter.getList());
- }
- if(mSearchMode.equals(SearchMode.UserPlaylist)) {
- PlaylistRemoteAdapter adapter = (PlaylistRemoteAdapter)mSearchListView.getAdapter();
- outState.putSerializable("values", adapter.getList());
- }
- outState.putInt("flipper_page", mViewFlipper.getDisplayedChild());
- }
- super.onSaveInstanceState(outState);
- }
八:播放流程
- Album album = (Album) adapterView.getItemAtPosition(position);
- PlayerActivity.launch(HomeActivity.this, album);
- public class PlayerAlbumLoadingDialog extends LoadingDialog<Album, Track[]>{
- private Album mAlbum;
- public PlayerAlbumLoadingDialog(Activity activity, int loadingMsg, int failMsg) {
- super(activity, loadingMsg, failMsg);
- }
- @Override
- public Track[] doInBackground(Album... params) {
- mAlbum = params[0];
- JamendoGet2Api service = new JamendoGet2ApiImpl();
- Track[] tracks = null;
- try {
- tracks = service.getAlbumTracks(mAlbum, JamendoApplication.getInstance().getStreamEncoding());
- Log.d("play_workflow", "doInBackground tracks is:" + tracks.toString());
- } catch (JSONException e) {
- e.printStackTrace();
- return null;
- } catch (WSError e) {
- publishProgress(e);
- cancel(true);
- }
- return tracks;
- }
- @Override
- public void doStuffWithResult(Track[] tracks) {
- Intent intent = new Intent(mActivity, PlayerActivity.class);
- Playlist playlist = new Playlist();
- mAlbum.setTracks(tracks);
- playlist.addTracks(mAlbum);
- intent.putExtra("playlist", playlist);
- Log.d("play_workflow", "doStuffWithResult playlist is:" + playlist.toString());
- mActivity.startActivity(intent);
- }
- }
- private void handleIntent(){
- Log.i(JamendoApplication.TAG, "PlayerActivity.handleIntent");
- // This will be result of this intent handling
- Playlist playlist = null;
- Log.d("play_workflow", "data is:" + getIntent().getData());//本身并未给data赋值,所以执行的都是data==null的情形
- // We need to handle Uri
- if(getIntent().getData() != null){//不执行此条判断
- // Check if this intent was already once parsed
- // we don't need to do that again
- if(!getIntent().getBooleanExtra("handled", false)){
- Log.d("play_workflow", "handled is true" );
- mUriLoadingDialog = (LoadingDialog) new UriLoadingDialog(this, R.string.loading, R.string.loading_fail).execute();
- }
- } else {
- Log.d("play_workflow", "handled is false" );
- playlist = (Playlist) getIntent().getSerializableExtra("playlist");
- Log.d("play_workflow", "handle_intent playlist is:" + playlist);
- loadPlaylist(playlist);
- }
- }
- private void loadPlaylist(Playlist playlist){
- Log.i(JamendoApplication.TAG, "PlayerActivity.loadPlaylist");
- if(playlist == null)
- return;
- mPlaylist = playlist;
- if(mPlaylist != getPlayerEngine().getPlaylist()){//播放列表不相等,就要重新加载
- //getPlayerEngine().stop();
- getPlayerEngine().openPlaylist(mPlaylist);
- getPlayerEngine().play();
- }
- }
- @Override
- public void openPlaylist(Playlist playlist) {
- mPlaylist = playlist;
- if(mServicePlayerEngine != null){
- mServicePlayerEngine.openPlaylist(playlist);
- }
- }
- @Override
- public void openPlaylist(Playlist playlist) {
- if(!playlist.isEmpty())
- mPlaylist = playlist;
- else
- mPlaylist = null;
- }
- /**
- * on click play/pause and open playlist if necessary
- */
- private OnClickListener mPlayOnClickListener = new OnClickListener(){
- @Override
- public void onClick(View v) {
- if(getPlayerEngine().isPlaying()){
- getPlayerEngine().pause();
- } else {
- getPlayerEngine().play();
- }
- }
- };
- @Override
- public void play() {
- if (mServicePlayerEngine != null) {
- Log.d("play_workflow", "mServicePlayerEngine is not null:" );
- playlistCheck();
- mServicePlayerEngine.play();
- } else {
- Log.d("play_workflow", "mServicePlayerEngine is null");
- startAction(PlayerService.ACTION_PLAY);
- }
- }
- if(action.equals(ACTION_PLAY)){
- mPlayerEngine.play();
- return;
- }
- @Override
- public void play() {
- if( mPlayerEngineListener.onTrackStart() == false ){
- return; // apparently sth prevents us from playing tracks
- }
- // check if there is anything to play
- if(mPlaylist != null){
- // check if media player is initialized
- if(mCurrentMediaPlayer == null){
- mCurrentMediaPlayer = build(mPlaylist.getSelectedTrack());
- }
- // check if current media player is set to our song
- if(mCurrentMediaPlayer != null && mCurrentMediaPlayer.playlistEntry != mPlaylist.getSelectedTrack()){
- cleanUp(); // this will do the cleanup job
- mCurrentMediaPlayer = build(mPlaylist.getSelectedTrack());
- }
- // check if there is any player instance, if not, abort further execution
- if(mCurrentMediaPlayer == null)
- return;
- // check if current media player is not still buffering
- if(!mCurrentMediaPlayer.preparing){
- // prevent double-press
- if(!mCurrentMediaPlayer.isPlaying()){
- // i guess this mean we can play the song
- Log.i(JamendoApplication.TAG, "Player [playing] "+mCurrentMediaPlayer.playlistEntry.getTrack().getName());
- // starting timer
- mHandler.removeCallbacks(mUpdateTimeTask);
- mHandler.postDelayed(mUpdateTimeTask, 1000);
- mCurrentMediaPlayer.start();
- }
- } else {
- // tell the mediaplayer to play the song as soon as it ends preparing
- mCurrentMediaPlayer.playAfterPrepare = true;
- }
- }
- }
- /**
- * Since 0.9.8.7 we embrace "bindless" PlayerService thus this adapter. No
- * big need of code refactoring, we just wrap sending intents around defined
- * interface
- *
- * 意思是:因为jamendo使用的是无绑定的PlayService,所以有着这个适配器。不需要对代码
- * 进行太多的重构。我们只需要通过这个指定的接口发送Intent就ok了。
- * @author Lukasz Wisniewski
- */
- private class IntentPlayerEngine implements PlayerEngine
- /**
- * Player core engine allowing playback, in other words, a
- * wrapper around Android's <code>MediaPlayer</code>, supporting
- * <code>Playlist</code> classes
- *
- * @author Lukasz Wisniewski
- */
- public class PlayerEngineImpl implements PlayerEngine