1.熟悉 Android Stuido、Eclipse、SQLite 等常用 Android 开发工具。
2.熟悉一种语言,主要使用java语言开发。
3.设计并实现一个具体的 Android 应用系统,本次课程设计选择的是新闻客户端的题目。
(1)对选定的新闻客户端项目进行需求分析,写出需求说明书,并搜集、整理所需素材。
(2)根据项目需求,进行数据库(如果需要数据库的话)的概要设计与详细设计。
(3)根据需求说明进行项目的功能设计,画出每个界面的原型。进行详细设计,实现每个模块的功能。
(4)对项目进行部署与测试。
(5)分析总结项目的创新点和存在的不足,提出优化思路。
对于要完成的新闻客户端项目需要做到以下功能:
1.掌握 Android 中的菜单及导航框架。
随着安卓开发的盛行,安卓应用占据了手机APP市场的绝大部分份额。随着市场的推动和技术的发展与沉淀,Android开发领域产生了很多实用并且容易开发的各类包和小型框架,例如速展示Adobe Afeter Effect(AE)工具所作动画的框架客户端组件间异步通信的框架lottie-android、RxAndroid、侧滑菜单栏框架SlidingMenu、提供场景转换过渡能力的动画框架Material-Animations等众多矿建,使得Android开发的样式更加的多样化、用户体验更加的高,开发周期更加短。
2.掌握自定义布局.
掌握安卓的五大布局,对于五大布局的使用场景进行了解,并且能够在自己的项目里面合理选择和使用安卓的界面布局。
3.掌握 Android 中的数据存储
对于Android的五大数据存储方式进行熟悉与使用。在本次的新闻客户端的课程设计的开发中,Android的数据存储使用到了SharedPreferences数据存储和网络断的数据获取的方法。
4.掌握安卓项目的运行方式和网络端数据的获取、处理和展示, 能够将从网络中夺取的数据进行处理利用listView显示在APP中,能够对于内容进行查看。
在课程设计的过程中要求以个人为小组完成实验项目的开发,要求从界面的设计到逻辑java代码的实现,图标的排版,运行、测试和实验报告的撰写都由个人完成。
随着移动通信与Internet向移动终端的普及,网络和用户对移动终端的要求越来越高,而wWindows Mobile, PalmoS等手机平台过于封闭,不能很好的满足用户的需求,因此市场迫切需要一个开发性很强的平台。经过多年的发展,第四代代数字通信(4G) 技术活动了广泛的接受,它为移动终端用户带来了更快的数据传输速率。随着4G网络的使用,移动终端不再仅是通讯网络的终端,还将成为互联网的终端。因此,移动终端的应用软件和需要的服务将会有很大的发展空间。Google 为此于2007年11月推出了一个专为移动设备设计的软件平台一-Android。
不仅如此,在科技的巅峰时期,第五代数字通信(5G的出现)将会把Android开推上一个更高的台阶,等多的、更多元化的、更快速的安卓应用将诞生。
Android是一套真正意义上的开发性的移动设备综合平台,它包括操作系统、中间件和一些关键的平台应用。Android是由Linux+Java 构成的开源软件,允许所有厂商和个人在其基础_上进行开发。Android平台的开放性等特点既能促进技术(包括平台本身)的创新,又有助于降低开发成本,还可以是运营商能非常方便地制定自己的特色化的产品。因此,它具有很大的市场发展潜力。
在互联网和IT技术快速发展的这个社会,伴随着Android操作系统的盛行,基于Android发的的基于Android的应用已经非常盛行。而且安卓开发更将面向普通永华,这些用户更关注用户体验因此利用安卓实现多媒体应用十分必要。
在以前的传统认知中人们获取新闻的方法一般来源于收听广播、阅览报纸、观看电视新闻、但是对于4G发展、5G马上盛行的新世纪,简单的信息获取已经完全不能能满足当代人的需求,一款可以直接在手机APP上阅览新闻的APP也就显得尤为重要。利用APP查看新闻、时事政治、以及热点新闻将是一种趋势。在这样的趋势下设计了这个Android手机新闻客户端APP。
以实践为目的,通过一个或者多个完整Android项目的开发从而从实际中掌握Android开发的流程与开发技术。将Android开发课程中的诸多知识点运用于实际开中。熟悉Android开发工具的使用,了解并学会解决安卓开发中常见的错误。理解整个流程。学会框架的使用。
Android Studio是一个Android的开发环境,它是基于IintelliJ IDEA,类似于Eclipse,Android Studio提供了集成的开发环境和调试,从整体上不论是开发的效率还是开发的便捷程度都是比Eclipse简洁方便很多。在程序的调试方面也远比Eclipse方便很多。
Android开发使用的是java+XML语言的方式。Java影响深远的面向对象编程语言。拥有着多种语言的特点,并且是跨平台的。因此java具有强大和简单易用两个特点。可以用来编写桌面应用程序、Web应用程序、分布式的系统和嵌入式的系统等。
XML是一种简单的可扩展标记语言。是SGML的一个子集合,也就是他的简化版本,非常适合与web应用的开发和其他数据源之间的数据交换。
1.仿照市面上常见的软件,使用底部与顶部导航栏结合,侧滑的方式实现新闻数据的展示
2.整体的页面布局使用的是RecycleView的嵌套的方式
3.底部的4个Fragment切换和在每个Fragment中的ViewPage切换, 采用的是LuckyJayce/ViewPagerIndicator的开源框架
4.新闻列表采用的是RecyclerView的方式
5.顶部的沉浸式的状态栏使参考此博客
6.新闻详情的实现采用的方法是通过Android自带的android.text.Html类解析Html和html下标签的图像
7.为数据的隐私和良好的用户体验在一般新闻客户端的基础上添加了登录注册模块以及切换主题等的功能。
1.对于网页html的解析有一些问题,导致分类模块的不稳定
2.由于解析的问题,有事刷新后没有显示相应信息
该设计实现了在手机端浏览新闻的应用程序。用户通过下载应用程序,进入注册应用程序可以在程序中浏览各种新闻。可以砸热点、体育等多个板块之间进行切换。程序通过网络和相关的协议从网络中获取新闻数据,通过程序的适配器和布局文件将数据进行展示。
用户通过注册登录的方式进入app中,然后对新闻进行浏览,可以对于浏览的主题进行切换,也可以通过menu浏览APP的相关介绍。在整体的布局上使用了底部菜案栏,上面分类栏的方式。利用适配器将页面和相对应的listitem适配茹相对应的文件中。对新闻进行展示。
程序划分为登录模块、主页模块、滑动模块和数据展示模块和其他模块。登录用户用户的登录还验证,同时具有不同用户的信息隐藏的功能。主页模块是对于数据的初步展示和其他滑动模块的门额进入接口。滑动模块用于新闻的分类和数据的切换。其他模块用于对用户的信息进行查看和对于程序的主题进行更改、查询程序的有关信息。数据是通过url连接来自网络的数据。经过处理显示在新闻客户端。
用户登录模块分为欢迎界面和用户登录模块,使用用户登录的作用是因为事先一个用户一个账号,对于软件的操作内容和日志进行保密。用户可以在登录界面进行账号和密码的输入然后登录。如果没有账号和秘密,可以点击“注册”按钮进行注册,然后登录。在用户没有注册的时候会提示不存在账号请先注册,注册的人员如果输入账号和密码错误则显示提示信息。
主要逻辑代码如下:
public class welcome extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
//getSupportActionBar().hide();
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_welcome);
Button welcome_button= (Button)findViewById(R.id.wecome_button);
final VideoView welcome_Videoview =(VideoView)findViewById(R.id.weclome_Viderview);
welcome_Videoview.setVideoURI(Uri.parse("android.resource://"+this.getPackageName()+"/"+R.raw.welcome));
welcome_Videoview.start();
welcome_Videoview.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
welcome_Videoview.start();
}
});
welcome_button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(welcome_Videoview.isPlaying()){
welcome_Videoview.stopPlayback();
}
Intent mIntent = new Intent(welcome.this, LoginActivity.class);
startActivity(mIntent);
}
});
}
}
登录主要代码:
btn_login.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (et_name.getText().toString().equals(user_name) && et_password.getText().toString().equals(password)) {
Intent intent = new Intent(LoginActivity.this, MainActivity.class);
startActivity(intent);
SharedPreferences.Editor editor = sp.edit();
editor.putString("user_name", user_name);
editor.putString("password", String.valueOf(password));
editor.commit();
} else {
Toast.makeText(LoginActivity.this, "用户名或密码错误", Toast.LENGTH_LONG).show();
} }});
主页面显示主要完成的是从用户登录跳转到主页面,同时在主页面显示。在主页面建立相应的按钮,完成侧滑和类型的转换,同时在没有滑到相应的位置的时候完成数据的提前加载。主页面是其他页面的前提,也是进入口。
主页面界面如图:
主页面的逻辑代码如下:
public class MainActivity extends AppCompatActivity {
private IndicatorViewPager indicatorViewPager;
private SystemBarTintManager tintManager;
private ViewPager tabmain_viewPager;
private LinearLayout main_learn;
private Indicator indicator;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initWindow();
setContentView(R.layout.activity_main);
SViewPager viewPager = (SViewPager) findViewById(R.id.tabmain_viewPager);
Indicator indicator = (Indicator) findViewById(R.id.tabmain_indicator);
indicatorViewPager = new IndicatorViewPager(indicator, viewPager);
indicatorViewPager.setAdapter(new MyAdapter(getSupportFragmentManager()));
// 禁止viewpager的滑动事件
viewPager.setCanScroll(false);
// 设置viewpager保留界面不重新加载的页面数量
viewPager.setOffscreenPageLimit(4);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
toolbar.setTitle(R.string.index_name);
setSupportActionBar(toolbar);
invalidateOptionsMenu();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@TargetApi(19)
private void initWindow() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
tintManager = new SystemBarTintManager(this);
tintManager.setStatusBarTintColor(getResources().getColor(R.color.tab_top_background));
tintManager.setStatusBarTintEnabled(true);
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
Intent intent = new Intent(MainActivity.this, SettingActivity.class);
startActivity(intent);
//return true;
}
if (id == R.id.action_settings_bg) {
//tabIcons = {R.style.AppTheme_Base};
main_learn = (LinearLayout) findViewById(R.id.main_learn);
main_learn.setBackground(Drawable.createFromPath("#DD2196F3"));
//return true;#673AB7 action_wholeday
}
if (id == R.id.action_wholeday) {
Intent intent = new Intent(MainActivity.this, MyInformatimActivity.class);
startActivity(intent);
//return true;#673AB7 action_wholeday
}
return super.onOptionsItemSelected(item);
}
private class MyAdapter extends IndicatorViewPager.IndicatorFragmentPagerAdapter {
private String[] tabNames = {"新闻", "阅读", "热点", "政要"};//, "我", R.drawable.maintab_5_selector
private int[] tabIcons = {R.drawable.maintab_1_selector, R.drawable.maintab_2_selector, R.drawable.maintab_3_selector,
R.drawable.maintab_4_selector, R.drawable.maintab_5_selector};
private LayoutInflater inflater;
public MyAdapter(FragmentManager fragmentManager) {
super(fragmentManager);
inflater = LayoutInflater.from(getApplicationContext());
}
@Override
public int getCount() {
return tabNames.length;
}
@Override
public View getViewForTab(int position, View convertView, ViewGroup container) {
if (convertView == null) {
convertView = inflater.inflate(R.layout.tab_main, container, false);
}
TextView textView = (TextView) convertView.findViewById(R.id.tv_tab_content);
textView.setText(tabNames[position]);
ImageView image = (ImageView) convertView.findViewById(R.id.iv_tab_img);
image.setImageResource(tabIcons[position]);
return convertView;
}
@Override
public Fragment getFragmentForPage(int position) {
Fragment mainFragment;
mainFragment = new FirstLayerFragment();
Bundle bundle = new Bundle();
bundle.putString(FirstLayerFragment.INTENT_STRING_TABNAME, tabNames[position]);
bundle.putInt(FirstLayerFragment.INTENT_INT_INDEX, position);
mainFragment.setArguments(bundle);
return mainFragment;
}
}
}
新闻展示部分是指在选中了相应的分类模块的新闻后点击相应的新闻的listitem部分之后会显示新闻的具体内容,这部分的实现是使用的Android中listview和适配器的使用部分。在对数据进行了处理之后再listitem中进行显示。
其他部分指的是在点击“个人中心”和右上方的下拉menu之后会展示相应的功能,包括了主题的切换功能和关于啊APP的介绍部分。
新闻详情展示页面和其他部分页面如图
适配器部分代码:
public class HorizontalImageRecyclerViewAdapter extends RecyclerView.Adapter implements View.OnTouchListener{
public HorizontalImageRecyclerViewAdapter(Context context, PhotoSet photoSet, RecyclerView recyclerView) {
mContext = context;
this.recyclerView = recyclerView;
mLayoutInflater = LayoutInflater.from(context);
this.photoSet = photoSet;
Resources r = context.getResources();
float leftAndRightMargin = r.getDimension(R.dimen.list_margin_left_and_right);//14px
float imageMargin = r.getDimension(R.dimen.list_margin_top_and_bottom);//20px
viewConfiguration = ViewConfiguration.get(context);
imageHeight = (int)r.getDimension(R.dimen.list_big_image_item_height);
imageWeight = (int)(MyApplication.width - (leftAndRightMargin + imageMargin) * 2) / 3;
}
public void setPhotoSet(PhotoSet photoSet) {
this.photoSet = photoSet;
}
@Override
public int getItemViewType(int position) {
return position == 0 ? 0 : position;
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, final int viewType) {
View hold = mLayoutInflater.inflate(R.layout.item_sub_image, parent, false);
this.parent = parent;
ImageViewHolder holder = new ImageViewHolder(hold, imageWeight, imageHeight, viewType);
holder.imageView.setTag(viewType);
holder.imageView.setOnTouchListener(this);
return holder;
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
if (photoSet == null || photoSet.getPhotos() == null) {
setNetworkImageView(((ImageViewHolder) holder).imageView, "");
} else {
setNetworkImageView(((ImageViewHolder) holder).imageView, NeteaseURLParse.parseWebpImageForTextAndImageType(photoSet.getPhotos().get(position).getTimgurl(), imageWeight));
}
}
@Override
public int getItemCount() {
return (photoSet == null || photoSet.getPhotos() == null) ? 3 : photoSet.getPhotos().size();
}
@Override
public boolean onTouch(View v, MotionEvent event) {
Log.d("HorizontalImage", "child onTouchEvent" + event.getAction());
long pressDuration = System.currentTimeMillis() - pressStartTime;
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: {
pressStartTime = System.currentTimeMillis();
pressedX = event.getX();
pressedY = event.getY();
isIntercept = false;
break;
}
case MotionEvent.ACTION_MOVE:
if (pressDuration <= ViewConfiguration.getJumpTapTimeout()
&& distance(pressedX, pressedY, event.getX(), event.getY()) <= viewConfiguration.getScaledTouchSlop()) {
} else {
isIntercept = true;
}
break;
case MotionEvent.ACTION_UP: {
if (pressDuration <= ViewConfiguration.getJumpTapTimeout()
&& distance(pressedX, pressedY, event.getX(), event.getY()) <= viewConfiguration.getScaledTouchSlop()) {
sendIntent(v);
} else {
isIntercept = true;
}
break;
}
}
return true;
}
本次的安卓开发课程设计收获颇丰。从整体上看Android课程设计不是很难,但是也不简单。不是很难是因为开发的环境、语言都是之前上安卓课的时候接触过的,学过的东西;也不简单是因为本次的课程设计整体上涉及了安卓开发的绝大部分的知识点内容。需要把学学的各大安卓的知识点实现在自己所写的项目中。、
从课设题目的选择到到布局的设计,图标的寻找、再到代码的逻辑实现和单元测试等各个部分都由个人完成。在这个过程中收获很多,但是也遇到了很多的问题。
关于收获,在课程设计的过程中,我从总体上从工程的角度对安卓开发有了很深一步的了解,整体上对安卓开发的流程进行了实践性的学习。同时学会使用了安卓相应的开发框架,例如,在本次的新闻客户端的开发中学会使用了ViewPagerIndicator的框架,对于数据的侧滑页面的数据浏览使用了slidermenu的框架。因为新闻端的数据是来自于网上,所以对于使用hppt协议获取数据的相应操作方法也有了一定的了解。同时也学会了使用侧滑等方法对app的页面进行布局。在之前的安卓上课过程中对于每一个知识点都是分开做实验的,所以对于整体的工程的理解没有那么深刻,对面面向对象编程有了更多的理解。
但是在开发的过程中也出现了很多的困惑与问题。
首先在设置侧滑页面实现侧滑后界面的转变,还有在设置导航栏模块的跳转的时候,在适配器的使用方面遇到了很多的问题,导致一直报错,
其次,对于网络上数据的存储和处理展示不是很理解,导致在开发的过程中花费了较多的时间在这一部分内容。在使用网络数据的时候,不会将数据转化,然后进行显示,出现了很多的问题,之后慢啊慢才解决。特别是寻找数据的尾部和起始位置花费了比较多的时间。
在使用适配器对导航栏的的pageview进行适配的时候也出现了一些问题,参数的传递出现问题,listitem不能正常显示等等,最后在重新学习有关适配器知识,理解了原理后重新编程,bug也随之解决了。课程设计也是磨炼性子的一种方式,为了做的更好看一点,我尝试了布局方面的方案,配色、选择图标图片等等,最后感觉不论是从布局还是从基本功能的实现都基本达到了自己的要求。
总之,本次的Android开发课程设计收获很大,我不仅巩固了之前上课学到的知识,而且在开发过程中遇到问题解决问题,在这个过程中又学到了很多的新东西,可以说是受益匪浅。