跟代码相关的工作,大多唯手熟尔,所以这里花了点时间做了款简易版的新闻 APP,虽然都是些基础的内容,不过还是可以加深自己对部分代码的理解。至少,可以加深自己的记忆


步骤


  1. 依赖库
  2. 网络请求
  3. 网络解析
  4. 界面布局
  5. 最后
  6. 运行界面
  7. 运行GIF
  8. 完整代码下载地址(github)

依赖库


过程中需要用到一些开源依赖库文件,先在 build.grade 中声明:

    compile 'com.google.code.gson:gson:2.8.0'       //网络解析compile 'com.squareup.okhttp3:okhttp:3.7.0'     //网络请求compile 'com.github.bumptech.glide:glide:3.8.0' //图片加载compile 'com.android.support:design:24.2.1'     //Material Design中用到的依赖库compile 'de.hdodenhof:circleimageview:2.1.0'    //显示圆形图片

网络请求


在包下创建一个文件夹 util 用来存放工具类,创建文件 HttpUtil.class 用来请求数据:

public class HttpUtil {public static void sendOkHttpRequest(String address, okhttp3.Callback callback){OkHttpClient client = new OkHttpClient();Request request = new Request.Builder().url(address).build();client.newCall(request).enqueue(callback);}
}

这里用到的是 okhttp3.Callback 的回调接口,结果会返回到 callback 的回调函数中,后面会进行处理


网络解析


我们先从数据解析开始,毕竟这才是这个小项目的重点。这次项目使用的数据来源是天行数据(http://www.tianapi.com/ )的新闻资讯 API ,先看 API 的说明:

可以看到返回数据为 JSON, 默认返回 10 条参数。请求地址为:

其中, APIKEY 需要用个人的 API KEY 代替,可以在个人中心中看到,其他的请求地址也是大同小异

JSON 返回示例:

还有错误返回码,用来判断返回数据的异常情况:

根据 gson 的返回示例,我们可以写出对应的实体类文件,通过 gson 将返回数据转化为对应的类型。先创建一个 gson 文件夹存放实体类文件。

在 gson 文件夹下创建 New.class 文件:

public class News {@SerializedName("ctime")public String time;public String title;public String description;public String picUrl;public String url;}

创建 NewsList.class 文件:

public class NewsList {public int code;public String msg;@SerializedName("newslist")public List<News> newsList ;}

至此,我们就已经创建好了与返回数据对应的实体类。

在 util 文件夹下创建文件 Utility.class 文件:

public class Utility {public static NewsList parseJsonWithGson(final String requestText){Gson gson = new Gson();return gson.fromJson(requestText, NewsList.class);}}

将请求得到的数据解析为 NewList 实体类对象。现在网络请求和解析都准备好了,就开始界面文件了


界面布局


修改 values 目录下的 styles.xml 文件:

<resources><!-- Base application theme. --><style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar"><!-- Customize your theme here. --><item name="colorPrimary">@color/colorPrimary</item><item name="colorPrimaryDark">@color/colorPrimary</item><item name="colorAccent">@color/colorAccent</item></style></resources>

修改通知栏颜色和标题栏颜色一样,是处于视觉统一的原因,也可以不修改(非必须)


主要采用的是 Material Design 的设计,整体布局采用的是滑动菜单,主界面内容为 ToolBar 和 ListView(这里为了方便,就直接使用),侧边栏内容为 NavigationView


主界面:
因为要用 ToolBar 替代 ActionBar, 我们先修改 values 下面的 styles 文件,修改主题为:

<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">

在layout 下创建 nav_header 文件

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="180dp"android:background="@color/colorPrimary"android:padding="10dp"><de.hdodenhof.circleimageview.CircleImageView
        android:id="@+id/icon_image"android:layout_width="80dp"android:layout_height="80dp"android:layout_centerInParent="true"android:src="@drawable/nav_icon" /><TextView
        android:id="@+id/username"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignParentBottom="true"android:text="https://github.com/lentitude"android:textColor="@color/color_White"android:textSize="14sp" /><TextView
        android:id="@+id/mail"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_above="@id/username"android:text="lentitude"android:textColor="@color/color_White"android:textSize="14sp" /></RelativeLayout>

这里在头部文件中放置了一个CircleImageView,两个 TextView,没有什么理解难度


在 res 目录下创建 menu 文件夹,新建 nav_menu.xml 文件:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"><group android:checkableBehavior="single"><itemandroid:id="@+id/nav_society"android:title="社会新闻" /><itemandroid:id="@+id/nav_county"android:title="国内新闻" /><itemandroid:id="@+id/nav_internation"android:title="国际新闻" /><itemandroid:id="@+id/nav_fun"android:title="娱乐新闻" /><itemandroid:id="@+id/nav_sport"android:title="体育新闻" /><itemandroid:id="@+id/nav_nba"android:title="NBA新闻" /><itemandroid:id="@+id/nav_football"android:title="足球新闻" /><itemandroid:id="@+id/nav_technology"android:title="科技新闻" /><itemandroid:id="@+id/nav_work"android:title="创业新闻" /><itemandroid:id="@+id/nav_apple"android:title="苹果新闻" /><itemandroid:id="@+id/nav_war"android:title="军事新闻" /><itemandroid:id="@+id/nav_internet"android:title="移动互联" /><itemandroid:id="@+id/nav_travel"android:title="旅游咨询" /><itemandroid:id="@+id/nav_health"android:title="健康知识" /><itemandroid:id="@+id/nav_strange"android:title="奇闻异事" /><itemandroid:id="@+id/nav_looker"android:title="美女图片" /><itemandroid:id="@+id/nav_vr"android:title="VR科技" /><itemandroid:id="@+id/nav_it"android:title="IT资讯" /></group>
</menu>

这里创建了若干个 ITEM 子项,只有 title,没有 icon,大家可以自行放置

主界面 activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayoutxmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"android:id="@+id/drawer_layout"android:layout_width="match_parent"android:layout_height="match_parent"><android.support.design.widget.CoordinatorLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"><android.support.design.widget.AppBarLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"><android.support.v7.widget.Toolbarandroid:id="@+id/tool_bar"android:layout_width="match_parent"android:layout_height="?attr/actionBarSize"app:contentInsetStart="0dp"app:titleTextColor="@color/color_White"android:background="@color/colorPrimary"/></android.support.design.widget.AppBarLayout><android.support.v4.widget.SwipeRefreshLayoutandroid:id="@+id/swipe_layout"android:layout_width="match_parent"android:layout_height="match_parent"app:layout_behavior="@string/appbar_scrolling_view_behavior"><ListViewandroid:id="@+id/list_view"android:layout_width="match_parent"android:layout_height="match_parent"android:divider="@color/color_Background"android:dividerHeight="1dp"/></android.support.v4.widget.SwipeRefreshLayout></android.support.design.widget.CoordinatorLayout><android.support.design.widget.NavigationViewandroid:id="@+id/nav_view"android:layout_width="match_parent"android:layout_height="match_parent"android:layout_gravity="start"app:headerLayout="@layout/nav_header"app:menu="@menu/nav_menu"/></android.support.v4.widget.DrawerLayout>

因为是一步到位,所以……大家最好之前用过使用过相同的布局设计(比如:第一行代码)

DrawerLayout 中有两个直接子布局文件:
1. CoordinatorLayout:一种 FrameLayout, 作为显示主界面内容的最外层布局
2. NavigationView:作为显示侧边栏的最外层布局,不过已经封装好了,可以直接通过 app:headerLayout 和 app:menu 属性引用之前我们已经写好的 头部和菜单布局文件

CoordinatorLayout 中有两个直接子布局文件:
1. AppBarLayout :通过 AppBarLayout 属性,可以将 ToolBar 和 ListView 分隔开,可以对滚动事件进行响应,实现 Material 效果
2. SwipeRefreshLayout:用来刷新 ListView 中的内容

创建 list_view_item.xml 文件,设计 ListView 的子项布局:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="100dp"android:background="@color/color_White"><RelativeLayout
        android:layout_width="match_parent"android:layout_height="match_parent"android:layout_margin="10dp"><ImageView
            android:id="@+id/title_pic"android:layout_width="80dp"android:layout_height="60dp"android:layout_centerVertical="true"android:layout_alignParentRight="true"android:scaleType="centerCrop"/><TextView
            android:id="@+id/title_text"android:layout_width="wrap_content"android:layout_height="wrap_content"android:textSize="16sp"android:layout_marginRight="10dp"android:layout_alignTop="@+id/title_pic"android:layout_alignParentLeft="true"android:layout_toLeftOf="@+id/title_pic"/><TextView
            android:id="@+id/descr_text"android:layout_width="wrap_content"android:layout_height="wrap_content"android:textSize="8sp"android:layout_marginRight="10dp"android:layout_alignBottom="@+id/title_pic"android:layout_alignParentLeft="true"/></RelativeLayout></RelativeLayout>

子项布局内包含 3 个控件,ImageView 显示返回的图片,TextView 显示返回的标题和出处

创建一个 Title.class类:

public class Title {private String title;private String descr;private String imageUrl;private String uri;public Title(String title,String descr, String imageUrl, String uri){this.title = title;this.imageUrl = imageUrl;this.descr = descr;this.uri = uri;}public String getTitle() {return title;}public String getImageUrl() {return imageUrl;}public String getDescr() {return descr;}public String getUri() {return uri;}
}

这里之所以除了 标题,出处,图片显示在 ListViw 中,uri 传入另一个布局,显示内容文件

接下来就是 TitleAdapter.class

public class TitleAdapter extends ArrayAdapter<Title> {private int resourceId;public TitleAdapter(@NonNull Context context, @LayoutRes int resource, @NonNull List<Title> objects) {super(context, resource, objects);resourceId = resource;}@NonNull@Overridepublic View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {Title title = getItem(position);View view;ViewHolder viewHolder;/*** 缓存布局和实例,优化 listView*/if (convertView == null){view = LayoutInflater.from(getContext()).inflate(resourceId,parent,false);viewHolder = new ViewHolder();viewHolder.titleText = (TextView)view.findViewById(R.id.title_text);viewHolder.titlePic = (ImageView) view.findViewById(R.id.title_pic);viewHolder.titleDescr = (TextView)view.findViewById(R.id.descr_text);view.setTag(viewHolder);}else{view = convertView;viewHolder = (ViewHolder) view.getTag();}Glide.with(getContext()).load(title.getImageUrl()).into(viewHolder.titlePic);viewHolder.titleText.setText(title.getTitle());viewHolder.titleDescr.setText(title.getDescr());return view;}public class ViewHolder{TextView titleText;TextView titleDescr;ImageView titlePic;}
}

这里还是一样的老套路,通过convertView 来缓存布局,通过类 ViewHolder 缓存控件实例,这样做,可以节省 50% 的效率,所以还是按照老套路走吧。

接下来就是 Activity 文件 MainActivity.class:

public class MainActivity extends AppCompatActivity {private static final int  ITEM_SOCIETY= 1;private static final int  ITEM_COUNTY= 2;private static final int  ITEM_INTERNATION= 3;private static final int  ITEM_FUN= 4;private static final int  ITEM_SPORT= 5;private static final int  ITEM_NBA= 6;private static final int  ITEM_FOOTBALL= 7;private static final int  ITEM_TECHNOLOGY= 8;private static final int  ITEM_WORK= 9;private static final int  ITEM_APPLE= 10;private static final int  ITEM_WAR= 11;private static final int  ITEM_INTERNET= 12;private static final int  ITEM_TREVAL= 13;private static final int  ITEM_HEALTH= 14;private static final int  ITEM_STRANGE= 15;private static final int  ITEM_LOOKER= 16;private static final int  ITEM_VR= 17;private static final int  ITEM_IT= 18;private List<Title> titleList = new ArrayList<Title>();private ListView listView;private TitleAdapter adapter;private NavigationView navigationView;private DrawerLayout drawerLayout;private SwipeRefreshLayout refreshLayout;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Toolbar toolbar = (Toolbar)findViewById(R.id.tool_bar);setSupportActionBar(toolbar);final ActionBar actionBar = getSupportActionBar();if (actionBar != null){actionBar.setDisplayHomeAsUpEnabled(true);actionBar.setHomeAsUpIndicator(R.drawable.ic_menu);}actionBar.setDisplayShowTitleEnabled(true);actionBar.setTitle("社会新闻");refreshLayout = (SwipeRefreshLayout)findViewById(R.id.swipe_layout);refreshLayout.setColorSchemeColors(getResources().getColor(R.color.colorPrimary));listView = (ListView)findViewById(R.id.list_view);adapter = new TitleAdapter(this,R.layout.list_view_item, titleList);listView.setAdapter(adapter);listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {Intent intent = new Intent(MainActivity.this, ContentActivity.class);@Overridepublic void onItemClick(AdapterView<?> parent, View view, int position, long id) {Title title = titleList.get(position);intent.putExtra("title",actionBar.getTitle());intent.putExtra("uri",title.getUri());startActivity(intent);}});drawerLayout = (DrawerLayout)findViewById(R.id.drawer_layout);navigationView = (NavigationView)findViewById(R.id.nav_view);navigationView.setCheckedItem(R.id.nav_society);navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {@Overridepublic boolean onNavigationItemSelected(@NonNull MenuItem item) {switch (item.getItemId()){case R.id.nav_society:handleCurrentPage("社会新闻",ITEM_SOCIETY);break;case R.id.nav_county:handleCurrentPage("国内新闻",ITEM_COUNTY);break;case R.id.nav_internation:handleCurrentPage("国际新闻",ITEM_INTERNATION);break;case R.id.nav_fun:handleCurrentPage("娱乐新闻",ITEM_FUN);break;case R.id.nav_sport:handleCurrentPage("体育新闻",ITEM_SPORT);break;case R.id.nav_nba:handleCurrentPage("NBA新闻",ITEM_NBA);break;case R.id.nav_football:handleCurrentPage("足球新闻",ITEM_FOOTBALL);break;case R.id.nav_technology:handleCurrentPage("科技新闻",ITEM_TECHNOLOGY);break;case R.id.nav_work:handleCurrentPage("创业新闻",ITEM_WORK);break;case R.id.nav_apple:handleCurrentPage("苹果新闻",ITEM_APPLE);break;case R.id.nav_war:handleCurrentPage("军事新闻",ITEM_WAR);break;case R.id.nav_internet:handleCurrentPage("移动互联",ITEM_INTERNET);break;case R.id.nav_travel:handleCurrentPage("旅游资讯",ITEM_TREVAL);break;case R.id.nav_health:handleCurrentPage("健康知识",ITEM_HEALTH);break;case R.id.nav_strange:handleCurrentPage("奇闻异事",ITEM_STRANGE);break;case R.id.nav_looker:handleCurrentPage("美女图片",ITEM_LOOKER);break;case R.id.nav_vr:handleCurrentPage("VR科技",ITEM_VR);break;case R.id.nav_it:handleCurrentPage("IT资讯",ITEM_IT);break;default:break;}drawerLayout.closeDrawers();return true;}});refreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {@Overridepublic void onRefresh() {refreshLayout.setRefreshing(true);int itemName = parseString((String)actionBar.getTitle());requestNew(itemName);}});requestNew(ITEM_SOCIETY);}/***  判断是否是当前页面,如果不是则 请求处理数据*/private void handleCurrentPage(String text, int item){ActionBar actionBar = getSupportActionBar();if (!text.equals(actionBar.getTitle().toString())){actionBar.setTitle(text);requestNew(item);refreshLayout.setRefreshing(true);}}/*** 请求处理数据*/public void requestNew(int itemName){// 根据返回到的 URL 链接进行申请和返回数据String address = response(itemName);    // keyHttpUtil.sendOkHttpRequest(address, new Callback() {@Overridepublic void onFailure(Call call, IOException e) {runOnUiThread(new Runnable() {@Overridepublic void run() {Toast.makeText(MainActivity.this, "新闻加载失败", Toast.LENGTH_SHORT).show();}});}@Overridepublic void onResponse(Call call, Response response) throws IOException {final String responseText = response.body().string();final NewsList newlist = Utility.parseJsonWithGson(responseText);final int code = newlist.code;final String msg = newlist.msg;if (code == 200){titleList.clear();for (News news:newlist.newsList){Title title = new Title(news.title,news.description,news.picUrl, news.url);titleList.add(title);}runOnUiThread(new Runnable() {@Overridepublic void run() {adapter.notifyDataSetChanged();listView.setSelection(0);refreshLayout.setRefreshing(false);};});}else{runOnUiThread(new Runnable() {@Overridepublic void run() {Toast.makeText(MainActivity.this, "数据错误返回",Toast.LENGTH_SHORT).show();refreshLayout.setRefreshing(false);}});}}});}/*** 输入不同的类型选项,返回对应的 URL 链接*/private String response(int itemName){String address = "https://api.tianapi.com/social/?key=339a8b166f397f008236e596616a5f54&num=50&rand=1";switch(itemName){case ITEM_SOCIETY:break;case ITEM_COUNTY:address = address.replaceAll("social","guonei");break;case ITEM_INTERNATION:address = address.replaceAll("social","world");break;case ITEM_FUN:address = address.replaceAll("social","huabian");break;case ITEM_SPORT:address = address.replaceAll("social","tiyu");break;case ITEM_NBA:address = address.replaceAll("social","nba");break;case ITEM_FOOTBALL:address = address.replaceAll("social","football");break;case ITEM_TECHNOLOGY:address = address.replaceAll("social","keji");break;case ITEM_WORK:address = address.replaceAll("social","startup");break;case ITEM_APPLE:address = address.replaceAll("social","apple");break;case ITEM_WAR:address = address.replaceAll("social","military");break;case ITEM_INTERNET:address = address.replaceAll("social","mobile");break;case ITEM_TREVAL:address = address.replaceAll("social","travel");break;case ITEM_HEALTH:address = address.replaceAll("social","health");break;case ITEM_STRANGE:address = address.replaceAll("social","qiwen");break;case ITEM_LOOKER:address = address.replaceAll("social","meinv");break;case ITEM_VR:address = address.replaceAll("social","vr");break;case ITEM_IT:address = address.replaceAll("social","it");break;default:}return address;}/*** 通过 actionbar.getTitle() 的参数,返回对应的 ItemName*/private int parseString(String text){if (text.equals("社会新闻")){return ITEM_SOCIETY;}if (text.equals("国内新闻")){return ITEM_COUNTY;}if (text.equals("国际新闻")){return ITEM_INTERNATION;}if (text.equals("娱乐新闻")){return ITEM_FUN;}if (text.equals("体育新闻")){return ITEM_SPORT;}if (text.equals("NBA新闻")){return ITEM_NBA;}if (text.equals("足球新闻")){return ITEM_FOOTBALL;}if (text.equals("科技新闻")){return ITEM_TECHNOLOGY;}if (text.equals("创业新闻")){return ITEM_WORK;}if (text.equals("苹果新闻")){return ITEM_APPLE;}if (text.equals("军事新闻")){return ITEM_WAR;}if (text.equals("移动互联")){return ITEM_INTERNET;}if (text.equals("旅游资讯")){return ITEM_TREVAL;}if (text.equals("健康知识")){return ITEM_HEALTH;}if (text.equals("奇闻异事")){return ITEM_STRANGE;}if (text.equals("美女图片")){return ITEM_LOOKER;}if (text.equals("VR科技")){return ITEM_VR;}if (text.equals("IT资讯")){return ITEM_IT;}return ITEM_SOCIETY;}/*** 对侧边栏按钮进行处理,打开侧边栏*/@Overridepublic boolean onOptionsItemSelected(MenuItem item) {switch (item.getItemId()){case android.R.id.home:drawerLayout.openDrawer(GravityCompat.START);break;default:}return true;}/*** 对返回键进行处理,如果侧边栏打开则关闭侧边栏,否则关闭 activity*/@Overridepublic void onBackPressed() {if(drawerLayout.isDrawerOpen(GravityCompat.START)){drawerLayout.closeDrawers();}else{finish();}}
}

本文的代码量虽然很大,只是比较繁琐,因为需要根据点击的 ITEM 来对不同的 接口地址提出申请,大部分的函数功能都有进行注释,所以略过了

public void requestNew(int itemName){// 根据返回到的 URL 链接进行申请和返回数据String address = response(itemName);    // keyHttpUtil.sendOkHttpRequest(address, new Callback() {@Overridepublic void onFailure(Call call, IOException e) {runOnUiThread(new Runnable() {@Overridepublic void run() {Toast.makeText(MainActivity.this, "新闻加载失败", Toast.LENGTH_SHORT).show();}});}@Overridepublic void onResponse(Call call, Response response) throws IOException {final String responseText = response.body().string();final NewsList newlist = Utility.parseJsonWithGson(responseText);final int code = newlist.code;final String msg = newlist.msg;if (code == 200){titleList.clear();for (News news:newlist.newsList){Title title = new Title(news.title,news.description,news.picUrl, news.url);titleList.add(title);}runOnUiThread(new Runnable() {@Overridepublic void run() {adapter.notifyDataSetChanged();listView.setSelection(0);refreshLayout.setRefreshing(false);};});}else{runOnUiThread(new Runnable() {@Overridepublic void run() {Toast.makeText(MainActivity.this, "数据错误返回",Toast.LENGTH_SHORT).show();refreshLayout.setRefreshing(false);}});}}});}
  1. 外部调用时传入 itemName 参数,通过 response() 函数得到所需要请求数据的地址
  2. 通过sendOkHttpRequest() 回调方法,在返回数据成功的 onResponse() 方法中使用 parseJsonWithGson() 方法获取对应的实体类
  3. 将实体类中的数据添加到 Title对应中,将 Title 对象添加到 titleList 中,最后通过 runOnUiThread() 方法,切换到主线程提醒适配器进行数据更新。

至此,主界面的代码逻辑都已经处理好了,还有 ListView 子项布局的点击事件处理:

listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {Intent intent = new Intent(MainActivity.this, ContentActivity.class);@Overridepublic void onItemClick(AdapterView<?> parent, View view, int position, long id) {Title title = titleList.get(position);intent.putExtra("title",actionBar.getTitle());intent.putExtra("uri",title.getUri());startActivity(intent);}});

在点击 ListView 子项布局时,会传入 标题栏文本 和 内容 URL

文件 activity_content.xml:

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayoutxmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"android:layout_width="match_parent"android:layout_height="match_parent"android:background="@color/color_White"><android.support.design.widget.AppBarLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"><android.support.v7.widget.Toolbarandroid:id="@+id/tool_bar"android:layout_width="match_parent"android:layout_height="?attr/actionBarSize"app:titleTextColor="@color/color_White"app:theme="@style/ThemeOverlay.AppCompat.Light"app:layout_scrollFlags="enterAlways|snap|scroll"/></android.support.design.widget.AppBarLayout><WebViewandroid:id="@+id/web_view"android:layout_width="match_parent"android:layout_height="match_parent"app:layout_behavior="@string/appbar_scrolling_view_behavior"/></android.support.design.widget.CoordinatorLayout>

如果了解了 activity_main.xml 的布局,这个布局也就没什么难度了,主要是新增了 WebView 控件,用来显示传入的 URL

文件 ContentActivity.class:

public class ContentActivity extends AppCompatActivity {private WebView webView;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_content);Toolbar toolbar = (Toolbar)findViewById(R.id.tool_bar);setSupportActionBar(toolbar);ActionBar actionBar = getSupportActionBar();if (actionBar != null){actionBar.setDisplayHomeAsUpEnabled(true);actionBar.setHomeAsUpIndicator(R.drawable.ic_back);}webView = (WebView)findViewById(R.id.web_view);webView.getSettings().setJavaScriptEnabled(true);webView.setWebViewClient(new WebViewClient());String uri = getIntent().getStringExtra("uri");String title = getIntent().getStringExtra("title");actionBar.setDisplayShowTitleEnabled(true);actionBar.setTitle(title);webView.loadUrl(uri);}/*** 点击返回键做了处理*/@Overridepublic boolean onOptionsItemSelected(MenuItem item) {switch (item.getItemId()){case android.R.id.home:finish();break;default:}return true;}
}

显示传入的 URL网址


最后


到这里就结束了 ? 如果你认为都结束了,那你可以就需要面对打开应用之后马上闪退的情况了…….权限

我们还没有对权限进行申请,在 AndroidManifest 文件中添加声明:

<uses-permission android:name="android.permission.INTERNET"/>

不过个人还是建议把 权限的考虑放在最先的优先级,毕竟养成这个习惯,就可以专注于代码的 bug…………………..


运行界面



(主界面)
(侧边栏)
(内容界面)


运行 GIF



(由于大小限制,所以就只能传这么大了)


完整代码下载地址


https://github.com/lentitude/NewsMD

Android 实践:做一款新闻 APP相关推荐

  1. Android 做一款直播APP?一分钟掌握乐视云直播Demo

    最近工作需要做一款直播APP,恩是的,从RTMP协议的实现开始到处理服务器高并发.负载均衡.客户端播放器实现等等等..... 估计全部写完我也到而立之年了吧23333...... BOSS们估计也是发 ...

  2. Android安卓期末大作业 新闻app 实现注册登录增删改查功能

    Android安卓期末大作业 新闻app (文末附下载链接) app情况如下图所示: 点我下载 https://download.csdn.net/download/weixin_43474701/7 ...

  3. 【Android】做一款类似我要当学霸里的学习监督的APP

    我要当学霸这款App有个学习监督的功能,当你启动它的时候,你将无法使用其他App,以此达到帮助人提高自觉性,起到监督学习的效果.最近和同学做了个小App,正好有这个功能,所以就来说说它是怎么实现的. ...

  4. 练习项目 一款新闻app的开发 (二) : 新闻首页开发(整体UI架构)

    下面主要整理下关于新闻首页的开发,最终效果图如下 本节主要先说下关于标题顶部栏和导航栏的UI处理,主要用到知识点有: 1.CoordinatorLayout : 用来协调子view. 具体详细描述,可 ...

  5. android学习的app,Android相见恨晚的6款学习APP,每天坚持学习,提升自我

    学习对每个人来说都是非常重要的,因为不停的学习不停的进步才能让自己变得更好,要知道天才都是通过努力换来的,没有人生下来就是天才,所以我们也要努力去学习.今天就给大家分享6个实用学习类的APP. 1.中 ...

  6. Android Compose——一个简单的新闻APP

    Owl 简述 效果视频 导航 导航结点 路线图 底部导航栏 使用 标签页 状态切换 FeaturePage 构建 CoursePage 实现 搜索 ViewModel View 详情页 Detail ...

  7. Android 实践:做一款可用的天气 APP

    可能很多人会问:之前已经写过一篇博文来介绍怎么做一款简单的新闻APP(http://blog.csdn.net/yiwei12/article/details/71249628),为什么还要专门一篇来 ...

  8. html+css+js+Hbuilder开发一款安卓APP,根本不用学Android开发!

    我们知道,要做一款安卓APP,咱们得先学安卓开发语言,例如java,前端后端.那么没有这些开发语言基础,咱们怎么做呢?其实现在有比较好的开发方案就是做webAPP,咱们可以用web前端知识构建安卓客户 ...

  9. html如何在手机上实现hb,html+css+js+Hbuilder开发一款安卓APP,根本不用学Android开发!...

    我碎前整要们开自近事端个广的的带近事端个广们知道,要做一款安卓APP,咱们得先学安卓开发语言,例如java,前端后端.那么没有这些开发语言基础,咱们怎么做呢?其实现在有比较好的开发方案就是做webAP ...

最新文章

  1. 链接访问后刷新颜色回到初始_如何使链接可访问(提示:颜色不够)
  2. Handler的源码分析
  3. linux 标准函数注释,Linux 驱动程序中相关函数注释汇总(跟新中)
  4. 485通讯线是几芯的_RS485通讯线是几芯电缆
  5. 可视化信息论(2015年10月14日)
  6. 计算机网络体系结构中的环节,ppt课件-第二章计算机网络体系结构.ppt
  7. 帧同步(LockStep)该如何反外挂 及 优化
  8. 软件可靠性测试意义,软件可靠性测试方法与目的
  9. File.ReadAllText读取文件中文乱码
  10. 什么句型可以 让我说出 悲伤的文法
  11. CAD批量打图精灵入门教程--CAD批量打印、CAD批量转PDF
  12. 广东理工学院c语言考试试卷,20年广东理工学院成人高考期末考试 C语言程序设计 复习资料(15页)-原创力文档...
  13. 阿里云ECS云服务器Linux Tomcat启动慢 访问网页转圈
  14. mac搭建IPV6网络环境
  15. 网页无插件视频流媒体播放器EasyPlayerPro-IOS版如何解决有声音无画面的问题?
  16. pos 机 gd32f103 midi设备
  17. Computer Vision笔记01:图像处理
  18. ACM算法训练【贪心合集】
  19. PNP与NPN两种三极管使用方法
  20. 错误集(大概会持续更新)

热门文章

  1. Linux 基本使用和 web 程序部署
  2. 安卓录屏软件实现 开维PRA自动生成代码Ctrl.js
  3. 无符号格式化输出的区别%d,%u?
  4. 攀登规模化的高峰 - 蚂蚁集团大规模 Sigma 集群 ApiServer 优化实践
  5. arxiv数据_使用neo4j第1部分分析arxiv数据
  6. Python PyCharm Django 搭建web开发环境
  7. 17 重定向(Redirect) vs 转发(Forward)
  8. Cypher语句-Create语句
  9. Ceph 存储集群5-数据归置
  10. SMPL:数据增强之处理pose和3d点