你的位置:首页 > 操作系统

[操作系统]学习Jammendo代码的心路历程(二)ViewFlipper数据的填充


打开Jammendo进入到首页之后,会看到这样一个界面。可以看到下左效果,我们可以看到,他是上部分的ViewFlipper模块和下半部分的listview模块构成的,今天就简单的说一下JammendoViewFlipper是如何加载实际的图片的

我们可以看到上面的ViewFlipper模块中有很多图片,这个模块第一次初始化的时候,实际作用可以理解为是——获取这个星期内最流行的专辑,并在ViewFlipper模块中展示

主界面功能在Jammendo中是在HomeActivity中实现的,可以看下他的布局文件

 main.

<com.teleca.jamendo.util.FixedViewFlipper		android:orientation="vertical" android:id="@+id/ViewFlipper"		android:layout_width="fill_parent" android:layout_height="75dip"		android:background="@drawable/gradient_dark_purple">		<!-- (0) Loading -->		<LinearLayout android:orientation="vertical"			android:layout_width="fill_parent" android:layout_height="fill_parent"			android:layout_marginLeft="15dip" android:gravity="left|center_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:orientation="vertical"			android:layout_width="fill_parent" android:layout_height="fill_parent"			android:gravity="center">			<Gallery android:id="@+id/Gallery" android:layout_width="fill_parent"				android:layout_height="wrap_content" android:spacing="0px" />		</LinearLayout>		<!-- (2) Failure -->		<LinearLayout android:orientation="vertical"			android:layout_width="fill_parent" android:layout_height="fill_parent"			android:layout_marginLeft="15dip" android:gravity="left|center_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>

  在Jammendo中,他自定义了一个继承于ViewFlipper的FixedViewFlipper控件,并且在代码中重写了onDetachedFromWindow方法。在此,他重写这个方法的目的是为了防止一个bug的出现,可以参考下面这篇文章                               http://blog.sina.com.cn/s/blog_74c22b2101012urv.html

  我们可以看到在FixedViewFlipper控件中又包含了三个LinerLayerout布局,它们的作用分别如下:  

  (1)Loading:当图片加载比较慢的时候,会在ViewFlipper显示Loading字样

  (2)Gallery:Gallery是一个滑动图片展示控件,如何客户端可以成功从服务器获取数据,会将在这个控件中展示获取专辑内容

  (3)Fialure:客户端信息获取失败时,会提示加载失败

 

  让我们会到HomeActivity文件,在HomeActivity的OnCreate()方法中存在我们可以看到这样一段代码

  new NewsTask().execute((Void)null);

  这里的NewsTask是继承于AsyncTask的一个类,执行异步操作。异步操作的意义在于我们可以将一些比较费时的操作放在这里执行,提高整体工作效率。在这里,我们将客户端请求服务器端数据,并将数据显示到FixedViewFlipper这样一个过程放在这里执行。

  首先简单分析一下AsyncTask中一些基本方法的意义:

  (1)onPreExecute():在执行doingBackground方法前会执行这个方法,可以显示一些进度条之类的

  (2)doinBackground():耗费时间的动作主要在这个方法中执行

  (3)publicProgress():用来更新任务进度

  (4)onProgressUpdate():当publicProgress方法被调用时,UI线程将调用这个方法在界面上展示任务的进展情况

  (5)onPostExecute():任务执行完成,返回结果

private class NewsTask extends AsyncTask<Void, WSError, Album[]> {		@Override		public void onPreExecute() {			mViewFlipper.setDisplayedChild(0);	     // 默认显示ViewFlipper中第一个界面			mProgressBar.setText(R.string.loading_news);	//进度条文字			super.onPreExecute();		}		@Override		/*		 * 获取专辑数据		 * 		 */		public Album[] doInBackground(Void... params) {			JamendoGet2Api server = new JamendoGet2ApiImpl();			Album[] albums = null;			try {				albums = server.getPopularAlbumsWeek();			} catch (JSONException e) {				e.printStackTrace();			} catch (WSError e){				publishProgress(e);			}			return albums;		}		@Override		public void onPostExecute(Album[] albums) {			if(albums != null && albums.length > 0){				mViewFlipper.setDisplayedChild(1);	//	显示ViewFlipper中第二个界面				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);		}		@Override		protected void onProgressUpdate(WSError... values) {			Toast.makeText(HomeActivity.this, values[0].getMessage(), Toast.LENGTH_LONG).show();			super.onProgressUpdate(values);		}			}

  在onPreExecute()方法中,我们可以看到,他这里执行了一个让FixedViewFlipper显示loading界面的功能

  doinBackground()方法主要完成了从服务器获取专辑信息的动作

  onPostExecute(),将当前获取数据绑定到Gallery控件之上,完成专辑信息的显示

  onProgressUpdate()如果发生异常,会弹出一个对话框提示

 

  下面我们主要分析一下doinBackground()函数到底干了些什么?

  public Album[] doInBackground(Void... params) {			JamendoGet2Api server = new JamendoGet2ApiImpl();			Album[] albums = null;			try {				albums = server.getPopularAlbumsWeek();			} catch (JSONException e) {				e.printStackTrace();			} catch (WSError e){				publishProgress(e);			}			return albums;		}

  首先创建了一个JamendoGet2Api对象,然后定义了一个Album[]数组,在这里的Album[]其实存放的就是我们将要从服务器上获取的专辑信息

  下面调用server中的getPopularAlbumsWeek()获取专辑信息

   跳转到getPopularAlbumsWeek()方法

	private String doGet(String query) throws WSError{		return Caller.doGet(GET_API + query);	}	@Override	public Album[] getPopularAlbumsWeek() throws JSONException, WSError {				String jsonString = doGet("id+name+url+image+rating+artist_name/album/json/?n=20&order=ratingweek_desc");		if (jsonString == null)			return null;				try {			JSONArray jsonArrayAlbums = new JSONArray(jsonString); 			return AlbumFunctions.getAlbums(jsonArrayAlbums);		} catch (NullPointerException e) {			e.printStackTrace();			throw new JSONException(e.getLocalizedMessage());		}	}

  getPopularAlbumsWeek中定义了一个jsonString来保存从从服务器上获取的数据,调用的doGet方法是在Caller类中定义,在这里只是传递了后面一些的参数信息

  跳转到Caller类中的doGet()方法中我们可以发现,他就是通常的json从服务器端获取数据的一个封装,值得我们注意的是他这里的Cache机制,当他收到当前url信息时,会先遍历本地的cache数据,如果本地存在,则不再去访问服务器获取数据。如果不存在于本地,则从服务端获取数据,并数据转换为String类型。

         String data = null;		if(requestCache != null){			data = requestCache.get(url);			if(data != null){				Log.d(JamendoApplication.TAG, "Caller.doGet [cached] "+url);				return data;			}		}

  之后我们只需要一步步返回,便完成了从服务器端获取最近一个火爆专辑信息的获取。