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

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


第二章:根据oschina开源的app代码快速构建自己站点的ANDROID APP 第二章:根据oschina开源的app代码快速构建自己站点的ANDROID APP 第二章:根据oschina开源的app代码快速构建自己站点的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

第二章:根据oschina开源的app代码快速构建自己站点的ANDROID APP

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

第二章:根据oschina开源的app代码快速构建自己站点的ANDROID APP

替换图片后,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测试,效果如下:


第二章:根据oschina开源的app代码快速构建自己站点的ANDROID APP


第二章:根据oschina开源的app代码快速构建自己站点的ANDROID APP

第二章:根据oschina开源的app代码快速构建自己站点的ANDROID APP


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

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








更多相关文章

  1. 查看Sqlite 数据库
  2. [对android程序作代码混淆]
  3. Android 多媒体数据库
  4. Android SQLiteOpenHelper Sqlite数据库的创建与打开
  5. Android GSM驱动模块(rild)详细分析(一)基本架构及初始化
  6. Android代码混淆配置(Proguard文件解析)
  7. 使用android快速开发框架afinal的FinalDb操作android sqlite数据

随机推荐

  1. viewpaper 抽屉
  2. Android(安卓)锁屏软件MemoryDebris测试
  3. Android(安卓)源码分析
  4. Android(安卓)当前线程是否为主线程(UI线
  5. android状态栏右上角增加图标的方法
  6. 【Android(安卓)开发教程】预创建数据库
  7. Android事件处理分析
  8. SharedPreferenced
  9. Android视频分享-初学者你必须知道的那些
  10. Android内容提供器-读取通讯录