├── .gitignore
├── .idea
├── encodings.xml
├── misc.xml
├── modules.xml
├── runConfigurations.xml
└── vcs.xml
├── LICENSE
├── README.md
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── example
│ │ └── viewnews
│ │ └── ExampleInstrumentedTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── assets
│ │ └── litepal.xml
│ ├── java
│ │ └── com
│ │ │ └── example
│ │ │ └── viewnews
│ │ │ ├── MainActivity.java
│ │ │ ├── NewsBean.java
│ │ │ ├── NewsCollectBean.java
│ │ │ ├── NewsFragment.java
│ │ │ ├── NewsInfoBean.java
│ │ │ ├── TabAdapter.java
│ │ │ ├── WebActivity.java
│ │ │ ├── tools
│ │ │ ├── ActivityCollector.java
│ │ │ ├── BaseActivity.java
│ │ │ └── DataCleanManager.java
│ │ │ └── usermodel
│ │ │ ├── Article.java
│ │ │ ├── ArticleActivity.java
│ │ │ ├── ArticleAdapter.java
│ │ │ ├── ArticleDetailActivity.java
│ │ │ ├── EditArticleActivity.java
│ │ │ ├── FavoriteNewsListAdapter.java
│ │ │ ├── LoginActivity.java
│ │ │ ├── RegisterActivity.java
│ │ │ ├── UserDetailActivity.java
│ │ │ ├── UserFavoriteActivity.java
│ │ │ └── UserInfo.java
│ └── res
│ │ ├── drawable-v24
│ │ └── ic_launcher_foreground.xml
│ │ ├── drawable-xxhdpi
│ │ ├── avatar.jpg
│ │ ├── ic_checked.png
│ │ ├── ic_clear.png
│ │ ├── ic_delete.png
│ │ ├── ic_edit_article.png
│ │ ├── ic_exit.png
│ │ ├── ic_menu.png
│ │ ├── ic_return_left.png
│ │ ├── ic_share.png
│ │ ├── ic_star_border_favourite_no.png
│ │ ├── ic_star_border_favourite_yes.png
│ │ ├── ic_uncheck.png
│ │ ├── ic_vertical_align_top.png
│ │ ├── nav_articles.png
│ │ ├── nav_clear_cache.png
│ │ ├── nav_edit.png
│ │ ├── nav_favorite.png
│ │ ├── nav_personinfo.png
│ │ ├── nav_publish.png
│ │ ├── nav_settings.png
│ │ ├── nav_switch.png
│ │ └── no_login_avatar.png
│ │ ├── drawable
│ │ └── ic_launcher_background.xml
│ │ ├── layout
│ │ ├── activity_article.xml
│ │ ├── activity_article_detail.xml
│ │ ├── activity_edit_article.xml
│ │ ├── activity_login.xml
│ │ ├── activity_main.xml
│ │ ├── activity_register.xml
│ │ ├── activity_user_detail.xml
│ │ ├── activity_user_favorite.xml
│ │ ├── activity_web.xml
│ │ ├── item_article.xml
│ │ ├── item_favorite_news.xml
│ │ ├── item_layout01.xml
│ │ ├── item_layout02.xml
│ │ ├── item_layout03.xml
│ │ ├── nav_header.xml
│ │ └── news_list.xml
│ │ ├── menu
│ │ ├── nav_menu.xml
│ │ ├── tool_webbottom.xml
│ │ ├── toolbar.xml
│ │ └── toolbar_webview.xml
│ │ ├── mipmap-anydpi-v26
│ │ ├── ic_launcher.xml
│ │ └── ic_launcher_round.xml
│ │ ├── mipmap-hdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-mdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxhdpi
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_foreground.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxxhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ └── values
│ │ ├── colors.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── test
│ └── java
│ └── com
│ └── example
│ └── viewnews
│ └── ExampleUnitTest.java
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── resultImage
├── articledetail.jpeg
├── clearcache.jpeg
├── collectionlist.jpeg
├── editarticle.jpeg
├── editnickanme.jpeg
├── feedback.jpeg
├── login.jpeg
├── myarticle.jpeg
├── personalinfo.jpeg
├── register.jpeg
└── viewpage.jpeg
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | # Built application files
2 | *.apk
3 | *.ap_
4 |
5 | # Files for the ART/Dalvik VM
6 | *.dex
7 |
8 | # Java class files
9 | *.class
10 |
11 | # Generated files
12 | bin/
13 | gen/
14 | out/
15 |
16 | # Gradle files
17 | .gradle/
18 | build/
19 |
20 | # Local configuration file (sdk path, etc)
21 | local.properties
22 |
23 | # Proguard folder generated by Eclipse
24 | proguard/
25 |
26 | # Log Files
27 | *.log
28 |
29 | # Android Studio Navigation editor temp files
30 | .navigation/
31 |
32 | # Android Studio captures folder
33 | captures/
34 |
35 | # IntelliJ
36 | *.iml
37 | .idea/workspace.xml
38 | .idea/tasks.xml
39 | .idea/gradle.xml
40 | .idea/assetWizardSettings.xml
41 | .idea/dictionaries
42 | .idea/libraries
43 | .idea/caches
44 |
45 | # Keystore files
46 | # Uncomment the following line if you do not want to check your keystore files in.
47 | #*.jks
48 |
49 | # External native build folder generated in Android Studio 2.2 and later
50 | .externalNativeBuild
51 |
52 | # Google Services (e.g. APIs or Firebase)
53 | google-services.json
54 |
55 | # Freeline
56 | freeline.py
57 | freeline/
58 | freeline_project_description.json
59 |
60 | # fastlane
61 | fastlane/report.xml
62 | fastlane/Preview.html
63 | fastlane/screenshots
64 | fastlane/test_output
65 | fastlane/readme.md
66 |
--------------------------------------------------------------------------------
/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # viewnews
2 | 安卓课设开发项目-看点新闻App
3 | 演示传送门:[av79880165](https://www.bilibili.com/video/av79880165/)
4 |
5 | ## 项目运行效果图
6 |
7 | 

8 | 

9 | 
10 |
11 | 
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 29
5 | buildToolsVersion "29.0.2"
6 | defaultConfig {
7 | applicationId "com.example.viewnews"
8 | minSdkVersion 15
9 | targetSdkVersion 29
10 | versionCode 1
11 | versionName "1.0"
12 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
13 | }
14 | buildTypes {
15 | release {
16 | minifyEnabled false
17 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
18 | }
19 | }
20 | }
21 |
22 | dependencies {
23 | implementation fileTree(dir: 'libs', include: ['*.jar'])
24 | implementation 'androidx.appcompat:appcompat:1.1.0'
25 | implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
26 |
27 | // 添加NavigationView控件的依赖库
28 | implementation 'com.google.android.material:material:1.0.0'
29 |
30 | //添加图片圆形化控件的依赖库
31 | implementation 'de.hdodenhof:circleimageview:2.1.0'
32 |
33 | // 添加recyclerview控件的依赖库
34 | implementation 'androidx.recyclerview:recyclerview:1.1.0'
35 |
36 | // 添加GSON库的依赖
37 | implementation 'com.google.code.gson:gson:2.8.5'
38 |
39 | //添加LitePal数据存储依赖
40 | implementation 'org.litepal.android:java:3.0.0'
41 |
42 | //添加Glide处理图片库的依赖
43 | implementation 'com.github.bumptech.glide:glide:3.7.0'
44 |
45 | // 添加Material Dialogs弹窗美化的依赖库
46 | // core版:可以创建basic, list, single/multi choice, progress, input等弹框。
47 | implementation 'com.afollestad.material-dialogs:core:0.9.6.0'
48 |
49 | // 添加第3方弹出窗
50 | implementation 'com.github.f0ris.sweetalert:library:1.6.2'
51 |
52 | // 引入卡片式布局的依赖库
53 | implementation 'androidx.cardview:cardview:1.0.0'
54 |
55 | implementation 'androidx.annotation:annotation:1.1.0'
56 | implementation 'androidx.lifecycle:lifecycle-extensions:2.1.0'
57 | testImplementation 'junit:junit:4.12'
58 | androidTestImplementation 'androidx.test:runner:1.2.0'
59 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
60 | }
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/example/viewnews/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.example.viewnews;
2 |
3 | import android.content.Context;
4 |
5 | import androidx.test.InstrumentationRegistry;
6 | import androidx.test.runner.AndroidJUnit4;
7 |
8 | import org.junit.Test;
9 | import org.junit.runner.RunWith;
10 |
11 | import static org.junit.Assert.*;
12 |
13 | /**
14 | * Instrumented test, which will execute on an Android device.
15 | *
16 | * @see Testing documentation
17 | */
18 | @RunWith(AndroidJUnit4.class)
19 | public class ExampleInstrumentedTest {
20 | @Test
21 | public void useAppContext() {
22 | // Context of the app under test.
23 | Context appContext = InstrumentationRegistry.getTargetContext();
24 |
25 | assertEquals("com.example.viewnews", appContext.getPackageName());
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
29 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/app/src/main/assets/litepal.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/viewnews/NewsCollectBean.java:
--------------------------------------------------------------------------------
1 | package com.example.viewnews;
2 |
3 | import org.litepal.crud.LitePalSupport;
4 |
5 | // 新闻收藏列表
6 | public class NewsCollectBean extends LitePalSupport {
7 | // 用户账号
8 | private String userIdNumer;
9 | // 新闻id
10 | private String newsId;
11 | // 新闻标题
12 | private String newSTitle;
13 | // 新闻连接
14 | private String newsUrl;
15 |
16 | public String getUserIdNumer() {
17 | return userIdNumer;
18 | }
19 |
20 | public void setUserIdNumer(String userIdNumer) {
21 | this.userIdNumer = userIdNumer;
22 | }
23 |
24 | public String getNewsId() {
25 | return newsId;
26 | }
27 |
28 | public void setNewsId(String newsId) {
29 | this.newsId = newsId;
30 | }
31 |
32 |
33 | public String getNewSTitle() {
34 | return newSTitle;
35 | }
36 |
37 | public void setNewSTitle(String newSTitle) {
38 | this.newSTitle = newSTitle;
39 | }
40 |
41 | public String getNewsUrl() {
42 | return newsUrl;
43 | }
44 |
45 | public void setNewsUrl(String newsUrl) {
46 | this.newsUrl = newsUrl;
47 | }
48 |
49 | @Override
50 | public String toString() {
51 | return "NewsCollectBean{" +
52 | "userIdNumer='" + userIdNumer + '\'' +
53 | ", newsId='" + newsId + '\'' +
54 | ", newSTitle='" + newSTitle + '\'' +
55 | ", newsUrl='" + newsUrl + '\'' +
56 | '}';
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/viewnews/NewsFragment.java:
--------------------------------------------------------------------------------
1 | package com.example.viewnews;
2 |
3 | import android.annotation.SuppressLint;
4 | import android.content.Intent;
5 | import android.os.AsyncTask;
6 | import android.os.Bundle;
7 | import android.os.Handler;
8 | import android.os.Message;
9 | import android.util.Log;
10 | import android.view.LayoutInflater;
11 | import android.view.View;
12 | import android.view.ViewGroup;
13 | import android.widget.AdapterView;
14 | import android.widget.ListView;
15 |
16 | import androidx.annotation.NonNull;
17 | import androidx.annotation.Nullable;
18 | import androidx.fragment.app.Fragment;
19 | import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
20 |
21 | import com.google.android.material.floatingactionbutton.FloatingActionButton;
22 | import com.google.gson.Gson;
23 |
24 | import org.litepal.LitePal;
25 |
26 | import java.io.BufferedReader;
27 | import java.io.IOException;
28 | import java.io.InputStream;
29 | import java.io.InputStreamReader;
30 | import java.net.HttpURLConnection;
31 | import java.net.MalformedURLException;
32 | import java.net.ProtocolException;
33 | import java.net.URL;
34 | import java.util.ArrayList;
35 | import java.util.List;
36 |
37 | //每个tab下的碎片Fragment
38 | public class NewsFragment extends Fragment {
39 | //新闻列表
40 | private ListView newsListView;
41 | //下拉刷新
42 | private SwipeRefreshLayout swipeRefreshLayout;
43 | //新闻子项
44 | private List contentItems = new ArrayList<>();
45 |
46 | private static final int UPNEWS_INSERT = 0;
47 |
48 | //用来保存当前tab的名字
49 | private String currentTabName = "top";
50 |
51 | //分页查询参数,每页显示10条新闻数据
52 | private int pageNo = 0, pageSize = 10;
53 |
54 | //每一个Fragment页面都有一个浮动按钮,用于快速回到顶部
55 | private FloatingActionButton fab;
56 |
57 | //添加此注解的原理:https://blog.csdn.net/androidsj/article/details/79865091
58 | @SuppressLint("HandlerLeak")
59 | private Handler newsHandler = new Handler() {
60 | //主线程
61 | @Override
62 | public void handleMessage(Message msg) {
63 | switch (msg.what) {
64 | case UPNEWS_INSERT:
65 | //从服务器来获取NewsBean数据
66 | //Log.d("从服务器来获取NewsBean数据", "handleMessage: " + msg.obj);
67 | contentItems = ((NewsBean) msg.obj).getResult().getData();
68 | //构造一个适配器来填充新闻列表
69 | TabAdapter adapter = new TabAdapter(getActivity(), contentItems);
70 | newsListView.setAdapter(adapter);
71 | //当adapter中的数据被更改后必须马上调用notifyDataSetChanged予以更新。
72 | adapter.notifyDataSetChanged();
73 | //从服务器获取的数据缓存到本地数据库,注意去重插入的数据
74 | NewsInfoBean newsInfo;
75 | for (int i = 0, len = contentItems.size(); i < len; ++i) {
76 | newsInfo = new NewsInfoBean(contentItems.get(i));
77 | //测试是否请求的数据有重复
78 | //List beans = LitePal.where("uniquekey = ?", contentItems.get(i).getUniquekey()).find(NewsInfoBean.class);
79 | //Log.d("请求数据后", "handleMessage: " + beans.size());
80 | //将数据缓存到本地数据库
81 | newsInfo.save();
82 | }
83 | break;
84 | default:
85 | break;
86 | }
87 | }
88 | };
89 |
90 | //创建Fragment被添加到活动中时回调,且只会被调用一次
91 | @Override
92 | public void onCreate(@Nullable Bundle savedInstanceState) {
93 | super.onCreate(savedInstanceState);
94 | }
95 |
96 | //每次创建,绘制该Fragment的View组件时回调,将显示的View返回
97 | @Nullable
98 | @Override
99 | public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
100 | //加载新闻列表
101 | View view = inflater.inflate(R.layout.news_list, container, false);
102 | //获取每个实例之后,返回当前视图
103 | newsListView = (ListView) view.findViewById(R.id.newsListView);
104 | //tv = (TextView) view.findViewById(R.id.text_response);
105 | fab = (FloatingActionButton) view.findViewById(R.id.fab);
106 | swipeRefreshLayout = (SwipeRefreshLayout) view.findViewById(R.id.swipe_refresh);
107 | return view;
108 | }
109 |
110 | //当NewsFragment所在的Activity启动完成后调用,声明周期紧接在onCreateView()之后
111 | //使用此注解的讲解:https://blog.csdn.net/androidsj/article/details/79865091
112 | //@SuppressLint("HandlerLeak")
113 | @Override
114 | public void onActivityCreated(@Nullable Bundle savedInstanceState) {
115 | super.onActivityCreated(savedInstanceState);
116 | //getActivity():获得Fragment依附的Activity对象。(具体讲解:https://blog.csdn.net/y874961524/article/details/53773095)
117 | //getActivity()和onAttach()结合使用的生命周期相关讲解:https://blog.csdn.net/u013446591/article/details/72730767
118 | //getActivity()为空的情况(API<23时并不会去调用此方法),讲解1:https://blog.csdn.net/u012811342/article/details/80493352
119 | //讲解2:https://blog.csdn.net/qq_31010739/article/details/83348085
120 | //onAttach(getActivity());//该方法已弃用,查看源码即可
121 | onAttach(getContext());
122 | Log.d("上下文:", "Context: " + getContext());
123 | Log.d("NewsFragment", "Activity: " + getActivity());
124 | Bundle bundle = getArguments();
125 | //获取键对应的值,参数2表示默认填充的值,其用法和Intent差不多,但又有区别
126 | //data = bundle.getString("name", "top");
127 | //tv.setText(data);
128 | final String category = bundle.getString("name", "top");
129 | currentTabName = category;
130 | Log.d("点击tab小标题为:", "onActivityCreated: " + category);
131 | //实现置顶功能
132 | fab.setOnClickListener(new View.OnClickListener() {
133 | @Override
134 | public void onClick(View v) {
135 | //滚动到第一个可见的item位置,下标为0,具体讲解:https://www.jianshu.com/p/a5cd3cff2f1b
136 | newsListView.smoothScrollToPosition(0);
137 | }
138 | });
139 | //实现下拉刷新的功能
140 | //设置下拉刷新进度条的颜色
141 | swipeRefreshLayout.setColorSchemeResources(R.color.colorRed);
142 | //实现下拉刷新的监听器
143 | swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
144 | @Override
145 | public void onRefresh() {
146 | threadLoaderData(category);
147 | }
148 | });
149 |
150 | //异步加载数据,传入条目
151 | getDataFromNet(category);
152 |
153 | // 轻度按监听新闻列表子项
154 | newsListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
155 | @Override
156 | public void onItemClick(AdapterView> parent, View view, int position, long id) {
157 | Log.d("子项的数据为", "onItemClick: " + contentItems.get(position));
158 | //获取点击条目的路径,传值显示WebView页面
159 | String url = contentItems.get(position).getUrl();
160 | Log.d("当前新闻子项的连接是:", "onItemClick: " + url);
161 | String uniquekey = contentItems.get(position).getUniquekey();
162 | String newsTitle = contentItems.get(position).getTitle();
163 | Intent intent = new Intent(getActivity(), WebActivity.class);
164 | intent.putExtra("pageUrl", url);
165 | intent.putExtra("uniquekey", uniquekey);
166 | intent.putExtra("news_title", newsTitle);
167 | System.out.println("当前账号2222222222222:" + MainActivity.currentUserId);
168 | startActivity(intent);
169 | }
170 | });
171 | }
172 |
173 | private void threadLoaderData(final String category) {
174 | new Thread(new Runnable() {
175 | @Override
176 | public void run() {
177 | try {
178 | //沉睡1.5s,本地刷新很快,以防看不到刷新效果
179 | Thread.sleep(1500);
180 | } catch (InterruptedException e) {
181 | e.printStackTrace();
182 | }
183 | //若快速点击tab,则会出现getActivity()为空的情况,但是第一次加载肯定不会出错,所以将要拦截,以防app崩溃
184 | if (getActivity() == null)
185 | return;
186 | //此处的用法:runOnUiThread必须是在主线程中调用,getActivity()获取主线程所在的活动,切换子线程到主线程
187 | getActivity().runOnUiThread(new Runnable() {
188 | @Override
189 | public void run() {
190 | //重新生成数据,传入tab条目
191 | loaderRefreshData(category);
192 | //表示刷新事件结束,并隐藏刷新进度条
193 | swipeRefreshLayout.setRefreshing(false);
194 | }
195 | });
196 | }
197 | }).start();
198 | }
199 |
200 | //加载数据,实现从本地数据库中读取数据刷新到newsListView的适配器中
201 | private void loaderRefreshData(final String category) {
202 | //top,shehui,guonei,guoji,yule,tiyu,junshi,keji,caijing,shishang
203 | String categoryName = "头条";
204 | if (category.equals("top")) {
205 | categoryName = "头条";
206 | } else if (category.equals("shehui")) {
207 | categoryName = "社会";
208 | } else if (category.equals("guonei")) {
209 | categoryName = "国内";
210 | } else if (category.equals("guoji")) {
211 | categoryName = "国际";
212 | } else if (category.equals("yule")) {
213 | categoryName = "娱乐";
214 | } else if (category.equals("tiyu")) {
215 | categoryName = "体育";
216 | } else if (category.equals("junshi")) {
217 | categoryName = "军事";
218 | } else if (category.equals("keji")) {
219 | categoryName = "科技";
220 | } else if (category.equals("caijing")) {
221 | categoryName = "财经";
222 | } else if (category.equals("shishang")) {
223 | categoryName = "时尚";
224 | }
225 | //页数加1
226 | ++pageNo;
227 | List dataBeanList = new ArrayList<>();
228 | NewsBean.ResultBean.DataBean bean = null;
229 | int offsetV = (pageNo - 1) * pageSize;
230 | Log.d("pageNo", "页数为: " + pageNo);
231 | Log.d("offsetV", "偏移量为: " + offsetV);
232 | Log.d("offsetV", "以下开始查询");
233 | List beanList = LitePal.where("category = ?", categoryName).limit(pageSize).offset(offsetV).find(NewsInfoBean.class);
234 | Log.d("TAG", "查询的数量为:" + beanList.size());
235 | //若查询的结果为0,则重新定位页数为1
236 | if (beanList.size() == 0) {
237 | pageNo = 1;
238 | offsetV = (pageNo - 1) * pageSize;
239 | beanList = LitePal.where("category = ?", categoryName).limit(pageSize).offset(offsetV).find(NewsInfoBean.class);
240 | Log.d("分页查询", "loaderRefreshData: 已经超过最大页数,归零并重新查询!");
241 | }
242 | Log.d("刷新查到的数据大小", "run: " + beanList.size());
243 | for (int i = 0, len = beanList.size(); i < len; ++i) {
244 | bean = new NewsBean.ResultBean.DataBean();
245 | bean.setDataBean(beanList.get(i));
246 | dataBeanList.add(bean);
247 | Log.d("刷新id:", "run: " + beanList.get(i));
248 | }
249 | contentItems = dataBeanList;
250 | //将dataBeanList赋值给全局的contentItems,否则点击新闻子项会出错,并且contentItems之前要清空,不然起不到更新视图的作用
251 | TabAdapter adapter = new TabAdapter(getActivity(), contentItems);
252 | newsListView.setAdapter(adapter);
253 | //当adapter中的数据被更改后必须马上调用notifyDataSetChanged予以更新。
254 | adapter.notifyDataSetChanged();
255 | }
256 |
257 | //异步消息处理机制
258 | private void getDataFromNet(final String data) {
259 | @SuppressLint("StaticFieldLeak")
260 | AsyncTask task = new AsyncTask() {
261 | //子线程
262 | @Override //储备key:547ee75ef186fc55a8f015e38dcfdb9a
263 | protected String doInBackground(Void... params) { // 自己的key:af2d37d2ed31f7a074f1d49b5460a0b5,可以替换下面请求中的key
264 | String path = "http://v.juhe.cn/toutiao/index?type=" + data + "&key=af2d37d2ed31f7a074f1d49b5460a0b5";
265 | URL url = null;
266 | try {
267 | url = new URL(path);
268 | HttpURLConnection connection = (HttpURLConnection) url.openConnection();
269 | //设置请求方式
270 | connection.setRequestMethod("GET");
271 | //设置读取超时的毫秒数
272 | connection.setReadTimeout(5000);
273 | //设置连接超时时间
274 | connection.setConnectTimeout(5000);
275 | //获取状态码
276 | int responseCode = connection.getResponseCode();
277 | if (responseCode == HttpURLConnection.HTTP_OK) { // 200
278 | //获取服务器返回的输入流
279 | InputStream inputStream = connection.getInputStream();
280 | String json = streamToString(inputStream, "utf-8");
281 | //返回任务的执行结果
282 | return json;
283 | } else {
284 | //返回的状态码不是200
285 | System.out.println(responseCode);
286 | return 404 + data;
287 | }
288 | } catch (MalformedURLException e) {
289 | e.printStackTrace();
290 | } catch (ProtocolException e) {
291 | e.printStackTrace();
292 | } catch (IOException e) {
293 | e.printStackTrace();
294 | }
295 | return 404 + data;
296 | }
297 |
298 | //当给后台任务执行完毕并通过return语句返回时,此方法将被调用,返回来的数据可以进行一些UI操作,并将处理的参数传入
299 | protected void onPostExecute(final String result) {
300 | new Thread(new Runnable() {
301 | @Override
302 | public void run() {
303 | //查看状态码是否为200,若不是(开子线程),然后从本地加载相应的数据
304 | NewsBean newsBean = null;
305 | //不包括endIndex
306 | Log.d("后台处理的数据为:", "run: " + result);
307 | if (!result.substring(0, 3).equals("404")) {
308 | newsBean = new Gson().fromJson(result, NewsBean.class);
309 | System.out.println(newsBean.getError_code());
310 | if ("0".equals("" + newsBean.getError_code())) {
311 | //obtainmessage()方法是从消息池中拿来一个msg,不需要另开辟空间new,new需要重新申请,效率低,obtianmessage可以循环利用;
312 | Message msg = newsHandler.obtainMessage();
313 | msg.what = UPNEWS_INSERT;
314 | msg.obj = newsBean;
315 | //发送一个通知来填充数据,因为安卓不允许在子线程中进行UI操作
316 | newsHandler.sendMessage(msg);
317 | } else {
318 | //{"resultcode":"112","reason":"超过每日可允许请求次数!","result":null,"error_code":10012}
319 | //实现从数据库加载数据
320 | Log.d("超过请求次数或者其他原因", "run: 现在从本地数据库中获取");
321 | Log.d("当前tab名字为:", "run: " + currentTabName);
322 | threadLoaderData(currentTabName);
323 | }
324 | } else {
325 | threadLoaderData(result.substring(3));
326 | }
327 | }
328 | }).start();
329 | }
330 |
331 | //当后台任务中调用了publishProgress(Progress...)方法后,onProgressUpdate方法很快被执行
332 | @Override
333 | protected void onProgressUpdate(Void... values) {
334 | super.onProgressUpdate(values);
335 | }
336 | };
337 | //启动异步加载任务
338 | task.execute();
339 | }
340 |
341 | //输入流转化成字符串
342 | private String streamToString(InputStream inputStream, String charset) {
343 | try {
344 | //创建一个使用命名字符集的InputStreamReader。 InputStreamReader(InputStream in, String charsetName)
345 | InputStreamReader inputStreamReader = new InputStreamReader(inputStream, charset);
346 | //构造一个字符输入流对象
347 | BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
348 | String s = null;
349 | StringBuilder builder = new StringBuilder();
350 | while ((s = bufferedReader.readLine()) != null) {
351 | builder.append(s);
352 | }
353 | //关闭流
354 | bufferedReader.close();
355 | inputStreamReader.close();
356 | return builder.toString();
357 | } catch (IOException e) {
358 | e.printStackTrace();
359 | }
360 | return null;
361 | }
362 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/viewnews/NewsInfoBean.java:
--------------------------------------------------------------------------------
1 | package com.example.viewnews;
2 |
3 | import org.litepal.crud.LitePalSupport;
4 |
5 | public class NewsInfoBean extends LitePalSupport {
6 |
7 | private String uniquekey;
8 | private String title;
9 | private String date;
10 | private String category;
11 | private String author_name;
12 | private String url;
13 | private String thumbnail_pic_s;
14 | private String thumbnail_pic_s02;
15 | private String thumbnail_pic_s03;
16 |
17 | public NewsInfoBean(NewsBean.ResultBean.DataBean dataBean) {
18 | this.uniquekey = dataBean.getUniquekey();
19 | this.title = dataBean.getTitle();
20 | this.date = dataBean.getDate();
21 | this.category = dataBean.getCategory();
22 | this.author_name = dataBean.getAuthor_name();
23 | this.url = dataBean.getUrl();
24 | this.thumbnail_pic_s = dataBean.getThumbnail_pic_s();
25 | this.thumbnail_pic_s02 = dataBean.getThumbnail_pic_s02();
26 | this.thumbnail_pic_s03 = dataBean.getThumbnail_pic_s03();
27 | }
28 |
29 | public String getUniquekey() {
30 | return uniquekey;
31 | }
32 |
33 | public void setUniquekey(String uniquekey) {
34 | this.uniquekey = uniquekey;
35 | }
36 |
37 | public String getTitle() {
38 | return title;
39 | }
40 |
41 | public void setTitle(String title) {
42 | this.title = title;
43 | }
44 |
45 | public String getDate() {
46 | return date;
47 | }
48 |
49 | public void setDate(String date) {
50 | this.date = date;
51 | }
52 |
53 | public String getCategory() {
54 | return category;
55 | }
56 |
57 | public void setCategory(String category) {
58 | this.category = category;
59 | }
60 |
61 | public String getAuthor_name() {
62 | return author_name;
63 | }
64 |
65 | public void setAuthor_name(String author_name) {
66 | this.author_name = author_name;
67 | }
68 |
69 | public String getUrl() {
70 | return url;
71 | }
72 |
73 | public void setUrl(String url) {
74 | this.url = url;
75 | }
76 |
77 | public String getThumbnail_pic_s() {
78 | return thumbnail_pic_s;
79 | }
80 |
81 | public void setThumbnail_pic_s(String thumbnail_pic_s) {
82 | this.thumbnail_pic_s = thumbnail_pic_s;
83 | }
84 |
85 | public String getThumbnail_pic_s02() {
86 | return thumbnail_pic_s02;
87 | }
88 |
89 | public void setThumbnail_pic_s02(String thumbnail_pic_s02) {
90 | this.thumbnail_pic_s02 = thumbnail_pic_s02;
91 | }
92 |
93 | public String getThumbnail_pic_s03() {
94 | return thumbnail_pic_s03;
95 | }
96 |
97 | public void setThumbnail_pic_s03(String thumbnail_pic_s03) {
98 | this.thumbnail_pic_s03 = thumbnail_pic_s03;
99 | }
100 |
101 | @Override
102 | public String toString() {
103 | return "NewsInfoBean{" +
104 | "uniquekey='" + uniquekey + '\'' +
105 | ", title='" + title + '\'' +
106 | ", date='" + date + '\'' +
107 | ", category='" + category + '\'' +
108 | ", author_name='" + author_name + '\'' +
109 | ", url='" + url + '\'' +
110 | ", thumbnail_pic_s='" + thumbnail_pic_s + '\'' +
111 | ", thumbnail_pic_s02='" + thumbnail_pic_s02 + '\'' +
112 | ", thumbnail_pic_s03='" + thumbnail_pic_s03 + '\'' +
113 | '}';
114 | }
115 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/viewnews/TabAdapter.java:
--------------------------------------------------------------------------------
1 | package com.example.viewnews;
2 |
3 | import android.content.Context;
4 |
5 | import android.view.View;
6 | import android.view.ViewGroup;
7 | import android.widget.BaseAdapter;
8 | import android.widget.ImageView;
9 | import android.widget.TextView;
10 |
11 | import com.bumptech.glide.Glide;
12 | import com.bumptech.glide.load.engine.DiskCacheStrategy;
13 |
14 | import java.util.List;
15 |
16 | //自定义新闻列表的适配器
17 | public class TabAdapter extends BaseAdapter {
18 |
19 | private List list;
20 |
21 | private Context context;
22 |
23 | //设置正常加载图片的个数
24 | private int IMAGE_01 = 0;
25 |
26 | private int IMAGE_02 = 1;
27 |
28 | private int IMAGE_03 = 2;
29 |
30 | private int VIEW_COUNT = 3;
31 |
32 | public TabAdapter(Context context, List list) {
33 | this.context = context;
34 | this.list = list;
35 | }
36 |
37 | @Override
38 | public int getCount() {
39 | return list.size();
40 | }
41 |
42 | @Override
43 | public Object getItem(int position) {
44 | return list.get(position);
45 | }
46 |
47 | @Override
48 | public long getItemId(int position) {
49 | return position;
50 | }
51 |
52 | //得到不同item的总数
53 | @Override
54 | public int getViewTypeCount() {
55 | return VIEW_COUNT;
56 | }
57 |
58 | //得到当前新闻子项item的类型
59 | @Override
60 | public int getItemViewType(int position) {
61 | if (list.get(position).getThumbnail_pic_s() != null &&
62 | list.get(position).getThumbnail_pic_s02() != null &&
63 | list.get(position).getThumbnail_pic_s03() != null) {
64 | return IMAGE_03;
65 | } else if (list.get(position).getThumbnail_pic_s() != null &&
66 | list.get(position).getThumbnail_pic_s02() != null) {
67 | return IMAGE_02;
68 | }
69 | return IMAGE_01;
70 | }
71 |
72 | //提升ListView的运行效率,参数convertView用于将之前加载好的布局进行缓存,以便以后可以重用:https://blog.csdn.net/xiao_ziqiang/article/details/50812471
73 | @Override
74 | public View getView(int position, View convertView, ViewGroup parent) {
75 | if (getItemViewType(position) == IMAGE_01) {
76 | Image01_ViewHolder holder;
77 | if (convertView == null) {
78 | convertView = View.inflate(context, R.layout.item_layout01, null);
79 | holder = new Image01_ViewHolder();
80 | //查找控件
81 | holder.author_name = (TextView) convertView.findViewById(R.id.author_name);
82 | holder.title = (TextView) convertView.findViewById(R.id.title);
83 | holder.image = (ImageView) convertView.findViewById(R.id.image);
84 |
85 | convertView.setTag(holder);
86 | } else {
87 | holder = (Image01_ViewHolder) convertView.getTag();
88 | }
89 |
90 | //获取数据重新赋值
91 | holder.title.setText(list.get(position).getTitle());
92 | holder.author_name.setText(list.get(position).getAuthor_name());
93 |
94 | /**
95 | * DiskCacheStrategy.NONE: 表示不缓存任何内容。
96 | */
97 | Glide.with(context)
98 | .load(list.get(position).getThumbnail_pic_s())
99 | .diskCacheStrategy(DiskCacheStrategy.NONE)
100 | .placeholder(R.mipmap.ic_launcher)
101 | .error(R.mipmap.ic_launcher)
102 | .into(holder.image);
103 |
104 |
105 | } else if (getItemViewType(position) == IMAGE_02) {
106 | Image02_ViewHolder holder;
107 | if (convertView == null) {
108 | convertView = View.inflate(context, R.layout.item_layout02, null);
109 | holder = new Image02_ViewHolder();
110 | //查找控件
111 | holder.image001 = (ImageView) convertView.findViewById(R.id.image001);
112 | holder.image002 = (ImageView) convertView.findViewById(R.id.image002);
113 | holder.title = (TextView) convertView.findViewById(R.id.title);
114 | //将ViewHolder对象存储在View中
115 | convertView.setTag(holder);
116 |
117 | } else {
118 | holder = (Image02_ViewHolder) convertView.getTag();
119 | }
120 | //获取数据重新赋值
121 | holder.title.setText(list.get(position).getTitle());
122 | Glide.with(context)
123 | .load(list.get(position).getThumbnail_pic_s())
124 | .diskCacheStrategy(DiskCacheStrategy.NONE)
125 | .placeholder(R.mipmap.ic_launcher)
126 | .error(R.mipmap.ic_launcher)
127 | .into(holder.image001);
128 |
129 | Glide.with(context)
130 | .load(list.get(position).getThumbnail_pic_s02())
131 | .diskCacheStrategy(DiskCacheStrategy.NONE)
132 | .placeholder(R.mipmap.ic_launcher)
133 | .error(R.mipmap.ic_launcher)
134 | .into(holder.image002);
135 |
136 | } else {
137 | Image03_ViewHolder holder;
138 | if (convertView == null) {
139 | convertView = View.inflate(context, R.layout.item_layout03, null);
140 | holder = new Image03_ViewHolder();
141 | //查找控件
142 | holder.image01 = (ImageView) convertView.findViewById(R.id.image01);
143 | holder.image02 = (ImageView) convertView.findViewById(R.id.image02);
144 | holder.image03 = (ImageView) convertView.findViewById(R.id.image03);
145 | holder.title = (TextView) convertView.findViewById(R.id.title);
146 | convertView.setTag(holder);
147 | } else {
148 | holder = (Image03_ViewHolder) convertView.getTag();
149 | }
150 | //获取数据重新赋值
151 | holder.title.setText(list.get(position).getTitle());
152 |
153 | Glide.with(context)
154 | .load(list.get(position).getThumbnail_pic_s())
155 | .diskCacheStrategy(DiskCacheStrategy.NONE)
156 | .placeholder(R.mipmap.ic_launcher)
157 | .error(R.mipmap.ic_launcher)
158 | .into(holder.image01);
159 |
160 | Glide.with(context)
161 | .load(list.get(position).getThumbnail_pic_s02())
162 | .diskCacheStrategy(DiskCacheStrategy.NONE)
163 | .placeholder(R.mipmap.ic_launcher)
164 | .error(R.mipmap.ic_launcher)
165 | .into(holder.image02);
166 |
167 | Glide.with(context)
168 | .load(list.get(position).getThumbnail_pic_s03())
169 | .diskCacheStrategy(DiskCacheStrategy.NONE)
170 | .placeholder(R.mipmap.ic_launcher)
171 | .error(R.mipmap.ic_launcher)
172 | .into(holder.image03);
173 |
174 | }
175 | return convertView;
176 | }
177 |
178 | //新增3个内部类
179 | class Image01_ViewHolder {
180 | TextView title, author_name;
181 | ImageView image;
182 | }
183 |
184 | class Image02_ViewHolder {
185 | TextView title;
186 | ImageView image001, image002;
187 | }
188 |
189 | class Image03_ViewHolder {
190 | TextView title;
191 | ImageView image01, image02, image03;
192 | }
193 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/viewnews/WebActivity.java:
--------------------------------------------------------------------------------
1 | package com.example.viewnews;
2 | import androidx.appcompat.app.ActionBar;
3 | import androidx.appcompat.widget.Toolbar;
4 | import android.annotation.SuppressLint;
5 | import android.content.Intent;
6 | import android.graphics.Bitmap;
7 | import android.net.http.SslError;
8 | import android.os.Bundle;
9 | import android.text.TextUtils;
10 | import android.view.Menu;
11 | import android.view.MenuItem;
12 | import android.webkit.SslErrorHandler;
13 | import android.webkit.WebChromeClient;
14 | import android.webkit.WebSettings;
15 | import android.webkit.WebView;
16 | import android.webkit.WebViewClient;
17 | import android.widget.Toast;
18 | import com.example.viewnews.tools.BaseActivity;
19 | import org.litepal.LitePal;
20 | import java.util.List;
21 |
22 | //若需要启用Javascript,则抑制其警告
23 | @SuppressLint("SetJavaScriptEnabled")
24 | public class WebActivity extends BaseActivity {
25 |
26 | private WebView webView;
27 |
28 | private Toolbar navToolbar, commentToolBar;
29 |
30 | private String urlData, pageUniquekey, pageTtile;
31 |
32 | @Override
33 | protected void onCreate(Bundle savedInstanceState) {
34 | super.onCreate(savedInstanceState);
35 | setContentView(R.layout.activity_web);
36 | webView = (WebView) findViewById(R.id.webView);
37 | navToolbar = (Toolbar) findViewById(R.id.toolbar_webView);
38 | commentToolBar = (Toolbar) findViewById(R.id.toolbar_webComment);
39 | //将底部评论框的toolbar放在主界面上
40 | findViewById(R.id.toolbar_webComment).bringToFront();
41 | }
42 |
43 | //活动由不可见变为可见时调用
44 | @Override
45 | protected void onStart() {
46 | super.onStart();
47 | // 获取html页面的连接
48 | urlData = getIntent().getStringExtra("pageUrl");
49 | pageUniquekey = getIntent().getStringExtra("uniquekey");
50 | pageTtile = getIntent().getStringExtra("news_title");
51 |
52 | System.out.println("当前新闻id为:" + pageUniquekey);
53 | System.out.println("当前新闻标题为:" + pageTtile);
54 |
55 | // 通过WebView中的getSettings方法获得一个WebSettings对象
56 | WebSettings settings = webView.getSettings();
57 |
58 | // 详细讲解:https://www.jianshu.com/p/0d7d429bd216
59 | // 开启javascript:h5页要一般都有js,设置为true才允许h5页面执行js,但开启js非常耗内存,经常会导致oom,
60 | // 为了解决这个问题,可以在onStart方法中开启,在onStop中关闭。
61 | settings.setJavaScriptEnabled(true);
62 |
63 | //设置支持缩放
64 | settings.setSupportZoom(true);
65 | // 设置出现缩放工具。若为false,则该WebView不可缩放
66 | settings.setBuiltInZoomControls(true);
67 | // 设置允许js弹出alert对话框
68 | settings.setJavaScriptCanOpenWindowsAutomatically(true);
69 |
70 | // 设置webview推荐使用的窗口,使html界面自适应屏幕
71 | // 原因讲解:https://blog.csdn.net/SCHOLAR_II/article/details/80614486
72 | settings.setUseWideViewPort(true);
73 | // 设置WebView底层的布局算法,参考LayoutAlgorithm#NARROW_COLUMNS,将会重新生成WebView布局
74 | settings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NORMAL);
75 | // 设置缩放至屏幕的大小
76 | settings.setLoadWithOverviewMode(true);
77 | // 隐藏webview缩放按钮
78 | settings.setDisplayZoomControls(false);
79 | // 加载网页连接
80 | webView.loadUrl(urlData);
81 |
82 | // Toolbar通过setSupportActionBar(toolbar) 被修饰成了actionbar。
83 | setSupportActionBar(commentToolBar);
84 | // 设置菜单栏标题
85 | navToolbar.setTitle("看点新闻");
86 | setSupportActionBar(navToolbar);
87 | commentToolBar.inflateMenu(R.menu.tool_webbottom);
88 | commentToolBar.setTitle("感谢观看");
89 |
90 | webView.setWebViewClient(new WebViewClient() {
91 |
92 | @Override
93 | public void onPageStarted(WebView view, String url, Bitmap favicon) {
94 | super.onPageStarted(view, url, favicon);
95 | // 页面开始加载时就去查看收藏表中是否有对应的记录,组合键(账号和新闻号)
96 | List beanList = LitePal.where("userIdNumer = ? AND newsId = ?", MainActivity.currentUserId == null ? "" : MainActivity.currentUserId, pageUniquekey).find(NewsCollectBean.class);
97 | // 获取收藏按钮
98 | MenuItem u = commentToolBar.getMenu().getItem(0);
99 | if(beanList.size() > 0) {
100 | u.setIcon(R.drawable.ic_star_border_favourite_yes);
101 | } else {
102 | u.setIcon(R.drawable.ic_star_border_favourite_no);
103 | }
104 | }
105 |
106 | // 在页面加载结束时调用
107 | @Override
108 | public void onPageFinished(WebView view, String url) {
109 | super.onPageFinished(view, url);
110 | // 通过查看每个新闻的网页发现网页广告的div样式的选择器为body > div.top-wrap.gg-item.J-gg-item 然后去除这个样式,使其加载网页时去掉广告
111 | view.loadUrl("javascript:function setTop1(){document.querySelector('body > div.top-wrap.gg-item.J-gg-item').style.display=\"none\";}setTop1();");
112 | view.loadUrl("javascript:function setTop4(){document.querySelector('body > a.piclick-link').style.display=\"none\";}setTop4();");
113 | view.loadUrl("javascript:function setTop2(){document.querySelector('#news_check').style.display=\"none\";}setTop2();");
114 | view.loadUrl("javascript:function setTop3(){document.querySelector('body > div.articledown-wrap gg-item J-gg-item').style.display=\"none\";}setTop3();");
115 | }
116 |
117 | // 重写此方法可以让webView处理https请求。
118 | public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
119 | // 默认的处理方式,WebView变成空白页
120 | // handler.cancel();
121 | // 接受所有网站的证书,忽略SSL错误,执行访问网页
122 | handler.proceed();
123 | }
124 | });
125 |
126 | // 重写执行执行去广告的js代码
127 | webView.setWebChromeClient(new WebChromeClient(){
128 | // 每次网页加载进度改变时,就会执行一次js代码,保证广告一出来就被干掉
129 | // 缺点也很明显,会执行很多次无效的js代码。
130 | @Override
131 | public void onProgressChanged(WebView view, int newProgress) {
132 | super.onProgressChanged(view, newProgress);
133 | // 去除加载热点新闻
134 | view.loadUrl("javascript:function setTop1(){document.querySelector('body > div.top-wrap.gg-item.J-gg-item').style.display=\"none\";}setTop1();");
135 | view.loadUrl("javascript:function setTop4(){document.querySelector('body > a.piclick-link').style.display=\"none\";}setTop4();");
136 | view.loadUrl("javascript:function setTop2(){document.querySelector('#news_check').style.display=\"none\";}setTop2();");
137 | view.loadUrl("javascript:function setTop3(){document.querySelector('body > div.articledown-wrap gg-item J-gg-item').style.display=\"none\";}setTop3();");
138 | }
139 | });
140 |
141 |
142 | commentToolBar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() {
143 | @Override
144 | public boolean onMenuItemClick(MenuItem menuItem) {
145 | switch (menuItem.getItemId()) {
146 | case R.id.news_share:
147 | // 这里有bug,点击之后没反应
148 | Intent intent = new Intent(Intent.ACTION_SEND);
149 | intent.putExtra(Intent.EXTRA_SUBJECT, urlData);
150 | // 分享的文本类型
151 | intent.setType("text/plain");
152 | intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
153 | startActivity(Intent.createChooser(intent, getTitle()));
154 | break;
155 | case R.id.news_collect:
156 | //下一步实现点击收藏功能,以及用户查看收藏功能
157 | if(!TextUtils.isEmpty(MainActivity.currentUserId)) {
158 | // 先去查询一下是否有收藏过,然后加载每条新闻的时候查看是否已经被收藏,若被收藏,则将收藏按钮背景色设置为红色,否则为白色
159 | MenuItem u = commentToolBar.getMenu().getItem(0);
160 | List bean = LitePal.where("userIdNumer = ? AND newsId = ?", MainActivity.currentUserId, pageUniquekey).find(NewsCollectBean.class);
161 | NewsCollectBean currentNews = null;
162 | System.out.println(bean);
163 | String answer = "";
164 | if(bean.size() > 0) {
165 | System.out.println("111111111111111");
166 | int i = LitePal.deleteAll(NewsCollectBean.class, "userIdNumer = ? AND newsId = ?", MainActivity.currentUserId, pageUniquekey);
167 | if(i > 0) {
168 | answer = "取消收藏!";
169 | u.setIcon(R.drawable.ic_star_border_favourite_no);
170 | } else answer = "取消失败!";
171 | System.out.println("6666666666666666");
172 | } else {
173 | currentNews = new NewsCollectBean();
174 | currentNews.setUserIdNumer(MainActivity.currentUserId);
175 | currentNews.setNewSTitle(pageTtile);
176 | currentNews.setNewsId(pageUniquekey);
177 | currentNews.setNewsUrl(urlData);
178 | boolean isSave = currentNews.save();
179 | System.out.println("收藏的新闻:" + currentNews);
180 | if(isSave){
181 | answer = "收藏成功!";
182 | u.setIcon(R.drawable.ic_star_border_favourite_yes);
183 | }
184 | else answer = "收藏失败!";
185 | }
186 | Toast.makeText(WebActivity.this , answer, Toast.LENGTH_SHORT).show();
187 | } else {
188 | Toast.makeText(WebActivity.this, "请先登录后再收藏!", Toast.LENGTH_SHORT).show();
189 | }
190 | break;
191 | }
192 | return true;
193 | }
194 | });
195 | ActionBar actionBar = getSupportActionBar();
196 | if (actionBar != null) {
197 | actionBar.setDisplayHomeAsUpEnabled(true);
198 | //设置返回图标
199 | actionBar.setHomeAsUpIndicator(R.drawable.ic_return_left);
200 | }
201 | }
202 |
203 | // 活动不可见时关闭脚本,否则可能会导致oom
204 | @Override
205 | protected void onStop() {
206 | super.onStop();
207 | webView.getSettings().setJavaScriptEnabled(false);
208 | }
209 |
210 | // 此方法用于初始化菜单,其中menu参数就是即将要显示的Menu实例。 返回true则显示该menu, false则不显示;
211 | @Override
212 | public boolean onCreateOptionsMenu(Menu menu) {
213 |
214 | getMenuInflater().inflate(R.menu.toolbar_webview, menu);
215 |
216 | // SearchManager提供全局搜索服务
217 | // SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
218 | // 通过MenuItem得到SearchView
219 | // SearchView searchView = (SearchView) menu.findItem(R.id.news_search).getActionView();
220 |
221 | // searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));
222 | // 搜索框文字变化监听
223 | /*searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
224 | @Override
225 | public boolean onQueryTextSubmit(String query) {
226 | // 在文字改变的时候回调,query是改变之后的文字
227 | Toast.makeText(WebActivity.this, query, Toast.LENGTH_SHORT).show();
228 | return false;
229 | }
230 |
231 | //文字提交的时候回调
232 | @Override
233 | public boolean onQueryTextChange(String newText) {
234 | Toast.makeText(WebActivity.this, newText, Toast.LENGTH_LONG).show();
235 | return false;
236 | }
237 | });*/
238 | return true;
239 | }
240 |
241 |
242 | @Override
243 | public boolean onOptionsItemSelected(MenuItem item) {
244 | switch (item.getItemId()) {
245 | // 左上角的id
246 | case android.R.id.home:
247 | Intent returnIntent = new Intent();
248 | setResult(RESULT_OK, returnIntent);
249 | // 结束当前活动
250 | WebActivity.this.finish();
251 | break;
252 | case R.id.news_setting:
253 | Toast.makeText(this, "夜间模式", Toast.LENGTH_SHORT).show();
254 | break;
255 | case R.id.news_feedback:
256 | Toast.makeText(this, "举报!", Toast.LENGTH_SHORT).show();
257 | break;
258 | default:
259 | break;
260 | }
261 | return true;
262 | }
263 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/viewnews/tools/ActivityCollector.java:
--------------------------------------------------------------------------------
1 | package com.example.viewnews.tools;
2 |
3 | import android.app.Activity;
4 |
5 | import java.util.ArrayList;
6 | import java.util.List;
7 |
8 | public class ActivityCollector {
9 |
10 | public static List activities = new ArrayList<>();
11 |
12 | public static void addActivity(Activity activity) {
13 | activities.add(activity);
14 | }
15 |
16 | public static void removeActivity(Activity activity) {
17 | activities.remove(activity);
18 | }
19 |
20 | public static void finishAll() {
21 | for (Activity activity : activities) {
22 | if (!activity.isFinishing()) {
23 | activity.finish();
24 | }
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/viewnews/tools/BaseActivity.java:
--------------------------------------------------------------------------------
1 | package com.example.viewnews.tools;
2 |
3 | import androidx.appcompat.app.AppCompatActivity;
4 |
5 | import android.os.Bundle;
6 | import android.util.Log;
7 |
8 | // BaseActivity不需要注册
9 | public class BaseActivity extends AppCompatActivity {
10 |
11 | @Override
12 | protected void onCreate(Bundle savedInstanceState) {
13 | super.onCreate(savedInstanceState);
14 | Log.d("BaseActivity", getClass().getSimpleName());
15 | ActivityCollector.addActivity(this);
16 | }
17 |
18 | @Override
19 | protected void onDestroy() {
20 | super.onDestroy();
21 | ActivityCollector.removeActivity(this);
22 | }
23 | }
24 |
25 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/viewnews/tools/DataCleanManager.java:
--------------------------------------------------------------------------------
1 | package com.example.viewnews.tools;
2 |
3 | import android.content.Context;
4 | import android.os.Environment;
5 | import android.text.TextUtils;
6 |
7 | import java.io.File;
8 | import java.math.BigDecimal;
9 |
10 | // 本应用数据清除管理器
11 | public class DataCleanManager {
12 | /**
13 | * 清除本应用内部缓存(/data/data/com.xxx.xxx/cache)
14 | *
15 | * @param context
16 | */
17 | public static void cleanInternalCache(Context context) {
18 | System.out.println("进来了:" + context.getCacheDir());
19 | deleteFilesByDirectory(context.getCacheDir());
20 | }
21 |
22 | /**
23 | * 清除本应用所有数据库(/data/data/com.xxx.xxx/databases)
24 | *
25 | * @param context
26 | */
27 | public static void cleanDatabases(Context context) {
28 | deleteFilesByDirectory(new File("/data/data/"
29 | + context.getPackageName() + "/databases"));
30 | }
31 |
32 | /**
33 | * 清除本应用SharedPreference(/data/data/com.xxx.xxx/shared_prefs)
34 | *
35 | * @param context
36 | */
37 | public static void cleanSharedPreference(Context context) {
38 | deleteFilesByDirectory(new File("/data/data/"
39 | + context.getPackageName() + "/shared_prefs"));
40 | }
41 |
42 | /**
43 | * 按名字清除本应用数据库 *
44 | *
45 | * @param context
46 | * @param dbName
47 | */
48 | public static void cleanDatabaseByName(Context context, String dbName) {
49 | context.deleteDatabase(dbName);
50 | }
51 |
52 | /**
53 | * 清除/data/data/com.xxx.xxx/files下的内容
54 | *
55 | * @param context
56 | */
57 | public static void cleanFiles(Context context) {
58 | deleteFilesByDirectory(context.getFilesDir());
59 | }
60 |
61 | /**
62 | * 清除外部cache下的内容(/mnt/sdcard/android/data/com.xxx.xxx/cache)
63 | *
64 | * @param context
65 | */
66 | public static void cleanExternalCache(Context context) {
67 | if (Environment.getExternalStorageState().equals(
68 | Environment.MEDIA_MOUNTED)) {
69 | deleteFilesByDirectory(context.getExternalCacheDir());
70 | }
71 | }
72 | /**
73 | * 清除自定义路径下的文件,使用需小心,请不要误删。而且只支持目录下的文件删除
74 | *
75 | * @param filePath
76 | * */
77 | public static void cleanCustomCache(String filePath) {
78 | deleteFilesByDirectory(new File(filePath));
79 | }
80 |
81 | /**
82 | * 清除本应用所有的数据
83 | *
84 | * @param context
85 | * @param filepath
86 | */
87 | public static void cleanApplicationData(Context context, String... filepath) {
88 | cleanInternalCache(context);
89 | cleanExternalCache(context);
90 | cleanDatabases(context);
91 | cleanSharedPreference(context);
92 | cleanFiles(context);
93 | if (filepath == null) {
94 | return;
95 | }
96 | for (String filePath : filepath) {
97 | cleanCustomCache(filePath);
98 | }
99 | }
100 |
101 | /**
102 | * 删除方法 这里只会删除某个文件夹下的文件,如果传入的directory是个文件,将不做处理
103 | *
104 | * @param file
105 | */
106 | private static void deleteFilesByDirectory(File file) {
107 | System.out.println("进来删除了?6666");
108 | if (file.isDirectory()) {
109 | File zFiles[] = file.listFiles();
110 | for (File file2 : zFiles) {
111 | deleteFilesByDirectory(file2);
112 | }
113 | System.out.println("要删除的目录名为:" + file.getName());
114 | System.out.println("删除成功?" + file.delete());
115 | } else {
116 | System.out.println("要删除的文件名为:" + file.getName());
117 | System.out.println("删除成功?" + file.delete());
118 | }
119 |
120 | }
121 |
122 | // 获取文件
123 | //Context.getExternalFilesDir() --> SDCard/Android/data/你的应用的包名/files/ 目录,一般放一些长时间保存的数据
124 | //Context.getExternalCacheDir() --> SDCard/Android/data/你的应用包名/cache/目录,一般存放临时缓存数据
125 | public static long getFolderSize(File file) throws Exception {
126 | long size = 0;
127 | try {
128 | File[] fileList = file.listFiles();
129 | for (int i = 0; i < fileList.length; i++) {
130 | // 如果下面还有文件
131 | if (fileList[i].isDirectory()) {
132 | size = size + getFolderSize(fileList[i]);
133 | } else {
134 | size = size + fileList[i].length();
135 | }
136 | }
137 | } catch (Exception e) {
138 | e.printStackTrace();
139 | }
140 | return size;
141 | }
142 |
143 | /**
144 | * 删除指定目录下文件及目录
145 | *
146 | * @param deleteThisPath
147 | * @param filePath
148 | * @return
149 | */
150 | public static void deleteFolderFile(String filePath, boolean deleteThisPath) {
151 | if (!TextUtils.isEmpty(filePath)) {
152 | try {
153 | File file = new File(filePath);
154 | if (file.isDirectory()) {// 如果下面还有文件
155 | File files[] = file.listFiles();
156 | for (int i = 0; i < files.length; i++) {
157 | System.out.println("递归");
158 | deleteFolderFile(files[i].getAbsolutePath(), true);
159 | }
160 | }
161 | if (deleteThisPath) {
162 | if (!file.isDirectory()) {// 如果是文件,删除
163 | file.delete();
164 | } else { // 目录
165 | if (file.listFiles().length == 0) { // 目录下没有文件或者目录,删除
166 | file.delete();
167 | }
168 | }
169 | }
170 | } catch (Exception e) {
171 | e.printStackTrace();
172 | }
173 | }
174 | }
175 |
176 | /**
177 | * 格式化单位
178 | *
179 | * @param size
180 | * @return
181 | */
182 | public static String getFormatSize(double size) {
183 | double kiloByte = size / 1024;
184 | if (kiloByte < 1) {
185 | return size + "Byte";
186 | }
187 |
188 | double megaByte = kiloByte / 1024;
189 | if (megaByte < 1) {
190 | BigDecimal result1 = new BigDecimal(Double.toString(kiloByte));
191 | return result1.setScale(2, BigDecimal.ROUND_HALF_UP)
192 | .toPlainString() + "KB";
193 | }
194 |
195 | double gigaByte = megaByte / 1024;
196 | if (gigaByte < 1) {
197 | BigDecimal result2 = new BigDecimal(Double.toString(megaByte));
198 | return result2.setScale(2, BigDecimal.ROUND_HALF_UP)
199 | .toPlainString() + "MB";
200 | }
201 |
202 | double teraBytes = gigaByte / 1024;
203 | if (teraBytes < 1) {
204 | BigDecimal result3 = new BigDecimal(Double.toString(gigaByte));
205 | return result3.setScale(2, BigDecimal.ROUND_HALF_UP)
206 | .toPlainString() + "GB";
207 | }
208 | BigDecimal result4 = new BigDecimal(teraBytes);
209 | return result4.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString()
210 | + "TB";
211 | }
212 |
213 | public static String getCacheSize(File file) throws Exception {
214 | return getFormatSize(getFolderSize(file));
215 | }
216 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/viewnews/usermodel/Article.java:
--------------------------------------------------------------------------------
1 | package com.example.viewnews.usermodel;
2 |
3 | import org.litepal.crud.LitePalSupport;
4 |
5 | public class Article extends LitePalSupport {
6 |
7 | // 用户账号(唯一标识)
8 | private String userId;
9 | // 标题
10 | private String articleTitle;
11 | // 作者昵称
12 | private String articleAuthor;
13 | // 编写时间
14 | private String articleTime;
15 | // 文章图片地址
16 | private String articleImagePath;
17 | // 文章内容
18 | private String articleContent;
19 |
20 | public String getUserId() {
21 | return userId;
22 | }
23 |
24 | public void setUserId(String userId) {
25 | this.userId = userId;
26 | }
27 |
28 | public String getArticleTitle() {
29 | return articleTitle;
30 | }
31 |
32 | public void setArticleTitle(String articleTitle) {
33 | this.articleTitle = articleTitle;
34 | }
35 |
36 | public String getArticleAuthor() {
37 | return articleAuthor;
38 | }
39 |
40 | public void setArticleAuthor(String articleAuthor) {
41 | this.articleAuthor = articleAuthor;
42 | }
43 |
44 | public String getArticleTime() {
45 | return articleTime;
46 | }
47 |
48 | public void setArticleTime(String articleTime) {
49 | this.articleTime = articleTime;
50 | }
51 |
52 | public String getArticleImagePath() {
53 | return articleImagePath;
54 | }
55 |
56 | public void setArticleImagePath(String articleImagePath) {
57 | this.articleImagePath = articleImagePath;
58 | }
59 |
60 | public String getArticleContent() {
61 | return articleContent;
62 | }
63 |
64 | public void setArticleContent(String articleContent) {
65 | this.articleContent = articleContent;
66 | }
67 |
68 | @Override
69 | public String toString() {
70 | return "Article{" +
71 | "userId='" + userId + '\'' +
72 | ", articleTitle='" + articleTitle + '\'' +
73 | ", articleAuthor='" + articleAuthor + '\'' +
74 | ", articleTime='" + articleTime + '\'' +
75 | ", articleImagePath='" + articleImagePath + '\'' +
76 | ", articleContent='" + articleContent + '\'' +
77 | '}';
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/viewnews/usermodel/ArticleActivity.java:
--------------------------------------------------------------------------------
1 | package com.example.viewnews.usermodel;
2 |
3 | import android.content.Intent;
4 | import android.os.Bundle;
5 | import android.view.MenuItem;
6 | import android.view.View;
7 |
8 | import androidx.annotation.Nullable;
9 | import androidx.appcompat.app.ActionBar;
10 | import androidx.appcompat.widget.Toolbar;
11 | import androidx.recyclerview.widget.LinearLayoutManager;
12 | import androidx.recyclerview.widget.RecyclerView;
13 |
14 | import com.example.viewnews.R;
15 | import com.example.viewnews.tools.BaseActivity;
16 | import com.google.android.material.floatingactionbutton.FloatingActionButton;
17 |
18 | import org.litepal.LitePal;
19 |
20 | import java.util.ArrayList;
21 | import java.util.List;
22 |
23 | public class ArticleActivity extends BaseActivity {
24 |
25 | private List articleList = new ArrayList<>();
26 |
27 | private ArticleAdapter adapter;
28 |
29 | private String userIdNumber;
30 |
31 | private RecyclerView recyclerView;
32 |
33 | @Override
34 | protected void onCreate(Bundle savedInstanceState) {
35 | super.onCreate(savedInstanceState);
36 | setContentView(R.layout.activity_article);
37 | userIdNumber = getIntent().getStringExtra("user_article_id");
38 | System.out.println("当前用户的账号为" + userIdNumber);
39 | Toolbar toolbar = findViewById(R.id.article_toolbar);
40 | toolbar.setTitle("我的文章");
41 | setSupportActionBar(toolbar);
42 | //获取到ActionBar的实例
43 | ActionBar actionBar = getSupportActionBar();
44 | if (actionBar != null) {
45 | //将导航按钮显示出来
46 | actionBar.setDisplayHomeAsUpEnabled(true);
47 | //设置一个导航按钮图标
48 | actionBar.setHomeAsUpIndicator(R.drawable.ic_return_left);
49 | }
50 |
51 | //监听点击事件
52 | FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.article_fab);
53 | fab.setOnClickListener(new View.OnClickListener() {
54 | @Override
55 | public void onClick(View view) {
56 | //Toast.makeText(ArticleActivity.this, "点击编辑文章", Toast.LENGTH_SHORT).show();
57 | //跳转到编辑文章页面,返回来之后重新刷新列表
58 | Intent editArticleIntent = new Intent(ArticleActivity.this, EditArticleActivity.class);
59 | editArticleIntent.putExtra("userId", userIdNumber);
60 | startActivityForResult(editArticleIntent, 7);
61 | }
62 | });
63 | recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
64 | LinearLayoutManager layoutManager = new LinearLayoutManager(this);
65 | recyclerView.setLayoutManager(layoutManager);
66 | initArticles();
67 | }
68 |
69 | @Override
70 | protected void onStart() {
71 | super.onStart();
72 | System.out.println("回到我的文章列表这里!需要重新刷新一下列表!");
73 | //initArticles();
74 | }
75 |
76 | private void initArticles() {
77 | articleList.clear();
78 | List articles = LitePal.where("userId = ?", userIdNumber).find(Article.class);
79 | articleList.addAll(articles);
80 | adapter = new ArticleAdapter(articleList);
81 | recyclerView.setAdapter(adapter);
82 | adapter.notifyDataSetChanged();
83 | }
84 | public boolean onOptionsItemSelected(MenuItem item) {
85 | switch (item.getItemId()) {
86 | case android.R.id.home:
87 | // 销毁当前活动
88 | ArticleActivity.this.finish();
89 | break;
90 | }
91 | return true;
92 | }
93 |
94 | @Override
95 | protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
96 | super.onActivityResult(requestCode, resultCode, data);
97 | switch (requestCode) {
98 | case 7:
99 | if(resultCode == RESULT_OK) {
100 | //Toast.makeText(ArticleActivity.this, "该刷新列表了", Toast.LENGTH_SHORT).show();
101 | // 刷新个人文章列表
102 | initArticles();
103 | }
104 | break;
105 | }
106 | }
107 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/viewnews/usermodel/ArticleAdapter.java:
--------------------------------------------------------------------------------
1 | package com.example.viewnews.usermodel;
2 |
3 | import android.content.Context;
4 | import android.content.Intent;
5 | import android.view.LayoutInflater;
6 | import android.view.View;
7 | import android.view.ViewGroup;
8 | import android.widget.ImageView;
9 | import android.widget.TextView;
10 |
11 | import androidx.cardview.widget.CardView;
12 | import androidx.recyclerview.widget.RecyclerView;
13 |
14 | import com.bumptech.glide.Glide;
15 | import com.bumptech.glide.load.engine.DiskCacheStrategy;
16 | import com.example.viewnews.R;
17 |
18 | import java.util.List;
19 |
20 | public class ArticleAdapter extends RecyclerView.Adapter{
21 |
22 | private static final String TAG = "ArticleAdapter";
23 |
24 | private Context mContext;
25 |
26 | private List mArticleList;
27 |
28 | static class ViewHolder extends RecyclerView.ViewHolder {
29 | CardView cardView;
30 | ImageView articleImage;
31 | TextView articleTitle;
32 | TextView articleTime;
33 |
34 | public ViewHolder(View view) {
35 | super(view);
36 | cardView = (CardView) view;
37 | articleImage = (ImageView) view.findViewById(R.id.article_image);
38 | articleTitle = (TextView) view.findViewById(R.id.article_name);
39 | articleTime = (TextView) view.findViewById(R.id.article_time);
40 | }
41 | }
42 |
43 | public ArticleAdapter(List fruitList) {
44 | mArticleList = fruitList;
45 | }
46 |
47 | @Override
48 | public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
49 | if (mContext == null) {
50 | mContext = parent.getContext();
51 | }
52 | View view = LayoutInflater.from(mContext).inflate(R.layout.item_article, parent, false);
53 |
54 | final ViewHolder holder = new ViewHolder(view);
55 | //给cardView注册了一个监听器,当点击时,构造一个Intent并带到ArticleActivity活动中
56 | holder.cardView.setOnClickListener(new View.OnClickListener() {
57 | @Override
58 | public void onClick(View v) {
59 | int position = holder.getAdapterPosition();
60 | Article article = mArticleList.get(position);
61 | Intent intent = new Intent(mContext, ArticleDetailActivity.class);
62 | intent.putExtra(ArticleDetailActivity.ARTICLE_IMAGE_ID, article.getArticleImagePath());
63 | intent.putExtra(ArticleDetailActivity.ARTICLE_NAME, article.getArticleTitle());
64 | intent.putExtra(ArticleDetailActivity.ARTICLE_TIME, article.getArticleTime());
65 | mContext.startActivity(intent);
66 | }
67 | });
68 | return holder;
69 | }
70 |
71 | @Override
72 | public void onBindViewHolder(ViewHolder holder, int position) {
73 | Article article = mArticleList.get(position);
74 | holder.articleTitle.setText(article.getArticleTitle());
75 | holder.articleTime.setText(article.getArticleTime());
76 | //使用Glide来加载图片,with方法传入一个Context、Activity或Fragment参数,最后调用load()方法去加载图片在
77 | Glide.with(mContext)
78 | .load(article.getArticleImagePath())
79 | .diskCacheStrategy(DiskCacheStrategy.NONE)
80 | .placeholder(R.mipmap.ic_launcher)
81 | .error(R.mipmap.ic_launcher)
82 | .into(holder.articleImage);
83 | }
84 | @Override
85 | public int getItemCount() {
86 | return mArticleList.size();
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/viewnews/usermodel/ArticleDetailActivity.java:
--------------------------------------------------------------------------------
1 | package com.example.viewnews.usermodel;
2 |
3 | import androidx.appcompat.app.ActionBar;
4 | import androidx.appcompat.widget.Toolbar;
5 |
6 | import android.content.Intent;
7 | import android.os.Bundle;
8 | import android.view.MenuItem;
9 | import android.view.View;
10 | import android.widget.ImageView;
11 | import android.widget.TextView;
12 | import android.widget.Toast;
13 |
14 | import com.afollestad.materialdialogs.DialogAction;
15 | import com.afollestad.materialdialogs.MaterialDialog;
16 | import com.bumptech.glide.Glide;
17 | import com.bumptech.glide.load.engine.DiskCacheStrategy;
18 | import com.example.viewnews.MainActivity;
19 | import com.example.viewnews.R;
20 | import com.example.viewnews.tools.BaseActivity;
21 | import com.google.android.material.appbar.CollapsingToolbarLayout;
22 | import com.google.android.material.floatingactionbutton.FloatingActionButton;
23 |
24 | import org.litepal.LitePal;
25 |
26 | import java.util.List;
27 |
28 | public class ArticleDetailActivity extends BaseActivity {
29 |
30 | public static final String ARTICLE_NAME = "artile_name";
31 |
32 | public static final String ARTICLE_IMAGE_ID = "artile_image_id";
33 |
34 | public static final String ARTICLE_TIME = "artile_time";
35 |
36 | private String articleName, articleImageId, articleTime;
37 | @Override
38 | protected void onCreate(Bundle savedInstanceState) {
39 | super.onCreate(savedInstanceState);
40 | setContentView(R.layout.activity_article_detail);
41 |
42 | Intent intent = getIntent();
43 |
44 | articleName = intent.getStringExtra(ARTICLE_NAME);
45 | articleImageId = intent.getStringExtra(ARTICLE_IMAGE_ID);
46 | articleTime = intent.getStringExtra(ARTICLE_TIME);
47 | System.out.println("当前图片的地址为:" + articleImageId);
48 | System.out.println("当前文章的标题为:" + articleName);
49 | System.out.println("当前文章的发布时间为:" + articleTime);
50 |
51 | Toolbar toolbar = (Toolbar) findViewById(R.id.article_detail_toolbar);
52 | setSupportActionBar(toolbar);
53 |
54 | ActionBar actionBar = getSupportActionBar();
55 | if (actionBar != null) {
56 | //启用HomeAsUp按钮
57 | actionBar.setDisplayHomeAsUpEnabled(true);
58 | actionBar.setHomeAsUpIndicator(R.drawable.ic_return_left);
59 | }
60 |
61 | CollapsingToolbarLayout collapsingToolbar = (CollapsingToolbarLayout) findViewById(R.id.collapsing_toolbar);
62 | ImageView articleImageView = (ImageView) findViewById(R.id.article_image_view);
63 | TextView articleContentText = (TextView) findViewById(R.id.article_content_text);
64 |
65 | TextView articleAuthor = findViewById(R.id.article_author11);
66 |
67 | TextView articleTime12 = findViewById(R.id.article_time11);
68 |
69 | // 此处去查询数据库
70 | List articles = LitePal.where("userId = ? AND articleTitle = ? AND articleTime = ?", MainActivity.currentUserId, articleName, articleTime).find(Article.class);
71 |
72 | //设置当前界面的标题,作者,内容
73 | collapsingToolbar.setTitle(articleName);
74 | // 设置时间
75 | articleTime12.setText(articleTime);
76 | articleAuthor.setText(articles.get(0).getArticleAuthor());
77 | articleContentText.setText(articles.get(0).getArticleContent());
78 |
79 | Glide.with(this).load(articleImageId)
80 | .diskCacheStrategy(DiskCacheStrategy.NONE)
81 | .placeholder(R.mipmap.ic_launcher)
82 | .error(R.mipmap.ic_launcher)
83 | .into(articleImageView);
84 |
85 |
86 | //监听删除点击事件
87 | FloatingActionButton delFab = (FloatingActionButton) findViewById(R.id.delete_article);
88 | delFab.setOnClickListener(new View.OnClickListener() {
89 | @Override
90 | public void onClick(View view) {
91 | // 点击删除文章
92 | new MaterialDialog.Builder(ArticleDetailActivity.this)
93 | .title("提示")
94 | .content("确认是否删除此篇文章")
95 | .onPositive(new MaterialDialog.SingleButtonCallback() {
96 | @Override
97 | public void onClick(MaterialDialog dialog, DialogAction which) {
98 | //Toast.makeText(ArticleDetailActivity.this, "点击了确认按钮", Toast.LENGTH_SHORT).show();
99 | int isOk = LitePal.deleteAll(Article.class, "userId = ? AND articleTitle = ? AND articleTime = ?", MainActivity.currentUserId, articleName, articleTime);
100 | if(isOk > 0) {
101 | Toast.makeText(ArticleDetailActivity.this, "删除成功!", Toast.LENGTH_SHORT).show();
102 | ArticleDetailActivity.this.finish();
103 | } else {
104 | Toast.makeText(ArticleDetailActivity.this, "删除失败!", Toast.LENGTH_SHORT).show();
105 | }
106 | }
107 | })
108 | .positiveText("确认")
109 | .negativeText("取消")
110 | .show();
111 | }
112 | });
113 | }
114 |
115 | @Override
116 | public boolean onOptionsItemSelected(MenuItem item) {
117 | switch (item.getItemId()) {
118 | case android.R.id.home:
119 | //关闭当前活动,从而返回上一个活动
120 | ArticleDetailActivity.this.finish();
121 | return true;
122 | }
123 | return true;
124 | }
125 | }
126 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/viewnews/usermodel/EditArticleActivity.java:
--------------------------------------------------------------------------------
1 | package com.example.viewnews.usermodel;
2 |
3 | import androidx.annotation.NonNull;
4 | import androidx.appcompat.app.ActionBar;
5 | import androidx.appcompat.widget.Toolbar;
6 | import androidx.core.app.ActivityCompat;
7 | import androidx.core.content.ContextCompat;
8 |
9 | import android.Manifest;
10 | import android.annotation.TargetApi;
11 | import android.content.ContentUris;
12 | import android.content.Intent;
13 | import android.content.pm.PackageManager;
14 | import android.database.Cursor;
15 | import android.graphics.Bitmap;
16 | import android.graphics.BitmapFactory;
17 | import android.net.Uri;
18 | import android.os.Build;
19 | import android.os.Bundle;
20 | import android.provider.DocumentsContract;
21 | import android.provider.MediaStore;
22 | import android.text.TextUtils;
23 | import android.view.MenuItem;
24 | import android.view.View;
25 | import android.widget.Button;
26 | import android.widget.EditText;
27 | import android.widget.ImageView;
28 | import android.widget.Toast;
29 |
30 | import com.example.viewnews.R;
31 | import com.example.viewnews.tools.BaseActivity;
32 |
33 | import org.litepal.LitePal;
34 |
35 | import java.text.SimpleDateFormat;
36 | import java.util.Calendar;
37 | import java.util.List;
38 |
39 | public class EditArticleActivity extends BaseActivity {
40 |
41 |
42 | private ImageView editImageView;
43 | private EditText editTitle, editContent;
44 | private Button publishBtn;
45 |
46 | public static final int CHOOSE_ARTICLE_IMAGE = 22;
47 |
48 | private String editImagePath = "";
49 |
50 | private Article article = new Article();
51 |
52 | private String userID;
53 |
54 | @Override
55 | protected void onCreate(Bundle savedInstanceState) {
56 | super.onCreate(savedInstanceState);
57 | setContentView(R.layout.activity_edit_article);
58 | userID = getIntent().getStringExtra("userId");
59 | Toolbar toolbar = (Toolbar) findViewById(R.id.article_edit_toolbar);
60 | toolbar.setTitle("编辑文章");
61 | List userInfos = LitePal.where("userAccount = ?", userID).find(UserInfo.class);
62 | article.setUserId(userID);
63 | article.setArticleAuthor(userInfos.get(0).getNickName());
64 | System.out.println("当前文章详情为:" + article);
65 | setSupportActionBar(toolbar);
66 | ActionBar actionBar = getSupportActionBar();
67 | if (actionBar != null) {
68 | //启用HomeAsUp按钮
69 | actionBar.setDisplayHomeAsUpEnabled(true);
70 | actionBar.setHomeAsUpIndicator(R.drawable.ic_return_left);
71 | }
72 |
73 | editImageView = findViewById(R.id.edit_picture);
74 | editTitle = findViewById(R.id.edit_title);
75 | editContent = findViewById(R.id.edit_content);
76 | publishBtn = findViewById(R.id.edit_publish);
77 |
78 | editImageView.setOnClickListener(new View.OnClickListener() {
79 | @Override
80 | public void onClick(View view) {
81 | if (ContextCompat.checkSelfPermission(EditArticleActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
82 | ActivityCompat.requestPermissions(EditArticleActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
83 | } else {
84 | openAlbum();
85 | }
86 | }
87 | });
88 |
89 | // 发布时间
90 | publishBtn.setOnClickListener(new View.OnClickListener() {
91 | @Override
92 | public void onClick(View view) {
93 | if(TextUtils.isEmpty(editTitle.getText()) || TextUtils.isEmpty(editContent.getText())) {
94 | Toast.makeText(EditArticleActivity.this, "输入不能为空!", Toast.LENGTH_SHORT).show();
95 | } else {
96 | article.setArticleTitle(editTitle.getText().toString());
97 | article.setArticleContent(editContent.getText().toString());
98 | article.setArticleImagePath(editImagePath);
99 | Calendar calendar= Calendar.getInstance();
100 | SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
101 | System.out.println(sdf.format(calendar.getTime()));
102 | article.setArticleTime(sdf.format(calendar.getTime()));
103 | boolean save = article.save();
104 | if(save) Toast.makeText(EditArticleActivity.this, "发布成功!", Toast.LENGTH_SHORT).show();
105 | else Toast.makeText(EditArticleActivity.this, "发布失败!", Toast.LENGTH_SHORT).show();
106 | }
107 | }
108 | });
109 | }
110 |
111 | private void openAlbum() {
112 | Intent mIntent = new Intent("android.intent.action.GET_CONTENT");
113 | mIntent.setType("image/*");
114 | startActivityForResult(mIntent, CHOOSE_ARTICLE_IMAGE);
115 | }
116 |
117 | @Override
118 | public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
119 | switch (requestCode) {
120 | case 1:
121 | if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
122 | openAlbum();
123 | } else {
124 | Toast.makeText(this, "you denied the permission", Toast.LENGTH_SHORT).show();
125 | }
126 | break;
127 | default:
128 | }
129 | }
130 |
131 | @Override
132 | protected void onActivityResult(int requestCode, int resultCode, Intent data) {
133 | super.onActivityResult(requestCode, resultCode, data);
134 | switch (requestCode) {
135 | case CHOOSE_ARTICLE_IMAGE:
136 | if (resultCode == RESULT_OK) {
137 | if (Build.VERSION.SDK_INT >= 19) {
138 | handleImageOnKiKat(data);
139 | } else {
140 | handleImageBeforeKiKat(data);
141 | }
142 | }
143 | break;
144 | }
145 | }
146 | @TargetApi(Build.VERSION_CODES.KITKAT)
147 | private void handleImageOnKiKat(Intent data) {
148 | String imagePath = null;
149 | Uri uri = data.getData();
150 | if (DocumentsContract.isDocumentUri(this, uri)) {
151 | String docId = DocumentsContract.getDocumentId(uri);
152 | if ("com.android.providers.media.documents".equals(uri.getAuthority())) {
153 | String id = docId.split(":")[1];
154 | String selection = MediaStore.Images.Media._ID + "=" + id;
155 | imagePath = getImagePath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, selection);
156 | } else if ("com.android.providers.downloads.documents".equals(uri.getAuthority())) {
157 | Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(docId));
158 | imagePath = getImagePath(contentUri, null);
159 | }
160 | } else if ("content".equalsIgnoreCase(uri.getScheme())) {
161 | //如或是content类型的URI就使用普通方法处理
162 | imagePath = getImagePath(uri, null);
163 |
164 | } else if ("file".equalsIgnoreCase(uri.getScheme())) {
165 | //如果是file类型的直接获取图片路径就行
166 | imagePath = uri.getPath();
167 | }
168 | editImagePath = imagePath;
169 | // 根据图片路径显示图片
170 | diplayImage(imagePath);
171 | }
172 |
173 | private void handleImageBeforeKiKat(Intent data) {
174 | Uri uri = data.getData();
175 | String imagePath = getImagePath(uri, null);
176 | diplayImage(imagePath);
177 | }
178 |
179 | private String getImagePath(Uri uri, String selection) {
180 | String path = null;
181 | //通过Uri和selection来获取真实的图片路径
182 | Cursor cursor = getContentResolver().query(uri, null, selection, null, null);
183 | if (cursor != null) {
184 | if (cursor.moveToFirst()) {
185 | path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
186 | }
187 | cursor.close();
188 | }
189 | return path;
190 | }
191 |
192 | private void diplayImage(String imagePath) {
193 | if (!TextUtils.isEmpty(imagePath)) {
194 | Bitmap bitmap = BitmapFactory.decodeFile(imagePath);
195 | editImageView.setImageBitmap(bitmap);
196 | } else {
197 | editImageView.setImageResource(R.mipmap.ic_launcher);
198 | }
199 | }
200 |
201 | @Override
202 | public boolean onOptionsItemSelected(MenuItem item) {
203 | switch (item.getItemId()) {
204 | case android.R.id.home:
205 | Intent intent = new Intent();
206 | // 提醒刷新列表
207 | setResult(RESULT_OK, intent);
208 | EditArticleActivity.this.finish();
209 | return true;
210 | }
211 | return true;
212 | }
213 | }
214 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/viewnews/usermodel/FavoriteNewsListAdapter.java:
--------------------------------------------------------------------------------
1 | package com.example.viewnews.usermodel;
2 |
3 | import android.content.Context;
4 | import android.view.LayoutInflater;
5 | import android.view.View;
6 | import android.view.ViewGroup;
7 | import android.widget.ArrayAdapter;
8 | import android.widget.TextView;
9 | import com.example.viewnews.NewsCollectBean;
10 | import com.example.viewnews.R;
11 |
12 | import java.util.List;
13 |
14 | public class FavoriteNewsListAdapter extends ArrayAdapter {
15 |
16 | private int resourceId;
17 |
18 | public FavoriteNewsListAdapter(Context context, int textViewResourceId, List objects){
19 | super(context, textViewResourceId, objects);
20 | resourceId = textViewResourceId;
21 | }
22 |
23 | @Override
24 | public View getView(int position, View convertView, ViewGroup parent) {
25 | NewsCollectBean dataBean = getItem(position);
26 | View view =null;
27 | if (convertView == null){
28 | view = LayoutInflater.from(getContext()).inflate(resourceId, parent,false);
29 | } else {
30 | view = convertView;
31 | }
32 | TextView newsName = (TextView) view.findViewById(R.id.title_news);
33 | newsName.setText(dataBean.getNewSTitle());
34 | return view;
35 | }
36 | public class ViewHoder{
37 | private TextView newsName;
38 | }
39 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/viewnews/usermodel/LoginActivity.java:
--------------------------------------------------------------------------------
1 | package com.example.viewnews.usermodel;
2 |
3 | import androidx.annotation.Nullable;
4 | import android.content.Context;
5 | import android.content.Intent;
6 | import android.os.Bundle;
7 | import android.text.TextUtils;
8 | import android.util.Log;
9 | import android.view.View;
10 | import android.widget.Button;
11 | import android.widget.EditText;
12 | import android.widget.Toast;
13 |
14 | import com.example.viewnews.MainActivity;
15 | import com.example.viewnews.R;
16 | import com.example.viewnews.tools.BaseActivity;
17 |
18 | import org.litepal.LitePal;
19 |
20 | import java.io.BufferedWriter;
21 | import java.io.FileNotFoundException;
22 | import java.io.FileOutputStream;
23 | import java.io.IOException;
24 | import java.io.OutputStreamWriter;
25 | import java.util.List;
26 |
27 | public class LoginActivity extends BaseActivity {
28 |
29 | private EditText userAccount;
30 | private EditText userPwd;
31 | private Button loginBtn;
32 |
33 | private Button registerBtn;
34 |
35 | @Override
36 | protected void onCreate(Bundle savedInstanceState) {
37 | super.onCreate(savedInstanceState);
38 | setContentView(R.layout.activity_login);
39 | userAccount = findViewById(R.id.login_userAccount);
40 | userPwd = findViewById(R.id.login_pwd);
41 |
42 | // 在点击编辑资料时,提醒先登录
43 | Intent intent = getIntent();
44 | String status = intent.getStringExtra("loginStatus");
45 | if(status != null) {
46 | Toast.makeText(LoginActivity.this, status, Toast.LENGTH_SHORT).show();
47 | }
48 |
49 | loginBtn = findViewById(R.id.login_on);
50 | registerBtn = findViewById(R.id.login_register);
51 |
52 | loginBtn.setOnClickListener(new View.OnClickListener() {
53 | @Override
54 | public void onClick(View view) {
55 | String numId = userAccount.getText().toString();
56 | String pwd = userPwd.getText().toString();
57 | // 先判断输入不能为空
58 | if(TextUtils.isEmpty(numId) || TextUtils.isEmpty(pwd)) {
59 | Toast.makeText(LoginActivity.this, "输入不能为空", Toast.LENGTH_SHORT).show();
60 | } else {
61 | //此处用litepal去查询数据库,查询用户输入的账号和密码是否登录成功,其中账号是唯一标识
62 | List userInfos = LitePal.where("userAccount = ?", numId).find(UserInfo.class);
63 | System.out.println(userInfos);
64 | Log.d("登录界面", "onClick: " + userInfos);
65 | if(userInfos.size() == 0) {
66 | // 提示用户注册
67 | Toast.makeText(LoginActivity.this, "账号不存在,请先注册!", Toast.LENGTH_SHORT).show();
68 | } else {
69 | // 验证密码是否正确
70 | if(!pwd.equals(userInfos.get(0).getUserPwd())) {
71 | Toast.makeText(LoginActivity.this, "请确认是否输入正确的密码?", Toast.LENGTH_SHORT).show();
72 | } else {
73 | // 登录成功,返回到主界面,主界面要保存登录的账号,便于查询读者信息,主界面使用onActivityResult来接收得到的账号
74 | Intent intent = new Intent(LoginActivity.this, MainActivity.class);
75 | intent.putExtra("userID", numId);
76 | intent.putExtra("userNick", userInfos.get(0).getNickName());
77 | intent.putExtra("userSign", userInfos.get(0).getUserSignature());
78 | intent.putExtra("imagePath", userInfos.get(0).getImagePath());
79 | setResult(RESULT_OK, intent);
80 | finish();
81 | }
82 | }
83 | }
84 | }
85 | });
86 |
87 | registerBtn.setOnClickListener(new View.OnClickListener() {
88 | @Override
89 | public void onClick(View view) {
90 | //此处跳转到注册页面
91 | Intent intent = new Intent(LoginActivity.this, RegisterActivity.class);
92 | // 注册请求码是2
93 | startActivityForResult(intent, 2);
94 | }
95 | });
96 | }
97 |
98 | @Override
99 | protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
100 | super.onActivityResult(requestCode, resultCode, data);
101 | switch (requestCode) {
102 | case 2:
103 | if(resultCode == RESULT_OK) {
104 | Toast.makeText(LoginActivity.this, data.getStringExtra("register_status"), Toast.LENGTH_SHORT).show();
105 | }
106 | break;
107 | }
108 | }
109 |
110 | @Override
111 | protected void onDestroy() {
112 | super.onDestroy();
113 | // 登录界面销毁时存储账号
114 | String inputIdText = userAccount.getText().toString();
115 | save(inputIdText);
116 | System.out.println("活动毁灭之前是否传值" + inputIdText);
117 | }
118 |
119 | // 存储账号,方便下次启动app时,直接读取账号,并初始化数据
120 | public void save(String inputText) {
121 | FileOutputStream out = null;
122 | BufferedWriter writer = null;
123 | try {
124 | out = openFileOutput("data", Context.MODE_PRIVATE);
125 | writer = new BufferedWriter(new OutputStreamWriter(out));
126 | writer.write(inputText);
127 | } catch (FileNotFoundException e) {
128 | e.printStackTrace();
129 | } catch (IOException e) {
130 | e.printStackTrace();
131 | } finally {
132 | if (writer != null){
133 | try {
134 | writer.close();
135 | } catch (IOException e) {
136 | e.printStackTrace();
137 | }
138 | }
139 | }
140 | }
141 | }
142 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/viewnews/usermodel/RegisterActivity.java:
--------------------------------------------------------------------------------
1 | package com.example.viewnews.usermodel;
2 |
3 | import android.content.Intent;
4 | import android.os.Bundle;
5 | import android.text.TextUtils;
6 | import android.view.View;
7 | import android.widget.Button;
8 | import android.widget.EditText;
9 | import android.widget.Toast;
10 |
11 | import com.example.viewnews.R;
12 | import com.example.viewnews.tools.BaseActivity;
13 |
14 | import org.litepal.LitePal;
15 |
16 | import java.util.List;
17 |
18 | public class RegisterActivity extends BaseActivity {
19 |
20 | private EditText reg_userAccount;
21 | private EditText reg_userPwd;
22 | private EditText reg_confirm_userPwd;
23 | private Button registerBtn;
24 |
25 | @Override
26 | protected void onCreate(Bundle savedInstanceState) {
27 | super.onCreate(savedInstanceState);
28 | setContentView(R.layout.activity_register);
29 | reg_userAccount = findViewById(R.id.register_userAccount);
30 | reg_userPwd = findViewById(R.id.register_pwd);
31 | reg_confirm_userPwd = findViewById(R.id.confirm_pwd);
32 | registerBtn = findViewById(R.id.register_click);
33 | registerBtn.setOnClickListener(new View.OnClickListener() {
34 | @Override
35 | public void onClick(View view) {
36 | // 首先验证输入是否为空
37 | String userId = reg_userAccount.getText().toString();
38 | String userPwd = reg_userPwd.getText().toString();
39 | String secondPwd = reg_confirm_userPwd.getText().toString();
40 | List all = LitePal.findAll(UserInfo.class);
41 | if(TextUtils.isEmpty(userId) || TextUtils.isEmpty(userPwd) || TextUtils.isEmpty(secondPwd)) {
42 | // 判断字符串是否为null或者""
43 | Toast.makeText(RegisterActivity.this, "输入不能为空", Toast.LENGTH_SHORT).show();
44 | } else {
45 | // 判断两次输入的密码是否匹配,匹配则写入数据库,并且结束当前活动,自动返回登录界面
46 | if(userPwd.equals(secondPwd)) {
47 | List userInfoList = LitePal.where("userAccount = ?", userId).find(UserInfo.class);
48 | if(userInfoList.size() > 0) {
49 | Toast.makeText(RegisterActivity.this, "当前账号已被注册,请重新输入账号", Toast.LENGTH_SHORT).show();
50 | } else {
51 | UserInfo userInfo = new UserInfo();
52 | userInfo.setUserAccount(userId);
53 | userInfo.setUserPwd(secondPwd);
54 | userInfo.setUserBirthDay("待完善");
55 | userInfo.setUserSex("待完善");
56 | userInfo.setUserSignature("这个人很懒,TA什么也没留下。");
57 | // 给其设置一个用户名
58 | userInfo.setNickName("用户" + (all.size() + 1));
59 | userInfo.save();
60 | System.out.println(userInfo);
61 | Intent intent = new Intent();
62 | intent.putExtra("register_status", "注册成功");
63 | setResult(RESULT_OK, intent);
64 | finish();
65 | }
66 | } else {
67 | Toast.makeText(RegisterActivity.this, "请确认输入密码与确认密码是否一致?", Toast.LENGTH_SHORT).show();
68 | }
69 | }
70 | }
71 | });
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/viewnews/usermodel/UserDetailActivity.java:
--------------------------------------------------------------------------------
1 | package com.example.viewnews.usermodel;
2 |
3 | import androidx.annotation.NonNull;
4 | import androidx.appcompat.app.ActionBar;
5 | import androidx.appcompat.widget.Toolbar;
6 | import androidx.core.app.ActivityCompat;
7 | import androidx.core.content.ContextCompat;
8 |
9 | import android.Manifest;
10 | import android.annotation.TargetApi;
11 | import android.app.DatePickerDialog;
12 | import android.content.ContentUris;
13 | import android.content.Intent;
14 | import android.content.pm.PackageManager;
15 | import android.database.Cursor;
16 | import android.graphics.Bitmap;
17 | import android.graphics.BitmapFactory;
18 | import android.net.Uri;
19 | import android.os.Build;
20 | import android.os.Bundle;
21 | import android.provider.DocumentsContract;
22 | import android.provider.MediaStore;
23 | import android.text.InputType;
24 | import android.text.TextUtils;
25 | import android.view.MenuItem;
26 | import android.view.View;
27 | import android.widget.DatePicker;
28 | import android.widget.ImageView;
29 | import android.widget.LinearLayout;
30 | import android.widget.TextView;
31 | import android.widget.Toast;
32 |
33 | import com.afollestad.materialdialogs.MaterialDialog;
34 | import com.example.viewnews.R;
35 | import com.example.viewnews.tools.BaseActivity;
36 |
37 | import org.litepal.LitePal;
38 |
39 | import java.text.ParseException;
40 | import java.text.SimpleDateFormat;
41 | import java.util.Calendar;
42 | import java.util.Date;
43 | import java.util.List;
44 |
45 | public class UserDetailActivity extends BaseActivity {
46 |
47 | private ImageView userAvatar;
48 |
49 | private Toolbar detailToolbar;
50 |
51 | private String userId;
52 |
53 | public static final int CHOOSE_USER_AVATAR = 11;
54 |
55 | private UserInfo userInfo;
56 |
57 | // 定义线性布局
58 | private LinearLayout layout_avatar, layout_nickname, layout_sex, layout_birth, layout_signature;
59 |
60 | private TextView showNickName, showSex, showBirthday, showSignature;
61 |
62 | private Calendar calendar;
63 |
64 | @Override
65 | protected void onCreate(Bundle savedInstanceState) {
66 | super.onCreate(savedInstanceState);
67 | setContentView(R.layout.activity_user_detail);
68 | detailToolbar = findViewById(R.id.userData_toolbar);
69 | detailToolbar.setTitle("个人信息");
70 | setSupportActionBar(detailToolbar);
71 | ActionBar actionBar = getSupportActionBar();
72 | if (actionBar != null) {
73 | actionBar.setDisplayHomeAsUpEnabled(true);
74 | actionBar.setHomeAsUpIndicator(R.drawable.ic_return_left);
75 | }
76 | layout_avatar = findViewById(R.id.lay_avatar);
77 | layout_nickname = findViewById(R.id.lay_nickname);
78 |
79 | layout_sex = findViewById(R.id.lay_sex);
80 | layout_birth = findViewById(R.id.lay_birthday);
81 | layout_signature = findViewById(R.id.lay_signature);
82 |
83 | userAvatar = findViewById(R.id.user_avatar);
84 |
85 | showNickName = findViewById(R.id.show_name);
86 | showSex = findViewById(R.id.show_sex);
87 |
88 | showBirthday = findViewById(R.id.show_birthday);
89 | showSignature = findViewById(R.id.show_sign);
90 |
91 | userId = getIntent().getStringExtra("user_edit_id");
92 | initData();
93 |
94 | calendar = Calendar.getInstance();
95 | SimpleDateFormat format = new SimpleDateFormat("yyyy-mm-dd");
96 | Date date = null;
97 | if (!TextUtils.isEmpty(userInfo.getUserBirthDay()) && !userInfo.getUserBirthDay().equals("待完善")) {
98 | try {
99 | date = format.parse(userInfo.getUserBirthDay());
100 | calendar.setTime(date);
101 | } catch (ParseException e) {
102 | e.printStackTrace();
103 | }
104 | }
105 | }
106 |
107 | // 初始化数据
108 | private void initData() {
109 | List infos = LitePal.where("userAccount = ?", userId).find(UserInfo.class);
110 | userInfo = infos.get(0);
111 | System.out.println("用户详情界面的信息为" + userInfo);
112 | showNickName.setText(userInfo.getNickName());
113 | showSex.setText(userInfo.getUserSex());
114 | showBirthday.setText(userInfo.getUserBirthDay());
115 | showSignature.setText(userInfo.getUserSignature());
116 | String curImagePath = userInfo.getImagePath();
117 | diplayImage(curImagePath);
118 | }
119 |
120 | // 在活动由不可见变为可见的时候调用
121 | @Override
122 | protected void onStart() {
123 | super.onStart();
124 | layout_avatar.setOnClickListener(new View.OnClickListener() {
125 | @Override
126 | public void onClick(View view) {
127 | if (ContextCompat.checkSelfPermission(UserDetailActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
128 | ActivityCompat.requestPermissions(UserDetailActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
129 | } else {
130 | openAlbum();
131 | }
132 | }
133 | });
134 | layout_nickname.setOnClickListener(new View.OnClickListener() {
135 | @Override
136 | public void onClick(View view) {
137 | new MaterialDialog.Builder(UserDetailActivity.this)
138 | .title("修改昵称")
139 | .inputRangeRes(2, 8, R.color.colorBlack)
140 | .inputType(InputType.TYPE_CLASS_TEXT)
141 | .input("请输入要修改的昵称", userInfo.getNickName(), new MaterialDialog.InputCallback() {
142 | @Override
143 | public void onInput(MaterialDialog dialog, CharSequence input) {
144 | // CharSequence的值是可读可写序列,而String的值是只读序列。
145 | //Toast.makeText(UserDetailActivity.this, input, Toast.LENGTH_SHORT).show();
146 |
147 | System.out.println(input.toString());
148 | // 重新设置值,当前活动被销毁时才保存到数据库
149 | userInfo.setNickName(input.toString());
150 | showNickName.setText(userInfo.getNickName());
151 | }
152 | })
153 | .positiveText("确定")
154 | .show();
155 |
156 | }
157 | });
158 | layout_sex.setOnClickListener(new View.OnClickListener() {
159 | @Override
160 | public void onClick(View view) {
161 | String[] contentSex = new String[]{"男", "女"};
162 | new MaterialDialog.Builder(UserDetailActivity.this)
163 | .title("修改性别")
164 | .items(contentSex)
165 | .itemsCallbackSingleChoice(userInfo.getUserSex().equals("女") ? 1 : 0, new MaterialDialog.ListCallbackSingleChoice() {
166 | @Override
167 | public boolean onSelection(MaterialDialog dialog, View view, int which, CharSequence text) {
168 | System.out.println("选择哪一个" + which);
169 | System.out.println("选择的内容是" + text);
170 | userInfo.setUserSex(text.toString());
171 | showSex.setText(userInfo.getUserSex());
172 | return true;
173 | }
174 | })
175 | .show();
176 | }
177 | });
178 |
179 | layout_birth.setOnClickListener(new View.OnClickListener() {
180 | @Override
181 | public void onClick(View view) {
182 | DatePickerDialog dialog = new DatePickerDialog(UserDetailActivity.this, R.style.MyDatePickerDialogTheme, new DatePickerDialog.OnDateSetListener() {
183 |
184 | @Override
185 | public void onDateSet(DatePicker datePicker, int year, int monthOfYear, int dayOfMonth) {
186 | String birth = year + "-" + (monthOfYear + 1) + "-" + dayOfMonth;
187 | System.out.println(birth);
188 | userInfo.setUserBirthDay(birth);
189 | showBirthday.setText(birth);
190 | }
191 | },
192 | calendar.get(Calendar.YEAR),
193 | calendar.get(Calendar.MONTH),
194 | calendar.get(Calendar.DAY_OF_MONTH));
195 | dialog.show();
196 | }
197 | });
198 |
199 | layout_signature.setOnClickListener(new View.OnClickListener() {
200 | @Override
201 | public void onClick(View view) {
202 | new MaterialDialog.Builder(UserDetailActivity.this)
203 | .title("修改个性签名")
204 | .inputRangeRes(1, 38, R.color.colorBlack)
205 | .inputType(InputType.TYPE_CLASS_TEXT)
206 | .input("请输入要修改的个性签名", userInfo.getUserSignature(), new MaterialDialog.InputCallback() {
207 | @Override
208 | public void onInput(MaterialDialog dialog, CharSequence input) {
209 |
210 | System.out.println(input.toString());
211 | userInfo.setUserSignature(input.toString());
212 | showSignature.setText(userInfo.getUserSignature());
213 | }
214 | })
215 | .positiveText("确定")
216 | .show();
217 | }
218 | });
219 | }
220 |
221 | @Override
222 | public boolean onOptionsItemSelected(MenuItem item) {
223 | switch (item.getItemId()) {
224 | case android.R.id.home:
225 | // 保存更改的数据
226 | userInfo.save();
227 | Intent intent = new Intent();
228 | intent.putExtra("nickName", showNickName.getText().toString());
229 | intent.putExtra("signature", showSignature.getText().toString());
230 | intent.putExtra("imagePath", userInfo.getImagePath());
231 | setResult(RESULT_OK, intent);
232 | System.out.println("当前个人信息活动页被销毁!!!");
233 | UserDetailActivity.this.finish();
234 | break;
235 | }
236 | return true;
237 | }
238 |
239 | private void openAlbum() {
240 | Intent mIntent = new Intent("android.intent.action.GET_CONTENT");
241 | mIntent.setType("image/*");
242 | startActivityForResult(mIntent, CHOOSE_USER_AVATAR);
243 | }
244 |
245 | @Override
246 | public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
247 | switch (requestCode) {
248 | case 1:
249 | if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
250 | openAlbum();
251 | } else {
252 | Toast.makeText(this, "you denied the permission", Toast.LENGTH_SHORT).show();
253 | }
254 | break;
255 | default:
256 | }
257 | }
258 |
259 | @Override
260 | protected void onActivityResult(int requestCode, int resultCode, Intent data) {
261 | super.onActivityResult(requestCode, resultCode, data);
262 | switch (requestCode) {
263 | case CHOOSE_USER_AVATAR:
264 | if (resultCode == RESULT_OK) {
265 | if (Build.VERSION.SDK_INT >= 19) {
266 | handleImageOnKiKat(data);
267 | } else {
268 | handleImageBeforeKiKat(data);
269 | }
270 | }
271 | break;
272 | }
273 | }
274 |
275 | @TargetApi(Build.VERSION_CODES.KITKAT)
276 | private void handleImageOnKiKat(Intent data) {
277 | String imagePath = null;
278 | Uri uri = data.getData();
279 | if (DocumentsContract.isDocumentUri(this, uri)) {
280 | String docId = DocumentsContract.getDocumentId(uri);
281 | if ("com.android.providers.media.documents".equals(uri.getAuthority())) {
282 | String id = docId.split(":")[1];
283 | String selection = MediaStore.Images.Media._ID + "=" + id;
284 | imagePath = getImagePath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, selection);
285 | } else if ("com.android.providers.downloads.documents".equals(uri.getAuthority())) {
286 | Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(docId));
287 | imagePath = getImagePath(contentUri, null);
288 | }
289 | } else if ("content".equalsIgnoreCase(uri.getScheme())) {
290 | //如或是content类型的URI就使用普通方法处理
291 | imagePath = getImagePath(uri, null);
292 |
293 | } else if ("file".equalsIgnoreCase(uri.getScheme())) {
294 | //如果是file类型的直接获取图片路径就行
295 | imagePath = uri.getPath();
296 | }
297 | // 根据图片路径显示图片
298 | userInfo.setImagePath(imagePath);
299 | System.out.println("更新图片后,用户信息为" + userInfo);
300 | diplayImage(imagePath);
301 | }
302 |
303 | private void handleImageBeforeKiKat(Intent data) {
304 | Uri uri = data.getData();
305 | String imagePath = getImagePath(uri, null);
306 | diplayImage(imagePath);
307 | }
308 |
309 | private String getImagePath(Uri uri, String selection) {
310 | String path = null;
311 | //通过Uri和selection来获取真实的图片路径
312 | Cursor cursor = getContentResolver().query(uri, null, selection, null, null);
313 | if (cursor != null) {
314 | if (cursor.moveToFirst()) {
315 | path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
316 | }
317 | cursor.close();
318 | }
319 | return path;
320 | }
321 |
322 | private void diplayImage(String imagePath) {
323 | if (!TextUtils.isEmpty(imagePath)) {
324 | Bitmap bitmap = BitmapFactory.decodeFile(imagePath);
325 | userAvatar.setImageBitmap(bitmap);
326 | } else {
327 | userAvatar.setImageResource(R.drawable.no_login_avatar);
328 | }
329 | }
330 |
331 | @Override
332 | protected void onDestroy() {
333 | super.onDestroy();
334 | System.out.println("个人信息页面被销毁。。。。。。。。。。");
335 | }
336 | }
337 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/viewnews/usermodel/UserFavoriteActivity.java:
--------------------------------------------------------------------------------
1 | package com.example.viewnews.usermodel;
2 |
3 | import androidx.annotation.Nullable;
4 | import androidx.appcompat.app.ActionBar;
5 | import androidx.appcompat.widget.Toolbar;
6 | import android.content.Intent;
7 | import android.os.Bundle;
8 | import android.view.MenuItem;
9 | import android.view.View;
10 | import android.widget.AdapterView;
11 | import android.widget.ListView;
12 | import com.example.viewnews.NewsCollectBean;
13 | import com.example.viewnews.R;
14 | import com.example.viewnews.WebActivity;
15 | import com.example.viewnews.tools.BaseActivity;
16 | import org.litepal.LitePal;
17 | import java.util.ArrayList;
18 | import java.util.List;
19 |
20 | public class UserFavoriteActivity extends BaseActivity {
21 |
22 | private ListView favoriteNewsList;
23 | private List sonNewList = new ArrayList<>();
24 | private Toolbar favoriteToolbar;
25 | private String userIdNumber;
26 |
27 | private FavoriteNewsListAdapter adapter;
28 |
29 | @Override
30 | protected void onCreate(Bundle savedInstanceState) {
31 | super.onCreate(savedInstanceState);
32 | setContentView(R.layout.activity_user_favorite);
33 | userIdNumber = getIntent().getStringExtra("user_love_id");
34 | System.out.println("收藏:当前用户的id为" + userIdNumber);
35 | favoriteNewsList = findViewById(R.id.favorite_newsList);
36 | favoriteToolbar = findViewById(R.id.userFavorite_toolbar);
37 | favoriteToolbar.setTitle("我的收藏");
38 | setSupportActionBar(favoriteToolbar);
39 | initNews();
40 | ActionBar actionBar = getSupportActionBar();
41 | if (actionBar != null){
42 | actionBar.setDisplayHomeAsUpEnabled(true);
43 | actionBar.setHomeAsUpIndicator(R.drawable.ic_return_left);
44 | }
45 | }
46 |
47 | // 初始化数据
48 | private void initNews() {
49 | sonNewList = LitePal.where("userIdNumer = ? ", userIdNumber).find(NewsCollectBean.class);
50 | System.out.println("当前喜欢的列表有:" + sonNewList);
51 | adapter = new FavoriteNewsListAdapter(UserFavoriteActivity.this, R.layout.item_favorite_news,sonNewList);
52 | favoriteNewsList.setAdapter(adapter);
53 | adapter.notifyDataSetChanged();
54 | }
55 |
56 | @Override
57 | protected void onStart() {
58 | super.onStart();
59 | favoriteNewsList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
60 | @Override
61 | public void onItemClick(AdapterView> parent, View view, int position, long id) {
62 | NewsCollectBean dataBean = sonNewList.get(position);
63 | Intent intent = new Intent(UserFavoriteActivity.this, WebActivity.class);
64 | intent.putExtra("pageUrl", dataBean.getNewsUrl());
65 | intent.putExtra("uniquekey", dataBean.getNewsId());
66 | intent.putExtra("news_title", dataBean.getNewSTitle());
67 | startActivityForResult(intent, 4);
68 | }
69 | });
70 | }
71 |
72 | @Override
73 | public boolean onOptionsItemSelected(MenuItem item) {
74 | switch (item.getItemId()){
75 | case android.R.id.home:
76 | UserFavoriteActivity.this.finish();
77 | break;
78 | }
79 | return true;
80 | }
81 |
82 | @Override
83 | protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
84 | super.onActivityResult(requestCode, resultCode, data);
85 | switch (requestCode) {
86 | case 4:
87 | if(resultCode == RESULT_OK) {
88 | initNews();
89 | System.out.println("奥里给!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
90 | }
91 | break;
92 | }
93 | }
94 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/viewnews/usermodel/UserInfo.java:
--------------------------------------------------------------------------------
1 | package com.example.viewnews.usermodel;
2 |
3 | import org.litepal.crud.LitePalSupport;
4 |
5 | public class UserInfo extends LitePalSupport {
6 |
7 | // 账号
8 | private String userAccount;
9 | // 昵称
10 | private String nickName;
11 | // 登录密码
12 | private String userPwd;
13 | // 性别
14 | private String userSex;
15 | // 生日
16 | private String userBirthDay;
17 | // 个性签名
18 | private String userSignature;
19 | // 保存头像的路径
20 | private String imagePath;
21 |
22 | public String getUserAccount() {
23 | return userAccount;
24 | }
25 |
26 | public void setUserAccount(String userAccount) {
27 | this.userAccount = userAccount;
28 | }
29 |
30 | public String getNickName() {
31 | return nickName;
32 | }
33 |
34 | public void setNickName(String nickName) {
35 | this.nickName = nickName;
36 | }
37 |
38 | public String getUserPwd() {
39 | return userPwd;
40 | }
41 |
42 | public void setUserPwd(String userPwd) {
43 | this.userPwd = userPwd;
44 | }
45 |
46 | public String getUserSex() {
47 | return userSex;
48 | }
49 |
50 | public void setUserSex(String userSex) {
51 | this.userSex = userSex;
52 | }
53 |
54 | public String getUserBirthDay() {
55 | return userBirthDay;
56 | }
57 |
58 | public void setUserBirthDay(String userBirthDay) {
59 | this.userBirthDay = userBirthDay;
60 | }
61 |
62 | public String getUserSignature() {
63 | return userSignature;
64 | }
65 |
66 | public void setUserSignature(String userSignature) {
67 | this.userSignature = userSignature;
68 | }
69 |
70 | public String getImagePath() {
71 | return imagePath;
72 | }
73 |
74 | public void setImagePath(String imagePath) {
75 | this.imagePath = imagePath;
76 | }
77 |
78 | @Override
79 | public String toString() {
80 | return "UserInfo{" +
81 | "userAccount='" + userAccount + '\'' +
82 | ", nickName='" + nickName + '\'' +
83 | ", userPwd='" + userPwd + '\'' +
84 | ", userSex='" + userSex + '\'' +
85 | ", userBirthDay='" + userBirthDay + '\'' +
86 | ", userSignature='" + userSignature + '\'' +
87 | ", imagePath='" + imagePath + '\'' +
88 | '}';
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
12 |
13 |
19 |
22 |
25 |
26 |
27 |
28 |
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/avatar.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Code-health/AndroidCourseDesign/b2f4429222eee2423c56e97ccc682dddbadefd0c/app/src/main/res/drawable-xxhdpi/avatar.jpg
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_checked.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Code-health/AndroidCourseDesign/b2f4429222eee2423c56e97ccc682dddbadefd0c/app/src/main/res/drawable-xxhdpi/ic_checked.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_clear.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Code-health/AndroidCourseDesign/b2f4429222eee2423c56e97ccc682dddbadefd0c/app/src/main/res/drawable-xxhdpi/ic_clear.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_delete.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Code-health/AndroidCourseDesign/b2f4429222eee2423c56e97ccc682dddbadefd0c/app/src/main/res/drawable-xxhdpi/ic_delete.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_edit_article.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Code-health/AndroidCourseDesign/b2f4429222eee2423c56e97ccc682dddbadefd0c/app/src/main/res/drawable-xxhdpi/ic_edit_article.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_exit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Code-health/AndroidCourseDesign/b2f4429222eee2423c56e97ccc682dddbadefd0c/app/src/main/res/drawable-xxhdpi/ic_exit.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_menu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Code-health/AndroidCourseDesign/b2f4429222eee2423c56e97ccc682dddbadefd0c/app/src/main/res/drawable-xxhdpi/ic_menu.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_return_left.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Code-health/AndroidCourseDesign/b2f4429222eee2423c56e97ccc682dddbadefd0c/app/src/main/res/drawable-xxhdpi/ic_return_left.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_share.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Code-health/AndroidCourseDesign/b2f4429222eee2423c56e97ccc682dddbadefd0c/app/src/main/res/drawable-xxhdpi/ic_share.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_star_border_favourite_no.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Code-health/AndroidCourseDesign/b2f4429222eee2423c56e97ccc682dddbadefd0c/app/src/main/res/drawable-xxhdpi/ic_star_border_favourite_no.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_star_border_favourite_yes.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Code-health/AndroidCourseDesign/b2f4429222eee2423c56e97ccc682dddbadefd0c/app/src/main/res/drawable-xxhdpi/ic_star_border_favourite_yes.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_uncheck.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Code-health/AndroidCourseDesign/b2f4429222eee2423c56e97ccc682dddbadefd0c/app/src/main/res/drawable-xxhdpi/ic_uncheck.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_vertical_align_top.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Code-health/AndroidCourseDesign/b2f4429222eee2423c56e97ccc682dddbadefd0c/app/src/main/res/drawable-xxhdpi/ic_vertical_align_top.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/nav_articles.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Code-health/AndroidCourseDesign/b2f4429222eee2423c56e97ccc682dddbadefd0c/app/src/main/res/drawable-xxhdpi/nav_articles.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/nav_clear_cache.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Code-health/AndroidCourseDesign/b2f4429222eee2423c56e97ccc682dddbadefd0c/app/src/main/res/drawable-xxhdpi/nav_clear_cache.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/nav_edit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Code-health/AndroidCourseDesign/b2f4429222eee2423c56e97ccc682dddbadefd0c/app/src/main/res/drawable-xxhdpi/nav_edit.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/nav_favorite.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Code-health/AndroidCourseDesign/b2f4429222eee2423c56e97ccc682dddbadefd0c/app/src/main/res/drawable-xxhdpi/nav_favorite.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/nav_personinfo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Code-health/AndroidCourseDesign/b2f4429222eee2423c56e97ccc682dddbadefd0c/app/src/main/res/drawable-xxhdpi/nav_personinfo.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/nav_publish.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Code-health/AndroidCourseDesign/b2f4429222eee2423c56e97ccc682dddbadefd0c/app/src/main/res/drawable-xxhdpi/nav_publish.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/nav_settings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Code-health/AndroidCourseDesign/b2f4429222eee2423c56e97ccc682dddbadefd0c/app/src/main/res/drawable-xxhdpi/nav_settings.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/nav_switch.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Code-health/AndroidCourseDesign/b2f4429222eee2423c56e97ccc682dddbadefd0c/app/src/main/res/drawable-xxhdpi/nav_switch.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/no_login_avatar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Code-health/AndroidCourseDesign/b2f4429222eee2423c56e97ccc682dddbadefd0c/app/src/main/res/drawable-xxhdpi/no_login_avatar.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
100 |
105 |
110 |
115 |
120 |
125 |
130 |
135 |
140 |
145 |
150 |
155 |
160 |
165 |
170 |
171 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_article.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
10 |
11 |
12 |
13 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_article_detail.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
17 |
18 |
27 |
28 |
31 |
38 |
41 |
42 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
57 |
58 |
62 |
63 |
71 |
72 |
77 |
87 |
88 |
98 |
99 |
100 |
101 |
106 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
128 |
131 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_edit_article.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
16 |
17 |
22 |
23 |
32 |
33 |
37 |
38 |
44 |
45 |
46 |
47 |
48 |
57 |
58 |
67 |
68 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_login.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
17 |
22 |
31 |
32 |
33 |
34 |
46 |
47 |
59 |
60 |
61 |
73 |
74 |
81 |
82 |
86 |
94 |
103 |
104 |
105 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
16 |
17 |
26 |
27 |
28 |
35 |
36 |
37 |
38 |
39 |
43 |
44 |
45 |
46 |
47 |
55 |
56 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_register.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
17 |
22 |
34 |
35 |
36 |
37 |
49 |
50 |
51 |
63 |
64 |
76 |
77 |
88 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_user_detail.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
13 |
14 |
22 |
28 |
34 |
35 |
44 |
49 |
55 |
56 |
57 |
58 |
59 |
64 |
65 |
71 |
72 |
82 |
83 |
90 |
91 |
96 |
102 |
103 |
113 |
114 |
121 |
122 |
123 |
128 |
129 |
135 |
136 |
145 |
146 |
153 |
154 |
155 |
160 |
161 |
162 |
168 |
169 |
178 |
179 |
187 |
188 |
189 |
190 |
191 |
192 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_user_favorite.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
12 |
13 |
20 |
21 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_web.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
15 |
24 |
25 |
29 |
30 |
35 |
36 |
37 |
38 |
43 |
44 |
53 |
54 |
55 |
56 |
57 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_article.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
15 |
16 |
24 |
25 |
26 |
37 |
38 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_favorite_news.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
19 |
20 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_layout01.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
17 |
18 |
25 |
26 |
37 |
38 |
47 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_layout02.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
16 |
17 |
26 |
27 |
33 |
34 |
39 |
40 |
46 |
47 |
52 |
53 |
54 |
55 |
56 |
57 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_layout03.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
16 |
17 |
26 |
27 |
33 |
34 |
39 |
40 |
46 |
47 |
53 |
54 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/nav_header.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
16 |
17 |
18 |
25 |
26 |
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/news_list.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
12 |
13 |
19 |
20 |
21 |
22 |
26 |
29 |
35 |
36 |
37 |
38 |
39 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/nav_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/tool_webbottom.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/toolbar.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/toolbar_webview.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Code-health/AndroidCourseDesign/b2f4429222eee2423c56e97ccc682dddbadefd0c/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Code-health/AndroidCourseDesign/b2f4429222eee2423c56e97ccc682dddbadefd0c/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Code-health/AndroidCourseDesign/b2f4429222eee2423c56e97ccc682dddbadefd0c/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Code-health/AndroidCourseDesign/b2f4429222eee2423c56e97ccc682dddbadefd0c/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Code-health/AndroidCourseDesign/b2f4429222eee2423c56e97ccc682dddbadefd0c/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Code-health/AndroidCourseDesign/b2f4429222eee2423c56e97ccc682dddbadefd0c/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Code-health/AndroidCourseDesign/b2f4429222eee2423c56e97ccc682dddbadefd0c/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Code-health/AndroidCourseDesign/b2f4429222eee2423c56e97ccc682dddbadefd0c/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Code-health/AndroidCourseDesign/b2f4429222eee2423c56e97ccc682dddbadefd0c/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Code-health/AndroidCourseDesign/b2f4429222eee2423c56e97ccc682dddbadefd0c/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Code-health/AndroidCourseDesign/b2f4429222eee2423c56e97ccc682dddbadefd0c/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #008577
4 | #00574B
5 | #D81B60
6 |
7 |
8 | #F00
9 | #000
10 | #FFF
11 | #DCDCDC
12 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | 看点新闻
3 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
15 |
16 |
19 |
22 |
23 |
29 |
--------------------------------------------------------------------------------
/app/src/test/java/com/example/viewnews/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.example.viewnews;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | google()
6 | jcenter()
7 | // 导入第3方弹出窗,必须配置这个
8 | mavenCentral()
9 |
10 | }
11 | dependencies {
12 | classpath 'com.android.tools.build:gradle:3.4.1'
13 |
14 | // NOTE: Do not place your application dependencies here; they belong
15 | // in the individual module build.gradle files
16 | }
17 | }
18 |
19 | allprojects {
20 | repositories {
21 | google()
22 | jcenter()
23 |
24 | }
25 | }
26 |
27 | task clean(type: Delete) {
28 | delete rootProject.buildDir
29 | }
30 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx1536m
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 | # AndroidX package structure to make it clearer which packages are bundled with the
15 | # Android operating system, and which are packaged with your app's APK
16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
17 | android.useAndroidX=true
18 | # Automatically convert third-party libraries to use AndroidX
19 | android.enableJetifier=true
20 |
21 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Code-health/AndroidCourseDesign/b2f4429222eee2423c56e97ccc682dddbadefd0c/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Sat Nov 30 09:36:30 CST 2019
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/resultImage/articledetail.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Code-health/AndroidCourseDesign/b2f4429222eee2423c56e97ccc682dddbadefd0c/resultImage/articledetail.jpeg
--------------------------------------------------------------------------------
/resultImage/clearcache.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Code-health/AndroidCourseDesign/b2f4429222eee2423c56e97ccc682dddbadefd0c/resultImage/clearcache.jpeg
--------------------------------------------------------------------------------
/resultImage/collectionlist.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Code-health/AndroidCourseDesign/b2f4429222eee2423c56e97ccc682dddbadefd0c/resultImage/collectionlist.jpeg
--------------------------------------------------------------------------------
/resultImage/editarticle.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Code-health/AndroidCourseDesign/b2f4429222eee2423c56e97ccc682dddbadefd0c/resultImage/editarticle.jpeg
--------------------------------------------------------------------------------
/resultImage/editnickanme.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Code-health/AndroidCourseDesign/b2f4429222eee2423c56e97ccc682dddbadefd0c/resultImage/editnickanme.jpeg
--------------------------------------------------------------------------------
/resultImage/feedback.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Code-health/AndroidCourseDesign/b2f4429222eee2423c56e97ccc682dddbadefd0c/resultImage/feedback.jpeg
--------------------------------------------------------------------------------
/resultImage/login.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Code-health/AndroidCourseDesign/b2f4429222eee2423c56e97ccc682dddbadefd0c/resultImage/login.jpeg
--------------------------------------------------------------------------------
/resultImage/myarticle.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Code-health/AndroidCourseDesign/b2f4429222eee2423c56e97ccc682dddbadefd0c/resultImage/myarticle.jpeg
--------------------------------------------------------------------------------
/resultImage/personalinfo.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Code-health/AndroidCourseDesign/b2f4429222eee2423c56e97ccc682dddbadefd0c/resultImage/personalinfo.jpeg
--------------------------------------------------------------------------------
/resultImage/register.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Code-health/AndroidCourseDesign/b2f4429222eee2423c56e97ccc682dddbadefd0c/resultImage/register.jpeg
--------------------------------------------------------------------------------
/resultImage/viewpage.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Code-health/AndroidCourseDesign/b2f4429222eee2423c56e97ccc682dddbadefd0c/resultImage/viewpage.jpeg
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------