Android小项目——新闻APP

前言:

 在公司学习了一段时间Android知识,决定做一个小项目,目的是学会运用所学的基础知识,在这里记录一下开发历程,大家可以把它看成一款入门级练手的 Demo 应用吧~

项目概述:

类型:

新闻APP(低仿今日头条)

基本功能:

欢迎页面加载(3s,点击可跳过)——Activity相关

用户注册/登录 ——SQLite运用

横向滑动列表显示新闻类别——TabLayout、ViewPager、FragmentPagerAdapter的应用

底部菜单栏 切换——Fragment运用

–-主页(显示新闻列表)——ListView

–-设置(退出应用、退出登录、清空缓存)——Activity管理、SharePreference

–-我的(账号安全、新闻收藏夹)——SQLite

新闻列表下拉、上滑实现刷新——自定义ListView

逐条收藏新闻、删除新闻——SharePreference

仿UI界面——各类控件运用

点击查看新闻详情 —— WebView

用户界面更换头像功能——Android运行时权限、多媒体、Content Provider

 

源码及下载地址:

https://download.csdn.net/download/qq_34149526/10977199

PS:

最近有不少朋友反馈程序闪退问题,我查看了一下,是因为我采用的数据接口(天行数据)请求下来的数据中,图片链接的数据为空(之前一直是正常数据),导致解析图片时空指针异常,最终程序闪退。json数据如下:

{
	"code": 200,
	"msg": "success",
	"newslist": [{
		"ctime": "2019-07-18 00:00",
		"title": "空间科学卫星:迈向空间科学强国",
		"description": "新华科技",
		"picUrl": "",--------------->此处为空!!!
		"url": "http:\/\/www.xinhuanet.com\/tech\/2019-07\/18\/c_1124767044.htm"
	},
    ……
}

修改方法一:替换含有图片数据接口,可采用聚合数据等(使用自行百度),注意修改代码中的数据字段名!!!

修改方法二:在代码中解析图片的地方加上非空校验,程序不会崩溃,但是新闻列表中不会显示图片。

修改方法三:自行想办法解决~哈哈

下面简单贴一下修改方法二:

//针对以下几个类做非空校验,希望大家以我为鉴,养成良好编码习惯。

1、MyBitmapUtils.java:
public Bitmap getBitmap(String url) {
        if(TextUtils.isEmpty(url)){
            return null;
        }
        Bitmap bitmap;
     ……
}
2、HttpUtils.java:
public static Bitmap decodeUriAsBitmapFromNet(String imgUrl) {
        if(TextUtils.isEmpty(imgUrl)){
            return null;
        }
        URL fileUrl = null;
        Bitmap bitmap = null;
     ……
}
3、NewsAdapter.java:
@Override
public View getView(int position, View convertView, ViewGroup parent) {
     ……

     if(news.getNews_img()!=null) {
        viewHolder.newsImg.setImageBitmap(news.getNews_img());
     }
     ……
}
4、NetCacheUtils.java:
private Bitmap downLoadBitmap(String url) {
     ……
        } finally {
            if (conn != null) {
                conn.disconnect();
            }
        }
     ……
    }

        关于界面无法显示内容,原因是我申请的天行数据的API接口调用次数已用完(当时我是有10万次的免费调用次数,不得不感叹你们的强大),具体解决方法是更换TechFragment、MiliFragment、SportFragment、EnteFragment四个类里面的url地址,原地址已无法正常请求数据。可以自己去天行数据申请免费接口,替换即可(具体url格式参考天行数据官方文档,我已经很久不用它了)。

在这里我再贴出一位评论区小伙伴 “qq_41835735”给出的解决方案,给大家一个参考。

----------华丽分割线----------

下面进入重点,开始介绍这个项目

1、项目结构:

类文件:

资源文件:

2、主要功能及其代码实现:

欢迎页面:(持续时间为3s);

利用handler机制并开启一个线程,实现展示欢迎页面3s后页面跳转;

 final Message message = new Message();
    final Thread thread = new Thread(new Runnable() {
        @Override
        public void run() {
            try {
                Thread.sleep(3000);
                message.what = 1;
                handler.sendMessage(message);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    });

欢迎页面加载完毕后会判断是否有用户登录,若没有用户登录,会跳转到注册&登录页面

final Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            if (msg.what == 1) {
                //判断用户是否登录
                boolean userIsLogin = (boolean) SharedPreUtil.getParam(WelcomeActivity.this,
                        SharedPreUtil.IS_LOGIN, false);
                if (userIsLogin) {
                    Intent intent = new Intent(WelcomeActivity.this, MainActivity.class);
                    startActivity(intent);
                } else {
                    Intent intent = new Intent(WelcomeActivity.this, LoginOrRegisterActivity.class);
                    startActivity(intent);
                }

                finish();
            } else if (msg.what == 0) {
                thread.interrupt();
            }

        }

    };

 注册或登录页面:

             

 “注册”和“登陆”功能的实现主要是应用的SQLite数据库存储技术;

注册——存

SQLiteDatabase db = dbHelper.getWritableDatabase();

                    String username_str = username.getText().toString();
                    String userpassword_str = userpassword.getText().toString();
                    String repassword_str = repassword.getText().toString();

                    if (userpassword_str.equals(repassword_str)) {
                        ContentValues values = new ContentValues();
                        //组装数据
                        values.put("name", username_str);
                        values.put("password", userpassword_str);

                        db.insert("User", null, values);

                        startActivity(new Intent(RegisterActivity.this, LoginActivity.class));
                        finish();
                    }

登陆——取

 if (cursor.moveToFirst()) {
                        String userpassword_db = cursor.getString(cursor.getColumnIndex("password"));
                        if (userpassword_str.equals(userpassword_db)) {
                            SharedPreUtil.setParam(LoginActivity.this, SharedPreUtil.IS_LOGIN, true);
                            SharedPreUtil.setParam(LoginActivity.this, SharedPreUtil.LOGIN_DATA, username_str);
                            //user.setUsername(username_str);
                            //user.setPassword(userpassword_str);
                            Intent intent = new Intent(LoginActivity.this, MainActivity.class);
                            TimeCount.getInstance().setTime(System.currentTimeMillis());
                            startActivity(intent);
                            finish();
                        } else {
                            Toast.makeText(LoginActivity.this, "密码错误,请重新登录", Toast.LENGTH_SHORT).show();
                        }
                    }

另外在实现“注册”中上传头像功能时涉及到一个小知识点——运行时权限;因为要访问图库:

若用户不选择上传,程序会默认使用一个给定好的图片作为用户头像。

@Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        switch (requestCode) {
            case 1:
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    openAlbum();
                } else {
                    Toast.makeText(this, "You denied the permission", Toast.LENGTH_SHORT).show();
                }
                break;
        }
    }

    private void openAlbum() {
        Intent intent = new Intent("android.intent.action.GET_CONTENT");
        intent.setType("image/*");
        startActivityForResult(intent, CHOSSE_PHOTO);
    }

    @RequiresApi(api = Build.VERSION_CODES.KITKAT)
    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        switch (requestCode) {
            case CHOSSE_PHOTO:
                if (resultCode == -1) {
                    String imgPath = AlbumUtil.handleImageOnKitKat(this, data);
                    setHead(imgPath);
                }
                break;
            default:
                break;
        }
    }

用户注册登陆后,即进入主页面:默认为科技新闻,左右滑动即可切换新闻类别;

新闻列表的显示原理及ListView、数据源与Adapter三者相结合,呈现出该画面;

    final String url = "http://api.tianapi.com/keji/?key=7d829a4176fef4ad7409c2dc129905ed&num=30";
    private View view;
    private LoadListView mListView;
    private List<News> newsList;

    private NewsAdapter adapter;

其中数据源的获取涉及到了HTTPClient的GET请求网络资源以及解析json数据的相关知识;

 JSONObject jsonObject = new JSONObject(jsonData);
            JSONArray jsonArray = jsonObject.getJSONArray("newslist");
            for (int i = 0; i < 10; i++) {
                JSONObject json_news = jsonArray.getJSONObject(i);
                String imgUrl = json_news.getString("picUrl");
                /**
                 * 采取三级缓存策略加载图片
                 */

                Bitmap bitmap = myBitmapUtils.getBitmap(imgUrl); 
                String title = json_news.getString("title");
                String date = json_news.getString("ctime");
                String author_name = json_news.getString("description");
                String url = json_news.getString("url");
                Log.d(TAG, "url:*-*-*-*-*-*-*" + imgUrl);
                News news = new News(bitmap, title, url, imgUrl, date, author_name);
                newsList.add(news);

                getActivity().runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        adapter.notifyDataSetChanged();
                    }
                });

​​​​该页面同样实现了下拉&上滑刷新新闻的功能:

下拉刷新:

上滑加载: 

该功能具体实现请参考——ListView实现上拉加载&下拉刷新

删除新闻:

在新闻列表点击每条新闻中的×号可完成新闻删除。

 

@Override
    public void click(View view) {
        Toast.makeText(getContext(), "该新闻已删除!", Toast.LENGTH_SHORT).show();
        newsList.remove(Integer.parseInt(view.getTag().toString()));
        adapter.notifyDataSetChanged();
    }

为每一个ListView item设置一个鼠标监听器,在remove方法中传入item的索引位置即可完成新闻列表的删除。

 新闻详情页面:(及加载提示)

 

代码实现:

show_news.getSettings().setJavaScriptEnabled(true);
        Intent intent = getIntent();
        final String news_url = intent.getStringExtra("url");
        final String news_title = intent.getStringExtra("title");
        final String news_date = intent.getStringExtra("date");
        final String news_author = intent.getStringExtra("author");
        final String news_picurl = intent.getStringExtra("pic_url");
        show_news.loadUrl(news_url);

 

获得intent对象中由上一个页面传来的新闻URL,将WebView初始化后进行加载;完成页面详情的展示。

mDialog = new ProgressDialog(ShowNewsActivity.this);
        mDialog.setMessage("玩命加载ing");
        show_news.setWebViewClient(new WebViewClient() {
            //网页加载时的回调
            @Override
            public void onPageStarted(WebView view, String url, Bitmap favicon) {
                super.onPageStarted(view, url, favicon);
                if (!mDialog.isShowing()) {
                    mDialog.show();
                }
            }

            //网页停止加载时的回调
            @Override
            public void onPageFinished(WebView view, String url) {
                super.onPageFinished(view, url);
                // 如果没有显示,则显示
                if (mDialog.isShowing())
                    mDialog.dismiss();
            }
        });

实例化ProgressDialog对象,设置标题与提示信息,以对用户进行友好提示。

新闻收藏:

 

代码实现:

主要是利用SQLite存储整个收藏新闻信息;

collect_news.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                collect_news.setImageResource(R.drawable.favorite_selected);

                SQLiteDatabase db = helper.getWritableDatabase();

                ContentValues values = new ContentValues();
                //组装数据
                values.put("news_url", news_url);
                values.put("news_title", news_title);
                values.put("news_date", news_date);
                values.put("news_author", news_author);
                values.put("news_picurl", news_picurl);

                db.insert("Collection_News", null, values);

                db.close();

设置页面:

清空缓存:

因为在加载新闻列表时对新闻图片采取了三级缓存策略(网络,本地文件,内存),所以会产生一定的缓存,该功能会清理掉所有缓存;

代码实现:

 // 获取文件
    //Context.getExternalFilesDir() --> SDCard/Android/data/你的应用的包名/files/ 目录,一般放一些长时间保存的数据
    //Context.getExternalCacheDir() --> SDCard/Android/data/你的应用包名/cache/目录,一般存放临时缓存数据
    public static long getFolderSize(File file) throws Exception {
        long size = 0;
        try {
            File[] fileList = file.listFiles();
            for (int i = 0; i < fileList.length; i++) {
                // 如果下面还有文件
                if (fileList[i].isDirectory()) {
                    size = size + getFolderSize(fileList[i]);
                } else {
                    size = size + fileList[i].length();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return size;
    }

    /**
     * * 清除本应用内部缓存(/data/data/com.xxx.xxx/cache) * *
     *
     * @param context
     */
    public static void cleanInternalCache(Context context) {
        deleteFilesByDirectory(context.getCacheDir());
    }

退出应用:

用户点击后直接退出程序并返回桌面。

代码实现:

专门创建了一个用户维护所有活动(页面)的工具类,当用户点击退出按钮时实际调用exit方法,结束活动类表中每一个活动,并执行System.exit(0);退出。

public class ApplicationUtil extends Application {
    private List<Activity> mList = new LinkedList<Activity>();
    private static ApplicationUtil instance;

    private ApplicationUtil() {
    }

    public synchronized static ApplicationUtil getInstance() {
        if (instance == null) {
            instance = new ApplicationUtil();
        }
        return instance;
    }

    // 添加Activity到列表中维持
    public void addActivity(Activity activity) {
        mList.add(activity);
    }

    public void exit() {
        try {
            for (Activity activity : mList) {
                if (activity != null) {
                    activity.finish();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            System.exit(0);
        }
    }
}

我的:

账号安全:

该功能即修改用户基本信息;本质是对SQLite的应用;

收藏夹:列举曾收藏过的所有新闻;

 

----------华丽分割线----------

 

至此,项目介绍完毕。

 

  • 399
    点赞
  • 1837
    收藏
    觉得还不错? 一键收藏
  • 2220
    评论
### 回答1: 新闻app是一款基于Android平台的小型项目应用程序,它主要用于展示各类新闻内容,为用户提供便捷的阅读体验。该项目的源码包含了应用程序的基本框架和功能实现,方便开发者进行二次开发和定制。 新闻app的源码主要包含以下几个方面的内容: 1. 用户界面设计:源码中包含了新闻app的界面布局和样式,开发者可以根据自己的需要进行修改和美化。用户界面通常包括新闻列表、新闻详情页、分类标签等,开发者可以自由设计并添加其他功能模块。 2. 数据获取与展示:源码中实现了与服务器进行数据交互的功能,通过网络请求获取新闻数据,并在界面上展示出来。开发者可以根据需要修改数据请求接口和解析方式,实现与自己的服务器交互。 3. 新闻分类与搜索:源码中提供了新闻分类和搜索功能的实现,用户可以根据自己的兴趣和需求选择不同的新闻分类进行浏览,也可以通过搜索关键词进行精确定位。 4. 用户交互与分享:源码中包含了用户的登录注册功能和新闻内容的分享功能,用户可以通过登录账号进行个性化设置和收藏喜欢的新闻内容,也可以将新闻分享到社交媒体上与他人交流。 总之,新闻app源码是一个基础框架,开发者可以在此基础上进行二次开发和定制,根据自己的需求添加功能模块和美化界面,实现自己独特的新闻应用。 ### 回答2: Android新闻App是一个基于Android平台开发的小型项目,它的主要功能是提供最新的新闻内容给用户,并且用户可以进行浏览、搜索和分享等操作。下面是这个项目的一些关键特点和所需的源码组成部分: 1. 特点: - 用户界面友好,交互性强,提供舒适的浏览体验; - 支持实时更新,提供最新的新闻内容; - 具备搜索功能,方便用户查找感兴趣的新闻; - 支持新闻分享功能,方便用户将新闻分享给朋友; - 具备图文混排的能力,可以展示新闻的文字和图片。 2. 源码组成部分: - 主界面布局代码:定义了App的整体布局结构,包括顶部导航栏、底部工具栏和新闻显示区域等。 - 数据源代码:负责获取新闻数据,可以通过API接口获取最新的新闻内容,也可以从本地数据库获取已缓存的新闻数据。 - 新闻列表适配器代码:用于将新闻数据展示在界面上,包括标题、描述和图片等。 - 新闻详情界面代码:用于显示单篇新闻的详细内容,包括标题、正文和相关图片等。 - 搜索功能代码:实现了按关键字搜索新闻的功能,可以在已有的新闻数据中进行筛选。 - 分享功能代码:集成了社交媒体的分享SDK,方便用户将新闻内容分享给朋友。 - 图片加载和缓存代码:处理了新闻中的图片加载和本地缓存,提高了图片加载速度和用户体验。 通过以上的源码组成部分,可以完成一个基本的新闻App,用户可以在界面上浏览最新的新闻内容,进行搜索和分享操作。这个小项目可以帮助开发者理解Android开发框架和开发方式,提高编码能力和UI设计能力。 ### 回答3: 新闻app是基于Android平台开发的一个小型应用程序,可以提供用户各种最新的新闻资讯。以下是关于这个项目的源码介绍。 该项目源码主要由Java语言编写,使用了Android Studio作为开发工具。代码结构清晰,包含了主要的几个模块。 1. 用户界面模块:这个模块负责显示新闻列表和新闻详情等信息,主要包含布局文件和相应的逻辑代码。列表界面使用RecyclerView控件展示新闻列表,详情界面使用WebView展示新闻内容。 2. 网络请求模块:这个模块负责与后台服务器进行数据交互,使用了Android的HttpURLConnection类来发送请求和接收响应。请求参数可以根据实际需要进行修改,例如可以根据新闻类别进行请求。 3. 数据解析模块:这个模块负责解析从服务器返回的JSON格式的数据,转换成Java对象供应用程序使用。可以使用Android提供的JSON解析库,如Gson。 4. 数据存储模块:这个模块负责缓存新闻数据,以提高应用程序的响应速度。可以使用SharedPreferences或SQLite数据库来存储新闻数据。同时也可以使用图片缓存库,如Glide或Picasso来缓存新闻图片。 5. 用户交互模块:这个模块负责处理用户的交互行为,例如点击新闻列表项跳转到新闻详情界面,下拉刷新获取最新数据等。可以使用Android提供的相关控件和事件监听器来实现用户交互。 除了以上几个主要的模块,还可以根据需要添加其他功能,例如搜索栏、分享按钮等。 总体来说,这个新闻app的源码提供了一个完整的开发框架,初学者可以通过阅读和理解源码来学习Android应用程序的开发流程和一些常用技术。同时,也可以根据实际需求进行二次开发,添加新的功能和改进用户体验。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2220
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值