OSCHINA的APP已经开源了,下载地址:http://www.oschina.net/p/oschina-android-app

立即下载回去研究研究吧,很多不错的方法值得学习



研究了几天,发现一些快速上手的方法,跟大家分享一下

第一:启动屏幕分享

AndroidManifest.xml

<activity android:name=".AppStart" android:theme="@android:style/Theme.NoTitleBar.Fullscreen" android:screenOrientation="portrait">

android:theme="@android:style/Theme.NoTitleBar.Fullscreen" 全屏的样式

android:name=".AppStart"对应打开:/src/net/oschina/app/AppStart.java

渐变展示启动屏,然后跳转到main

那么我们来修改启动屏幕
final View view = View.inflate(this, R.layout.start, null);

对应打开:/res/layout/start.xml 可以看到 android:background="@drawable/start_background">

然后对应打开:/res/drawable/start_background.xml

然后就找到 android:src="@drawable/welcome"对应的 /res/drawable/welcome.png

我们可以做个同尺寸的图片,这个不用说了吧,比如我给dlog.cn做了个

替换图片后,run as ,呵呵,是不是很不错,到此为止,大家都应该会做启动屏幕了吧


第二:数据与服务器交互 及 LISTVIEW 展现(穿插讲解顶部下拉刷新数据,及底部分页数据)

OSCHINA APP全部功能已经实现,打开代码后初学者会发现很难上手,因为太多功能太复杂,看着头晕,

我来帮大家理理头绪。。。。。。。

任何网站最主要的数据归根结底都是去做LIST,ANDROID主要是做LISTVIEW,

OSCHINA的APP第一屏就是NEWS的LISTVIEW,那么我们就打开/src/net/oschina/app/ui/Main.java

我们把NEWS更改成我们想要和网站交互的LIST的数据,比如我需要将DLOG.CN的日记列表用NEWS的方式来展现

打开 /src/net/oschina/app/bean/News.java 你会发现,OSCHINA交互数据使用的XML格式的

因为研究过JSON,所以我把DLOG.CN使用JSON来作为和ANDROID的数据交互


1,我们先去看看WEBSERVICE,创建交互数据使用的JSON,

http://www.dlog.cn/api/diary_list?pageSize=30&pageIndex=1 日记列表的JSON

http://www.dlog.cn/api/diary_detail?id=154157907&site=njzj3 日记详情的JSON

pageSize=分页数据列表多少,pageIndex=第几页,

id=日记的ID,site=日记的空间地址

JSON格式如下:

{id:,site:,catalog:,title:,user:,author:,pubTime:,replyCount:,viewCount:}


2,按照这个JSON的KEY,在APP的BEAN目录下创建一个DiaryBean.JAVA

BEAN文件的创建,我就不说了,大家可以打开/src/net/oschina/app/bean/News.java参照一下

我主要讲解一下下面这个方法:

public static Diary parse(InputStream inputStream) throws IOException, AppException, JSONException {

}

inputStream是URL请求后返回的JSON文件,获得文件需要做一些读取转换的工作,然后给DIARY BEAN的KEY赋值,废话不多说,代码如下:


public static Diary parse(InputStream inputStream) throws IOException, AppException, JSONException {Diary diary = null;StringBuilder result = new StringBuilder();InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "UTF-8");BufferedReader reader = new BufferedReader(inputStreamReader);String s;while (((s = reader.readLine()) != null)) {result.append(s);}        reader.close();                try {        JSONObject jsonObject = new JSONObject(result.toString());            Iterator<String> keyIter = jsonObject.keys();    String key;    diary = new Diary();    while (keyIter.hasNext()) {    key = (String) keyIter.next();    if (key.equalsIgnoreCase("id")){    diary.id = StringUtils.toInt(jsonObject.get(key));    }else if(key.equalsIgnoreCase("site")){    diary.site = jsonObject.get(key).toString();    }else if(key.equalsIgnoreCase("catalog")){    diary.setCatalog(StringUtils.toInt(jsonObject.get(key)));    }else if(key.equalsIgnoreCase("replyCount")){    diary.setReplyCount(StringUtils.toInt(jsonObject.get(key)));    }else if(key.equalsIgnoreCase("viewCount")){    diary.setViewCount(StringUtils.toInt(jsonObject.get(key)));    }else if(key.equalsIgnoreCase("title")){    diary.setTitle(jsonObject.get(key).toString());    }else if(key.equalsIgnoreCase("content")){    diary.setContent(jsonObject.get(key).toString());    }else if(key.equalsIgnoreCase("user")){    diary.setUser(jsonObject.get(key).toString());    }else if(key.equalsIgnoreCase("author")){    diary.setAuthor(jsonObject.get(key).toString());    }else if(key.equalsIgnoreCase("pubTime")){    diary.setPubTime(StringUtils.friendly_time(jsonObject.get(key).toString()));    }    }        } catch (JSONException e) {e.printStackTrace();}        return diary;       }


你可以模拟一个JSON文件,然后赋值给BEAN,检查是否正常

3,用同样的方法,做一个DiaryListBean.JAVA

4,ANDROID LISTVIEW通过 ADAPTER将值赋给 ID,然后展现出来,那么我们需要制作一个ADAPTER,和layout里面XML的ID对应起来,

参照/src/net/oschina/app/adapter/ListViewNewsAdapter.java

我们新建立一个 ListViewDiaryAdapter.java,里面id部分不用更改,如果你重新制作XML文件后,重新命名,那么你需要修改对应的id


//获取控件对象listItemView.title = (TextView)convertView.findViewById(R.id.news_listitem_title);listItemView.author = (TextView)convertView.findViewById(R.id.news_listitem_author);listItemView.count= (TextView)convertView.findViewById(R.id.news_listitem_commentCount);listItemView.date= (TextView)convertView.findViewById(R.id.news_listitem_date);listItemView.flag= (ImageView)convertView.findViewById(R.id.news_listitem_flag);
5,增加请求数据源的地址:打卡:/src/cn/dlog/app/bean/URLs.java



public final static String DHOST = "www.dlog.cn";private final static String URL_API_DHOST = HTTP + DHOST + URL_SPLITTER;public final static String DIARY_LIST = URL_API_DHOST+"api/diary_list";public final static String DIARY_DETAIL = URL_API_DHOST+"api/diary_detail";
6,打开/src/cn/dlog/app/AppContext.java,判断是服务器交互读取还是本机缓存读取的方法



/** * 日记列表 * @param catalog * @param pageIndex * @param pageSize * @return * @throws ApiException */public DiaryList getDiaryList(int catalog, int pageIndex, boolean isRefresh) throws AppException {DiaryList list = null;String key = "diarylist_"+catalog+"_"+pageIndex+"_"+PAGE_SIZE;if(isNetworkConnected() && isRefresh) {try{list = ApiClient.getDiaryList(this, catalog, pageIndex, PAGE_SIZE);if(list != null && pageIndex == 0){Notice notice = list.getNotice();list.setNotice(null);list.setCacheKey(key);saveObject(list, key);list.setNotice(notice);}}catch(AppException e){list = (DiaryList)readObject(key);if(list == null)throw e;}} else {list = (DiaryList)readObject(key);if(list == null)list = new DiaryList();}return list;}/** * 日记详情 * @param diary_id * @param diary_site * @return * @throws ApiException */public Diary getDiary(long diary_id, String diary_site, boolean isRefresh) throws AppException {Diary diary = null;String key = "diary_"+diary_id+"_"+diary_site;if(isNetworkConnected() && (!isReadDataCache(key) || isRefresh)) {try{diary = ApiClient.getDiaryDetail(this, diary_id, diary_site);if(diary != null){Notice notice = diary.getNotice();diary.setNotice(null);diary.setCacheKey(key);saveObject(diary, key);diary.setNotice(notice);}}catch(AppException e){diary = (Diary)readObject(key);if(diary == null)throw e;}} else {diary = (Diary)readObject(key);if(diary == null)diary = new Diary();}return diary;}
7,打开: /src/cn/dlog/app/api/ApiClient.java ,增加服务器交互数据读取的方法,即请求URL返回JSON文件的方法。


/** * 获取日记列表 * @param url * @param catalog * @param pageIndex * @param pageSize * @return * @throws AppException */public static DiaryList getDiaryList(AppContext appContext, final int catalog, final int pageIndex, final int pageSize) throws AppException {String diaryUrl = _MakeURL(URLs.DIARY_LIST, new HashMap<String, Object>(){{put("catalog", catalog);put("pageIndex", pageIndex);put("pageSize", pageSize);}});try{return DiaryList.parse(http_get(appContext, diaryUrl));}catch(Exception e){if(e instanceof AppException)throw (AppException)e;throw AppException.network(e);}}/** * 获取日记的详情 * @param url * @param news_id * @return * @throws AppException */public static Diary getDiaryDetail(AppContext appContext, final long diary_id , final String diary_site) throws AppException {String diaryUrl = _MakeURL(URLs.DIARY_DETAIL, new HashMap<String, Object>(){{put("id", diary_id);put("site", diary_site);}});try{return Diary.parse(http_get(appContext, diaryUrl));}catch(Exception e){if(e instanceof AppException)throw (AppException)e;throw AppException.network(e);}}
8,开始编写main文件,让前面的准备的代码都运转起来


打开:/src/net/oschina/app/ui/Main.java

PullToRefreshListView控件是用来下拉刷新页面,及达到页面底部自动获取第二页数据的控件方法,效果很不错

ListViewDiaryAdapter 第4步创建的adapter

Handler是当前的线程

private PullToRefreshListView lvDiary;private ListViewDiaryAdapter lvDiaryAdapter;private List<Diary> lvDiaryData = new ArrayList<Diary>();private Handler lvDiaryHandler;

查看onCreate方法,onCreate是当app进入main页面后,这个页面都在处理什么,

所以我们在这里可以看得很清晰

其实是OSCHINA代码注释的很清晰


@Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.main);                //注册广播接收器    tweetReceiver = new TweetReceiver();        IntentFilter filter = new IntentFilter();        filter.addAction("net.oschina.app.action.APP_TWEETPUB");        registerReceiver(tweetReceiver, filter);                appContext = (AppContext)getApplication();        //网络连接判断        if(!appContext.isNetworkConnected())        UIHelper.ToastMessage(this, R.string.network_not_connected);        //初始化登录        appContext.initLoginInfo();this.initHeadView();        this.initFootBar();        this.initPageScroll();                this.initFrameButton();        this.initBadgeView();        this.initQuickActionGrid();        this.initFrameListView();                //检查新版本        UpdateManager.getUpdateManager().checkAppUpdate(this, false);                //启动轮询通知信息        this.foreachUserNotice();    }


this.initHeadView();初始化头部视图
this.initFootBar();初始化底部栏
this.initPageScroll();初始化水平滚动翻页
this.initFrameButton(); 初始化各个主页的按钮(资讯、问答、动弹、动态、留言)
this.initBadgeView(); 初始化通知信息标签控件
this.initQuickActionGrid();初始化快捷栏
this.initFrameListView();初始化所有ListView

那么我们主要是做 LISTVIEW,点击这个方法查看:

/**     * 初始化所有ListView     */    private void initFrameListView()    {    //初始化listview控件this.initNewsListView();this.initBlogListView();this.initQuestionListView();this.initTweetListView();this.initActiveListView();this.initMsgListView();//加载listview数据this.initFrameListViewData();    }    /** * 初始化所有ListView数据 */ private void initFrameListViewData() { //初始化Handler lvNewsHandler = this.getLvHandler(lvNews, lvNewsAdapter, lvNews_foot_more, lvNews_foot_progress, AppContext.PAGE_SIZE); lvBlogHandler = this.getLvHandler(lvBlog, lvBlogAdapter, lvBlog_foot_more, lvBlog_foot_progress, AppContext.PAGE_SIZE); lvQuestionHandler = this.getLvHandler(lvQuestion, lvQuestionAdapter, lvQuestion_foot_more, lvQuestion_foot_progress, AppContext.PAGE_SIZE);  lvTweetHandler = this.getLvHandler(lvTweet, lvTweetAdapter, lvTweet_foot_more, lvTweet_foot_progress, AppContext.PAGE_SIZE);  lvActiveHandler = this.getLvHandler(lvActive, lvActiveAdapter, lvActive_foot_more, lvActive_foot_progress, AppContext.PAGE_SIZE);  lvMsgHandler = this.getLvHandler(lvMsg, lvMsgAdapter, lvMsg_foot_more, lvMsg_foot_progress, AppContext.PAGE_SIZE);     //加载资讯数据  if(lvNewsData.isEmpty()) {   loadLvNewsData(curNewsCatalog, 0, lvNewsHandler, UIHelper.LISTVIEW_ACTION_INIT);  } }

this.initFrameListViewData(); //加载listview数据

loadLvNewsData(curNewsCatalog, 0, lvNewsHandler, UIHelper.LISTVIEW_ACTION_INIT); //加载资讯数据

这样整个main文件的结构大家应该清晰了,我们只需要增加两个方法,

一个是this.initDiaryListView();

一个是 loadLvDiaryData();

代码如下:

/**     * 初始化日记列表     */    private void initDiaryListView()    {        lvDiaryAdapter = new ListViewDiaryAdapter(this, lvDiaryData, R.layout.diary_listitem);                lvDiary_footer = getLayoutInflater().inflate(R.layout.listview_footer, null);        lvDiary_foot_more = (TextView)lvDiary_footer.findViewById(R.id.listview_foot_more);        lvDiary_foot_progress = (ProgressBar)lvDiary_footer.findViewById(R.id.listview_foot_progress);        lvDiary = (PullToRefreshListView)findViewById(R.id.frame_listview_diary);        lvDiary.addFooterView(lvDiary_footer);//添加底部视图  必须在setAdapter前        lvDiary.setAdapter(lvDiaryAdapter);         lvDiary.setOnItemClickListener(new AdapterView.OnItemClickListener() {        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {        //点击头部、底部栏无效        if(position == 0 || view == lvDiary_footer) return;                Diary diary = null;                //判断是否是TextView        if(view instanceof TextView){        diary = (Diary)view.getTag();        }else{        TextView tv = (TextView)view.findViewById(R.id.diary_listitem_title);        diary = (Diary)tv.getTag();        }        if(diary == null) return;        //跳转到日记详情        UIHelper.showDiaryRedirect(view.getContext(), diary);        }        });        lvDiary.setOnScrollListener(new AbsListView.OnScrollListener() {public void onScrollStateChanged(AbsListView view, int scrollState) {lvDiary.onScrollStateChanged(view, scrollState);//数据为空--不用继续下面代码了if(lvDiaryData.isEmpty()) return;//判断是否滚动到底部boolean scrollEnd = false;try {if(view.getPositionForView(lvDiary_footer) == view.getLastVisiblePosition())scrollEnd = true;} catch (Exception e) {scrollEnd = false;}int lvDataState = StringUtils.toInt(lvDiary.getTag());if(scrollEnd && lvDataState==UIHelper.LISTVIEW_DATA_MORE){lvDiary.setTag(UIHelper.LISTVIEW_DATA_LOADING);lvDiary_foot_more.setText(R.string.load_ing);lvDiary_foot_progress.setVisibility(View.VISIBLE);//当前pageIndexint pageIndex = lvDiarySumData/AppContext.PAGE_SIZE;loadLvDiaryData(curDiaryCatalog, pageIndex, lvDiaryHandler, UIHelper.LISTVIEW_ACTION_SCROLL);}}public void onScroll(AbsListView view, int firstVisibleItem,int visibleItemCount, int totalItemCount) {lvDiary.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount);}});        lvDiary.setOnRefreshListener(new PullToRefreshListView.OnRefreshListener() {            public void onRefresh() {            loadLvDiaryData(curDiaryCatalog, 0, lvDiaryHandler, UIHelper.LISTVIEW_ACTION_REFRESH);            }        });    }/** * 线程加载日记数据 * @param catalog 分类 * @param pageIndex 当前页数 * @param handler 处理器 * @param action 动作标识 */ private void loadLvDiaryData(final int catalog,final int pageIndex,final Handler handler,final int action){   mHeadProgress.setVisibility(ProgressBar.VISIBLE);    new Thread(){   public void run() {        Message msg = new Message();    boolean isRefresh = false;    if(action == UIHelper.LISTVIEW_ACTION_REFRESH || action == UIHelper.LISTVIEW_ACTION_SCROLL)     isRefresh = true;    try {          DiaryList list = appContext.getDiaryList(catalog, pageIndex, isRefresh);         msg.what = list.getPageSize();     msg.obj = list;  } catch (AppException e) {   e.printStackTrace();   msg.what = -1;   msg.obj = e;  }    msg.arg1 = action;    msg.arg2 = UIHelper.LISTVIEW_DATATYPE_DIARY; if(curDiaryCatalog == catalog)  handler.sendMessage(msg);   }  }.start(); } 
修改initFrameListView和initFrameListViewData方法
/**     * 初始化所有ListView     */    private void initFrameListView()    {this.initDiaryListView();this.initFrameListViewData();    }    /**     * 初始化所有ListView数据     */    private void initFrameListViewData()    {        //初始化Handler        lvDiaryHandler = this.getLvHandler(lvDiary, lvDiaryAdapter, lvDiary_foot_more, lvDiary_foot_progress, AppContext.PAGE_SIZE);                //加载资讯数据        if(lvDiaryData.isEmpty()) {loadLvDiaryData(curDiaryCatalog, 0, lvDiaryHandler, UIHelper.LISTVIEW_ACTION_INIT);}    }

大功告成:RUN AS测试,效果如下:




当原理熟悉了以后,剩余的只是机器人工作了

可以使用同样的方法,制作其他分类板块的LISTVIEW数据








更多相关文章

  1. Android(安卓)AsyncTask介绍
  2. Android使用Parcelable传递对象方法及注意事项
  3. 查看Sqlite 数据库
  4. Android(安卓): 如何在WebView显示的页面中查找内容
  5. 有关Android线程的学习
  6. 浅谈Java中Collections.sort对List排序的两种方法
  7. mybatisplus的坑 insert标签insert into select无参数问题的解决
  8. python起点网月票榜字体反爬案例
  9. Python list sort方法的具体使用

随机推荐

  1. android makefile prebuild
  2. Android(安卓)缩放、移动、旋转View相关
  3. Android之查看外部依赖jar的源码_android
  4. Android之Audio初探
  5. 转-Android(安卓)UI学习 - Tab的学习和使
  6. 数据存储和界面展示一
  7. android调用系统功能
  8. Android(安卓)4.4 SD卡文件读写变化
  9. android设置Activity背景色为透明的2种方
  10. android中的帧动画