├── .gitignore ├── LICENSE ├── README.md ├── apk └── demo-2.2.1.apk ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── classic │ │ └── simple │ │ ├── activity │ │ ├── AppBaseActivity.java │ │ ├── FragmentActivity.java │ │ ├── ListViewActivity.java │ │ ├── MainActivity.java │ │ └── SplashActivity.java │ │ ├── app │ │ └── ClassicApplication.java │ │ ├── crash │ │ └── CustomCrashProcessImpl.java │ │ ├── fragment │ │ ├── ImageFragment.java │ │ └── TextFragment.java │ │ ├── model │ │ ├── Demo.java │ │ └── News.java │ │ └── utils │ │ ├── GlideImageLoad.java │ │ └── NewsDataSource.java │ └── res │ ├── drawable │ └── item_bg.xml │ ├── layout │ ├── activity_fragment.xml │ ├── activity_listview.xml │ ├── activity_main.xml │ ├── activity_main_item.xml │ ├── fragment_image.xml │ ├── fragment_text.xml │ ├── item_multiple_picture.xml │ ├── item_none_picture.xml │ └── item_single_picture.xml │ ├── mipmap-hdpi │ └── ic_launcher.png │ ├── mipmap-mdpi │ └── ic_launcher.png │ ├── mipmap-xhdpi │ ├── ic_launcher.png │ ├── splash.jpg │ ├── splash1.jpg │ ├── splash2.jpg │ ├── test.jpg │ └── test_image.jpg │ ├── mipmap-xxhdpi │ ├── ic_classic.png │ └── ic_launcher.png │ ├── mipmap-xxxhdpi │ └── ic_launcher.png │ ├── values-w820dp │ └── dimens.xml │ └── values │ ├── colors.xml │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml ├── build.gradle ├── classic ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── classic │ │ └── core │ │ ├── BasicConfig.java │ │ ├── activity │ │ ├── BaseActivity.java │ │ ├── BaseActivityStack.java │ │ ├── BaseSplashActivity.java │ │ └── package-info.java │ │ ├── consts │ │ ├── MIME.java │ │ └── package-info.java │ │ ├── exception │ │ ├── CrashHandler.java │ │ ├── impl │ │ │ └── DefaultCrashProcess.java │ │ └── package-info.java │ │ ├── fragment │ │ ├── BaseFragment.java │ │ └── package-info.java │ │ ├── interfaces │ │ ├── IActivity.java │ │ ├── ICrashProcess.java │ │ ├── IFragment.java │ │ ├── IRegister.java │ │ └── package-info.java │ │ ├── permissions │ │ ├── AfterPermissionGranted.java │ │ ├── AppSettingsDialog.java │ │ ├── EasyPermissions.java │ │ └── package-info.java │ │ └── utils │ │ ├── AppInfoUtil.java │ │ ├── BitmapUtil.java │ │ ├── ByteUtil.java │ │ ├── CloseUtil.java │ │ ├── ConversionUtil.java │ │ ├── CursorUtil.java │ │ ├── DataUtil.java │ │ ├── DateUtil.java │ │ ├── DeviceUtil.java │ │ ├── DoubleClickExitHelper.java │ │ ├── EditTextUtil.java │ │ ├── FileUtil.java │ │ ├── HtmlUtil.java │ │ ├── IntentUtil.java │ │ ├── IpUtil.java │ │ ├── KeyBoardUtil.java │ │ ├── MatcherUtil.java │ │ ├── MoneyUtil.java │ │ ├── NetworkUtil.java │ │ ├── PackageUtil.java │ │ ├── ResourceUtil.java │ │ ├── SDcardUtil.java │ │ ├── SharedPreferencesUtil.java │ │ ├── ShellUtil.java │ │ ├── SizeUtil.java │ │ ├── StringUtil.java │ │ ├── ToastUtil.java │ │ ├── ViewHolder.java │ │ ├── WeakHandler.java │ │ ├── WifiHelper.java │ │ ├── WindowUtil.java │ │ ├── encrypt │ │ ├── Base64.java │ │ ├── DESUtil.java │ │ └── MD5.java │ │ └── package-info.java │ └── res │ └── values │ ├── colors.xml │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── screenshots ├── Screenshot_20160929-181720.png ├── Screenshot_20160929-181734.png ├── Screenshot_20160929-181803.png └── log.png └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | # Gradle files 2 | build/ 3 | /build 4 | */build/ 5 | .gradle 6 | .gradle/ 7 | 8 | # Android Studio 9 | *.iml 10 | .idea 11 | 12 | # Intellij project files 13 | *.ipr 14 | *.iws 15 | .idea/ 16 | 17 | # Local configuration file (sdk path, etc) 18 | local.properties 19 | /local.properties 20 | 21 | /.idea/workspace.xml 22 | /.idea/libraries 23 | .DS_Store 24 | /captures 25 | 26 | #built application files 27 | #*.apk 28 | *.ap_ 29 | 30 | # files for the dex VM 31 | *.dex 32 | 33 | # generated files 34 | bin/ 35 | gen/ 36 | 37 | # Windows thumbnail db 38 | Thumbs.db 39 | 40 | # Java class files 41 | *.class 42 | # Eclipse project files 43 | .classpath 44 | .project 45 | # Eclipse Metadata 46 | .metadata/ 47 | # Proguard folder generated by Eclipse 48 | proguard/ 49 | 50 | # Log Files 51 | *.log 52 | 53 | #NDK 54 | obj/ 55 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | Copyright (c) 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | 8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | API 3 | Library version 4 | License 5 |

6 | 7 | 8 | ## 此项目停止更新,新项目地址:[BaseProject](https://github.com/qyxxjd/BaseProject) 9 | 10 | ## 关于 11 | 12 | * Blog: [http://blog.csdn.net/qy1387](http://blog.csdn.net/qy1387) 13 | * Email: [pgliubin@gmail.com](http://mail.qq.com/cgi-bin/qm_share?t=qm_mailme&email=pgliubin@gmail.com) 14 | 15 | ## License 16 | 17 | ``` 18 | Copyright 2015 classic 19 | 20 | Permission is hereby granted, free of charge, to any person obtaining a copy 21 | of this software and associated documentation files (the "Software"), to deal 22 | in the Software without restriction, including without limitation the rights 23 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 24 | copies of the Software, and to permit persons to whom the Software is 25 | furnished to do so, subject to the following conditions: 26 | 27 | The above copyright notice and this permission notice shall be included in 28 | all copies or substantial portions of the Software. 29 | 30 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 31 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 32 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 33 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 34 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 35 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 36 | THE SOFTWARE. 37 | ``` 38 | -------------------------------------------------------------------------------- /apk/demo-2.2.1.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qyxxjd/AndroidBasicProject/b1156b2a36b0a54219214a6c6caa89b34f607583/apk/demo-2.2.1.apk -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | *.iml 3 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | apply plugin: 'com.neenbedankt.android-apt' 3 | 4 | android { 5 | compileSdkVersion 25 6 | buildToolsVersion "25.0.0" 7 | 8 | defaultConfig { 9 | applicationId "com.classic.simple" 10 | minSdkVersion 9 11 | targetSdkVersion 25 12 | versionCode 1 13 | versionName "1.0" 14 | } 15 | buildTypes { 16 | release { 17 | minifyEnabled false 18 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 19 | } 20 | } 21 | } 22 | 23 | dependencies { 24 | compile fileTree(dir: 'libs', include: ['*.jar']) 25 | compile 'com.android.support:recyclerview-v7:25.0.0' 26 | compile 'com.android.support:cardview-v7:25.0.0' 27 | compile 'com.classic.adapter:commonadapter:1.2' 28 | compile 'com.github.bumptech.glide:glide:3.7.0' 29 | compile 'com.jakewharton:butterknife:8.4.0' 30 | apt 'com.jakewharton:butterknife-compiler:8.4.0' 31 | // compile project(':classic') 32 | compile 'com.classic.core:classic:2.2.1' 33 | } 34 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in D:\AndroidStudio\sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 26 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 39 | 42 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /app/src/main/java/com/classic/simple/activity/AppBaseActivity.java: -------------------------------------------------------------------------------- 1 | package com.classic.simple.activity; 2 | 3 | import android.os.Bundle; 4 | import android.view.MenuItem; 5 | import butterknife.ButterKnife; 6 | import com.classic.core.activity.BaseActivity; 7 | 8 | public abstract class AppBaseActivity extends BaseActivity { 9 | 10 | @Override public void initView(Bundle savedInstanceState) { 11 | ButterKnife.bind(this); 12 | } 13 | 14 | @Override public boolean onOptionsItemSelected(MenuItem item) { 15 | if (item.getItemId() == android.R.id.home) { 16 | finish(); 17 | return true; 18 | } 19 | return super.onOptionsItemSelected(item); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /app/src/main/java/com/classic/simple/activity/FragmentActivity.java: -------------------------------------------------------------------------------- 1 | package com.classic.simple.activity; 2 | 3 | import android.os.Bundle; 4 | import butterknife.OnClick; 5 | import com.classic.simple.R; 6 | import com.classic.simple.fragment.ImageFragment; 7 | import com.classic.simple.fragment.TextFragment; 8 | 9 | public class FragmentActivity extends AppBaseActivity { 10 | private ImageFragment mImageFragment; 11 | private TextFragment mTextFragment; 12 | private boolean isImageFragment; 13 | 14 | @Override public int getLayoutResId() { 15 | return R.layout.activity_fragment; 16 | } 17 | 18 | @Override public void initView(Bundle savedInstanceState) { 19 | super.initView(savedInstanceState); 20 | //这里偷懒,使用默认的。实际项目中建议使用ToolBar 21 | getSupportActionBar().setTitle("Fragment示例"); 22 | getSupportActionBar().setDisplayHomeAsUpEnabled(true); 23 | mImageFragment = new ImageFragment(); 24 | mTextFragment = new TextFragment(); 25 | isImageFragment = true; 26 | 27 | if(savedInstanceState == null){ 28 | onSwitchButtonClick(); 29 | } 30 | } 31 | 32 | @OnClick(R.id.btn_switch) 33 | public void onSwitchButtonClick(){ 34 | isImageFragment = !isImageFragment; 35 | /** 36 | * 参数1:被替换为Fragment的视图id 37 | * 参数2:BaseFragment对象 38 | */ 39 | changeFragment(R.id.fragment_layout, isImageFragment ? mImageFragment : mTextFragment); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /app/src/main/java/com/classic/simple/activity/ListViewActivity.java: -------------------------------------------------------------------------------- 1 | package com.classic.simple.activity; 2 | 3 | import android.content.Context; 4 | import android.os.Bundle; 5 | import android.widget.ListView; 6 | import butterknife.BindView; 7 | import com.classic.adapter.BaseAdapterHelper; 8 | import com.classic.adapter.CommonAdapter; 9 | import com.classic.simple.R; 10 | import com.classic.simple.model.News; 11 | import com.classic.simple.utils.GlideImageLoad; 12 | import com.classic.simple.utils.NewsDataSource; 13 | import java.text.SimpleDateFormat; 14 | import java.util.Date; 15 | import java.util.List; 16 | import java.util.Locale; 17 | 18 | /** 19 | * 通用适配器示例By ListView 20 | */ 21 | public class ListViewActivity extends AppBaseActivity { 22 | public static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.CHINA); 23 | public static final String URL_SEPARATOR = ";"; 24 | public static final String FORMAT_AUTHOR = "报道人:%s"; 25 | 26 | @BindView(R.id.listview_lv) ListView mListView; 27 | 28 | @Override public int getLayoutResId() { 29 | return R.layout.activity_listview; 30 | } 31 | 32 | @Override public void initView(Bundle savedInstanceState) { 33 | super.initView(savedInstanceState); 34 | getSupportActionBar().setTitle("通用适配器示例"); 35 | getSupportActionBar().setDisplayHomeAsUpEnabled(true); 36 | 37 | mListView.setAdapter(new MultipleLayoutAdapter(this, R.layout.item_none_picture, NewsDataSource.getNewsList())); 38 | } 39 | 40 | private final class MultipleLayoutAdapter extends CommonAdapter { 41 | 42 | public MultipleLayoutAdapter(Context context, int layoutResId, List data) { 43 | super(context, layoutResId, data); 44 | } 45 | 46 | @Override public int getLayoutResId(News item, int position) { 47 | int layoutResId = -1; 48 | switch (item.getNewsType()){ 49 | case News.TYPE_NONE_PICTURE: 50 | layoutResId = R.layout.item_none_picture; 51 | break; 52 | case News.TYPE_SINGLE_PICTURE: 53 | layoutResId = R.layout.item_single_picture; 54 | break; 55 | case News.TYPE_MULTIPLE_PICTURE: 56 | layoutResId = R.layout.item_multiple_picture; 57 | break; 58 | } 59 | return layoutResId; 60 | } 61 | 62 | @Override public void onUpdate(BaseAdapterHelper helper, News item, int position) { 63 | switch (item.getNewsType()){ 64 | case News.TYPE_NONE_PICTURE: 65 | helper.setText(R.id.item_none_picture_title, item.getTitle()) 66 | .setText(R.id.item_none_picture_author, 67 | String.format(Locale.CHINA, FORMAT_AUTHOR, item.getAuthor())) 68 | .setText(R.id.item_none_picture_date, 69 | DATE_FORMAT.format(new Date(item.getReleaseTime()))) 70 | .setText(R.id.item_none_picture_intro, item.getIntro()); 71 | break; 72 | case News.TYPE_SINGLE_PICTURE: 73 | helper.setText(R.id.item_single_picture_title, item.getTitle()) 74 | .setText(R.id.item_single_picture_author, 75 | String.format(Locale.CHINA, FORMAT_AUTHOR, item.getAuthor())) 76 | .setText(R.id.item_single_picture_date, 77 | DATE_FORMAT.format(new Date(item.getReleaseTime()))) 78 | .setImageLoad(new GlideImageLoad()) 79 | .setImageUrl(R.id.item_single_picture_cover,item.getCoverUrl()); 80 | break; 81 | case News.TYPE_MULTIPLE_PICTURE: 82 | String[] urls = item.getCoverUrl().split(URL_SEPARATOR); 83 | helper.setText(R.id.item_multiple_picture_intro, item.getIntro()) 84 | .setImageLoad(new GlideImageLoad()) 85 | .setImageUrl(R.id.item_multiple_picture_cover_left,urls[0]) 86 | .setImageUrl(R.id.item_multiple_picture_cover_right, urls[1]); 87 | break; 88 | } 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /app/src/main/java/com/classic/simple/activity/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.classic.simple.activity; 2 | 3 | import android.Manifest; 4 | import android.content.Context; 5 | import android.os.Bundle; 6 | import android.os.Handler; 7 | import android.support.v7.widget.CardView; 8 | import android.support.v7.widget.DefaultItemAnimator; 9 | import android.support.v7.widget.LinearLayoutManager; 10 | import android.support.v7.widget.RecyclerView; 11 | import android.util.Log; 12 | import android.view.KeyEvent; 13 | import android.view.View; 14 | import butterknife.BindView; 15 | import com.classic.adapter.BaseAdapterHelper; 16 | import com.classic.adapter.CommonRecyclerAdapter; 17 | import com.classic.core.permissions.AfterPermissionGranted; 18 | import com.classic.core.permissions.EasyPermissions; 19 | import com.classic.core.utils.DoubleClickExitHelper; 20 | import com.classic.core.utils.SDcardUtil; 21 | import com.classic.core.utils.ToastUtil; 22 | import com.classic.simple.R; 23 | import com.classic.simple.model.Demo; 24 | import com.orhanobut.logger.Logger; 25 | import java.util.List; 26 | 27 | /** 28 | * 通用适配器示例By RecyclerView 29 | */ 30 | public class MainActivity extends AppBaseActivity { 31 | private static final int REQUEST_CODE_CAMERA = 101; 32 | private static final String TAG = "MainActivity"; 33 | 34 | @BindView(R.id.main_rv) RecyclerView mRecyclerView; 35 | 36 | private List mDemos; 37 | private DoubleClickExitHelper mDoubleClickExitHelper; 38 | private DemoAdapter mAdapter; 39 | 40 | @Override public int getLayoutResId() { 41 | return R.layout.activity_main; 42 | } 43 | 44 | @Override public void onFirst() { 45 | super.onFirst(); 46 | Logger.d("onFirst只有第一次才会执行"); 47 | //这里可以做一些界面功能引导 48 | } 49 | 50 | /** 51 | * 方法执行顺序: 52 | * initData() --> initView() --> register() 53 | */ 54 | @Override public void initData() { 55 | super.initData(); 56 | mDemos = Demo.getDemos(); 57 | //双击退出应用工具类使用方法,别忘了重写onKeyDown方法(见底部) 58 | mDoubleClickExitHelper = new DoubleClickExitHelper(this); 59 | //mDoubleClickExitHelper = new DoubleClickExitHelper(this) 60 | //.setTimeInterval(3000) 61 | //.setToastContent("再按一次退出demo"); 62 | } 63 | 64 | /** 65 | * 方法执行顺序: 66 | * initData() --> initView() --> register() 67 | */ 68 | @Override public void initView(Bundle savedInstanceState) { 69 | super.initView(savedInstanceState); 70 | mRecyclerView.setOnClickListener(this); 71 | LinearLayoutManager manager = new LinearLayoutManager(this); 72 | manager.setOrientation(LinearLayoutManager.VERTICAL); 73 | mRecyclerView.setLayoutManager(manager); 74 | //如果可以确定每个item的高度是固定的,设置这个选项可以提高性能 75 | mRecyclerView.setHasFixedSize(true); 76 | mRecyclerView.setItemAnimator(new DefaultItemAnimator()); 77 | mAdapter = new DemoAdapter(mActivity, R.layout.activity_main_item, mDemos); 78 | mRecyclerView.setAdapter(mAdapter); 79 | mAdapter.setOnItemClickListener(new CommonRecyclerAdapter.OnItemClickListener() { 80 | @Override 81 | public void onItemClick(RecyclerView.ViewHolder viewHolder, View view, int position) { 82 | itemClick(mDemos.get(position)); 83 | } 84 | }); 85 | } 86 | 87 | private final class DemoAdapter extends CommonRecyclerAdapter { 88 | 89 | public DemoAdapter(Context context, int layoutResId, List data) { 90 | super(context, layoutResId, data); 91 | } 92 | 93 | @Override public void onUpdate(BaseAdapterHelper helper, Demo item, int position) { 94 | final CardView cardView = helper.getView(R.id.main_item_cardview); 95 | cardView.setCardBackgroundColor(item.bgColor); 96 | helper.setText(R.id.main_item_tv, item.title); 97 | } 98 | } 99 | 100 | @Override public void register() { 101 | super.register(); 102 | //这里可以注册一些广播、服务 103 | } 104 | 105 | @Override public void unRegister() { 106 | super.unRegister(); 107 | //注销广播、服务 108 | } 109 | 110 | private void itemClick(Demo demo) { 111 | switch (demo.type) { 112 | case Demo.TYPE_ADAPTER: 113 | startActivity(MainActivity.this, ListViewActivity.class); 114 | break; 115 | case Demo.TYPE_CRASH: 116 | crashTest(); 117 | break; 118 | case Demo.TYPE_SPLASH: 119 | startActivity(MainActivity.this, SplashActivity.class); 120 | break; 121 | case Demo.TYPE_FRAGMENT: 122 | startActivity(MainActivity.this, FragmentActivity.class); 123 | break; 124 | case Demo.TYPE_PERMISSIONS: 125 | useCamera(); 126 | break; 127 | } 128 | } 129 | 130 | private void crashTest() { 131 | ToastUtil.showLongToast(this, "程序即将崩溃,崩溃日志请查看:" + SDcardUtil.getLogDirPath()); 132 | new Handler().postDelayed(new Runnable() { 133 | @Override public void run() { 134 | throw new NullPointerException("666"); 135 | } 136 | }, 3000); 137 | } 138 | 139 | 140 | @AfterPermissionGranted(REQUEST_CODE_CAMERA) 141 | public void useCamera() { 142 | if (EasyPermissions.hasPermissions(this, Manifest.permission.CAMERA)) { 143 | ToastUtil.showToast(getApplicationContext(), "相机权限已授权,可以开始使用相机了"); 144 | } else { 145 | //请求权限 146 | EasyPermissions.requestPermissions(this, "应用需要访问你的相机进行拍照", 147 | REQUEST_CODE_CAMERA, Manifest.permission.CAMERA); 148 | } 149 | } 150 | 151 | @Override 152 | public void onPermissionsGranted(int requestCode, List perms) { 153 | Log.d(TAG, "onPermissionsGranted:" + requestCode + ":" + perms.size()); 154 | } 155 | 156 | @Override 157 | public void onPermissionsDenied(int requestCode, List perms) { 158 | Log.e(TAG, "onPermissionsDenied:" + requestCode + ":" + perms.size()); 159 | } 160 | 161 | @Override public boolean onKeyDown(int keyCode, KeyEvent event) { 162 | return mDoubleClickExitHelper.onKeyDown(keyCode, event); 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /app/src/main/java/com/classic/simple/activity/SplashActivity.java: -------------------------------------------------------------------------------- 1 | package com.classic.simple.activity; 2 | 3 | import com.classic.core.activity.BaseSplashActivity; 4 | import com.classic.simple.R; 5 | import java.util.List; 6 | 7 | /** 8 | * 启动页示例 9 | */ 10 | public class SplashActivity extends BaseSplashActivity { 11 | private final int mPlayerTime = 1000; 12 | private final float mStartAlpha = 100f; 13 | private final boolean isExpand = true; 14 | 15 | @Override protected void setSplashResources(List resources) { 16 | /** 17 | * SplashImgResource参数: 18 | * mResId - 图片资源的ID。 19 | * playerTime - 图片资源的播放时间,单位为毫秒。。 20 | * startAlpha - 图片资源开始时的透明程度。0-255之间。 21 | * isExpand - 如果为true,则图片会被拉伸至全屏幕大小进行展示,否则按原大小展示。 22 | */ 23 | resources.add(new SplashImgResource(R.mipmap.splash, mPlayerTime, mStartAlpha, isExpand)); 24 | resources.add(new SplashImgResource(R.mipmap.splash1, mPlayerTime, mStartAlpha, isExpand)); 25 | resources.add(new SplashImgResource(R.mipmap.splash2, mPlayerTime, mStartAlpha, isExpand)); 26 | } 27 | 28 | @Override protected boolean isAutoStartNextActivity() { 29 | return true; 30 | } 31 | 32 | @Override protected Class nextActivity() { 33 | //如果isAutoStartNextActivity设置为true,这里需要指定跳转的activity 34 | return MainActivity.class; 35 | } 36 | 37 | @Override protected void runOnBackground() { 38 | //这里可以执行耗时操作、初始化工作 39 | //请注意:如果执行了耗时操作,那么启动页会等到耗时操作执行完才会进行跳转 40 | //try { 41 | // Thread.sleep(15 * 1000); 42 | //} catch (InterruptedException e) { 43 | // e.printStackTrace(); 44 | //} 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /app/src/main/java/com/classic/simple/app/ClassicApplication.java: -------------------------------------------------------------------------------- 1 | package com.classic.simple.app; 2 | 3 | import android.app.Application; 4 | import com.classic.core.BasicConfig; 5 | import com.classic.simple.crash.CustomCrashProcessImpl; 6 | 7 | public class ClassicApplication extends Application { 8 | 9 | @Override public void onCreate() { 10 | super.onCreate(); 11 | 12 | /** 13 | * 默认配置,适用于正式版本 14 | * 内部调用了: initDir() initLog(false) initExceptionHandler()三个方法 15 | */ 16 | //BasicConfig.getInstance(this).init(); 17 | 18 | /** 19 | * 自定义配置 20 | * initDir() 初始化SDCard缓存目录 21 | * initLog() 初始化日志打印 22 | * initExceptionHandler() 默认异常信息处理 23 | */ 24 | BasicConfig.getInstance(this) 25 | .initDir() // or initDir(rootDirName) 26 | .initExceptionHandler(new CustomCrashProcessImpl()) //自定义异常信息处理,实现ICrashProcess 27 | .initLog(true); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /app/src/main/java/com/classic/simple/crash/CustomCrashProcessImpl.java: -------------------------------------------------------------------------------- 1 | package com.classic.simple.crash; 2 | 3 | import com.classic.core.interfaces.ICrashProcess; 4 | import com.classic.core.utils.DateUtil; 5 | import com.classic.core.utils.SDcardUtil; 6 | import java.io.BufferedWriter; 7 | import java.io.File; 8 | import java.io.FileWriter; 9 | import java.io.PrintWriter; 10 | 11 | /** 12 | * 13 | * 自定义崩溃日志处理 14 | */ 15 | public class CustomCrashProcessImpl implements ICrashProcess { 16 | private static final String SUFFIX = ".txt"; 17 | 18 | @Override public void onException(Thread thread, Throwable exception) throws Exception { 19 | 20 | //TODO 这里替换你的自定义逻辑 21 | 22 | final String logName = DateUtil.formatDate("yyyyMMdd_HHmmss",System.currentTimeMillis()) + SUFFIX; 23 | final File file = new File(SDcardUtil.getLogDirPath(), logName); 24 | if (!file.exists()) { 25 | file.createNewFile(); 26 | } 27 | PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter(file, true))); 28 | pw.println(DateUtil.formatDate(DateUtil.FORMAT, System.currentTimeMillis())); 29 | pw.println(); 30 | exception.printStackTrace(pw); 31 | pw.println(); 32 | pw.close(); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /app/src/main/java/com/classic/simple/fragment/ImageFragment.java: -------------------------------------------------------------------------------- 1 | package com.classic.simple.fragment; 2 | 3 | import com.classic.core.fragment.BaseFragment; 4 | import com.classic.core.utils.ToastUtil; 5 | import com.classic.simple.R; 6 | 7 | public class ImageFragment extends BaseFragment { 8 | 9 | @Override public int getLayoutResId() { 10 | return R.layout.fragment_image; 11 | } 12 | 13 | @Override public void onFragmentShow() { 14 | super.onFragmentShow(); 15 | ToastUtil.showToast(getActivity(), "ImageFragment --> onFragmentShow()"); 16 | } 17 | 18 | @Override public void onFragmentHide() { 19 | super.onFragmentHide(); 20 | ToastUtil.showToast(getActivity(), "ImageFragment --> onFragmentHide()"); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /app/src/main/java/com/classic/simple/fragment/TextFragment.java: -------------------------------------------------------------------------------- 1 | package com.classic.simple.fragment; 2 | 3 | import com.classic.core.fragment.BaseFragment; 4 | import com.classic.core.utils.ToastUtil; 5 | import com.classic.simple.R; 6 | 7 | public class TextFragment extends BaseFragment { 8 | 9 | @Override public int getLayoutResId() { 10 | return R.layout.fragment_text; 11 | } 12 | 13 | @Override public void onFragmentShow() { 14 | super.onFragmentShow(); 15 | ToastUtil.showToast(getActivity(), "TextFragment --> onFragmentShow()"); 16 | } 17 | 18 | @Override public void onFragmentHide() { 19 | super.onFragmentHide(); 20 | ToastUtil.showToast(getActivity(), "TextFragment --> onFragmentHide()"); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /app/src/main/java/com/classic/simple/model/Demo.java: -------------------------------------------------------------------------------- 1 | package com.classic.simple.model; 2 | 3 | import android.graphics.Color; 4 | import com.classic.core.utils.DataUtil; 5 | import java.io.Serializable; 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | 9 | /** 10 | * @author 续写经典 11 | * @date 2015/11/7 12 | */ 13 | public class Demo implements Serializable { 14 | public static final int TYPE_SPLASH = 0x00; 15 | public static final int TYPE_ADAPTER = 0x01; 16 | public static final int TYPE_CRASH = 0x02; 17 | public static final int TYPE_FRAGMENT = 0x03; 18 | public static final int TYPE_PERMISSIONS = 0x04; 19 | 20 | public String title; 21 | public int bgColor; 22 | public int type; 23 | 24 | public Demo() { 25 | } 26 | 27 | public Demo(String title, int bgColor, int type) { 28 | this.title = title; 29 | this.bgColor = bgColor; 30 | this.type = type; 31 | } 32 | 33 | private static List demos; 34 | 35 | public static List getDemos() { 36 | if (DataUtil.isEmpty(demos)) { 37 | demos = new ArrayList<>(); 38 | demos.add(new Demo("启动页", Color.parseColor("#00bcd4"), TYPE_SPLASH)); 39 | demos.add(new Demo("Fragment", Color.parseColor("#ff4081"), TYPE_FRAGMENT)); 40 | demos.add(new Demo("通用适配器", Color.parseColor("#9c27b0"), TYPE_ADAPTER)); 41 | demos.add(new Demo("异常日志收集", Color.parseColor("#e51c23"), TYPE_CRASH)); 42 | demos.add(new Demo("Android6.0权限请求", Color.parseColor("#ff9800"), TYPE_PERMISSIONS)); 43 | } 44 | return demos; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /app/src/main/java/com/classic/simple/model/News.java: -------------------------------------------------------------------------------- 1 | package com.classic.simple.model; 2 | 3 | public class News { 4 | 5 | /** 单图布局样式 */ 6 | public static final int TYPE_SINGLE_PICTURE = 0; 7 | /** 多图布局样式 */ 8 | public static final int TYPE_MULTIPLE_PICTURE = 1; 9 | /** 无图布局样式 */ 10 | public static final int TYPE_NONE_PICTURE = 2; 11 | 12 | private String title; 13 | private String intro; 14 | private String coverUrl; 15 | private String author; 16 | private long releaseTime; 17 | private int newsType; 18 | 19 | public News(){} 20 | 21 | public News(int newsType, String author, String title, String intro) { 22 | this(newsType,author,title,intro,""); 23 | } 24 | 25 | public News(int newsType, String author, String title, String intro, String coverUrl) { 26 | this.newsType = newsType; 27 | this.author = author; 28 | this.title = title; 29 | this.intro = intro; 30 | this.coverUrl = coverUrl; 31 | this.releaseTime = System.currentTimeMillis(); 32 | } 33 | 34 | public String getTitle() { 35 | return title; 36 | } 37 | 38 | public void setTitle(String title) { 39 | this.title = title; 40 | } 41 | 42 | public String getIntro() { 43 | return intro; 44 | } 45 | 46 | public void setIntro(String intro) { 47 | this.intro = intro; 48 | } 49 | 50 | public String getCoverUrl() { 51 | return coverUrl; 52 | } 53 | 54 | public void setCoverUrl(String coverUrl) { 55 | this.coverUrl = coverUrl; 56 | } 57 | 58 | public String getAuthor() { 59 | return author; 60 | } 61 | 62 | public void setAuthor(String author) { 63 | this.author = author; 64 | } 65 | 66 | public long getReleaseTime() { 67 | return releaseTime; 68 | } 69 | 70 | public void setReleaseTime(long releaseTime) { 71 | this.releaseTime = releaseTime; 72 | } 73 | 74 | public int getNewsType() { 75 | return newsType; 76 | } 77 | 78 | public void setNewsType(int newsType) { 79 | this.newsType = newsType; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /app/src/main/java/com/classic/simple/utils/GlideImageLoad.java: -------------------------------------------------------------------------------- 1 | package com.classic.simple.utils; 2 | 3 | import android.content.Context; 4 | import android.text.TextUtils; 5 | import android.widget.ImageView; 6 | import com.bumptech.glide.Glide; 7 | import com.classic.adapter.interfaces.ImageLoad; 8 | 9 | public class GlideImageLoad implements ImageLoad { 10 | 11 | @Override public void load(Context context, ImageView imageView, String imageUrl) { 12 | if(TextUtils.isEmpty(imageUrl)) return; 13 | Glide.with(context).load(imageUrl).centerCrop().crossFade().into(imageView); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /app/src/main/java/com/classic/simple/utils/NewsDataSource.java: -------------------------------------------------------------------------------- 1 | package com.classic.simple.utils; 2 | 3 | import com.classic.simple.model.News; 4 | import java.util.ArrayList; 5 | 6 | public final class NewsDataSource { 7 | private static final String AUTHOR = "续写经典"; 8 | private static ArrayList newsList; 9 | 10 | //测试数据 11 | public static ArrayList getNewsList(){ 12 | if(null==newsList || newsList.isEmpty()){ 13 | newsList = new ArrayList<>(); 14 | newsList.add(new News(News.TYPE_SINGLE_PICTURE,AUTHOR,"谷歌返华前兆?桥头堡Google Play降低门槛","北京时间1月26日上午消息,谷歌今日在Play Games中取消了强制使用Google+登录的要求,允许没有谷歌帐号的新用户全面使用这项服务。有相关评论称,此举或意味着谷歌返华又更近了一步。","http://n.sinaimg.cn/tech/transform/20160126/g8H_-fxnvhvu7058461.jpg")); 15 | newsList.add(new News(News.TYPE_NONE_PICTURE,AUTHOR,"河北工商局:三大运营商涉嫌不正当竞争","记者从河北省工商局获悉,中国移动河北分公司、中国联通河北分公司、中国电信河北分公司等电信运营商采取赠与学校领导、班主任、联系人老师话费的方式,向广大学生强行推销“校讯通”“家校通”“翼校通”等产品,涉嫌违反《中华人民共和国反不正当竞争法》。")); 16 | newsList.add(new News(News.TYPE_MULTIPLE_PICTURE,AUTHOR,"杭州零下9度 一夜寒风吹冻西湖","1月25日清晨,西湖雷峰塔景区冰封美景醉人,当日,受霸王级寒潮影响,杭州主城区出现最低-9.3℃气温,逼近1969年的历史极值,受此影响,杭州西湖部分水域出现严重结冰现象。","http://www.sinaimg.cn/dy/slidenews/1_img/2016_04/2841_656896_533796.jpg;http://www.sinaimg.cn/dy/slidenews/1_img/2016_04/2841_656904_171122.jpg")); 17 | newsList.add(new News(News.TYPE_SINGLE_PICTURE,AUTHOR,"创投机构回应上海政府风投补偿:返税意义更大","引力创投是落户上海的早期投资机构,其合伙人戴周颖在接受新浪科技采访时认为,上海市此举还是属于招商引资的一个办法。在此之前,上海市就有专门的政策和方案,通过引导基金的方式,让更多GP(基金管理合伙人)注入上海,并且基金须有一定比例投资上海。","http://n.sinaimg.cn/tech/transform/20160126/KR43-fxnuvxc1994221.jpg")); 18 | newsList.add(new News(News.TYPE_NONE_PICTURE,AUTHOR,"上海新规:天使投资有损失可获补偿 最高补六成","近日,上海市科学技术委员会、上海市财政局、上海市发改委联合发布《上海市天使投资风险补偿管理暂行办法》,提出对投资机构投资种子期、初创期科技型企业,最终回收的转让收入与退出前累计投入该企业的投资额之间的差额部分,给予以一定比例的财务补偿。")); 19 | newsList.add(new News(News.TYPE_SINGLE_PICTURE,AUTHOR,"我们为什么投资马斯克的超级高铁Hyperloop","对于天使投资而言,每一次投资就像一次豪赌。当Peter Thiel投资Facebook、Paul Graham投资Airbnb、Sherwin Pishevar投资Uber的时候,都被很多人看作是“疯子”。当然现在有无数的投资人为错过了投资机会懊悔不已,但在最初撒出大笔现金时,谁也说不准它会成长为独角兽,还是让投资人输得血本无归。","http://s.img.mix.sina.com.cn/auto/resize?size=560_0&img=http%3A%2F%2Fsinastorage.com%2Fstorage.csj.sina.com.cn%2F319f277142405b15c3c702b03c8af1cf.jpg")); 20 | newsList.add(new News(News.TYPE_MULTIPLE_PICTURE,AUTHOR,"2015电子信息制造业销售产值同比增长8.7%","1-12月,规模以上电子信息制造业内销产值同比增长17.3%,出口交货值同比下降0.1%。从内外资角度看,1-12月,内资企业的销售产值同比增长17.8%,港澳台投资企业销售产值同比增长8.3%,外商投资企业销售产值同比下降0.1%。","http://n.sinaimg.cn/tech/transform/20160125/onUR-fxnuvxe8392239.png;http://n.sinaimg.cn/tech/transform/20160125/Ll3P-fxnuvxe8392273.png")); 21 | newsList.add(new News(News.TYPE_NONE_PICTURE,AUTHOR,"微软反垄断案新突破 Win10或需剥离可信计算","半年多来,我们跟微软进行过数次谈判。我们希望微软可以按照我国法律法规实现本土化,但谈判至今还没有结果。”沈昌祥系此次微软网络安全审查的负责人,他笑称,“每一次都斗争激烈,我们要坚守网络安全主权,而微软也不止是一家商业公司,它的决策也需要通过美国本土的审批。")); 22 | newsList.add(new News(News.TYPE_NONE_PICTURE,AUTHOR,"高管集体离职致Twitter股价开盘跳水逾6%","新浪科技讯 北京时间1月26日早间消息,在5名重要高管离职后,Twitter股价周一开盘下跌逾6个百分点。此次离职的包括该公司工程副总裁亚历克斯·罗特尔(Alex Roettter)、产品副总裁凯文·维尔(Kevin Weil)、媒体主管凯蒂·斯坦顿(Katie Stanton)、人力资源副总裁布莱恩·施佩尔(Brian Schipper)和Vine主管詹森·托夫(Jason Toff)。")); 23 | newsList.add(new News(News.TYPE_SINGLE_PICTURE,AUTHOR,"动物弱肉强食惊心动魄捕食:雄狮遭水牛追赶","当地时间2015年2月4日,一头雄狮在一群水牛的追赶下居然也会落荒而逃。虽然被成为是森林之王,但这只明显更像是一只受到惊吓的小猫。一开始两头狮子在草地上休息,突然,水牛发现了敌人的身影,便一同扑上去追赶,狮子吓得立刻掉头逃走了。","http://www.sinaimg.cn/dy/slidenews/5_img/2016_04/453_74575_776168.jpg")); 24 | newsList.add(new News(News.TYPE_SINGLE_PICTURE,AUTHOR,"非洲变色龙捕食甲虫瞬间:伸出长舌头黏住吞下","摄影师托马斯•惠滕(Thomas Whetten)在纳米比亚西部的纳米布沙漠(Namib Desert)拍摄到一组纳马夸变色龙从后方捕食毫无防备的甲虫的照片。","http://www.sinaimg.cn/dy/slidenews/5_img/2016_04/453_74569_384735.jpg")); 25 | newsList.add(new News(News.TYPE_SINGLE_PICTURE,AUTHOR,"潜水员与大白鲨亲密接触上演惊魂时刻","近日,在墨西哥瓜达卢佩圣母岛海岸,一名潜水员通过向大白鲨投喂食物将其引诱至笼子边,将他的手臂伸出,轻轻抚摸了大白鲨的鼻子。这一惊魂时刻被摄影师记录了下来。","http://www.sinaimg.cn/dy/slidenews/5_img/2016_04/453_74552_646977.jpg")); 26 | newsList.add(new News(News.TYPE_MULTIPLE_PICTURE,AUTHOR,"网曝富士康郑州工厂发生火灾 现场黑烟滚滚","火灾发生地点位于新郑富士康02区,当时消防人员已经到位,随后大火被扑灭。目前尚不知道起火原因,人员伤亡情况也未公布,暂不清楚是否会对部分手机数码产品的供货造成影响。目前尚未有富士康方面的公开回应。","http://n.sinaimg.cn/translate/20160125/q0v5-fxnuwcr7470993.jpg;http://n.sinaimg.cn/translate/20160125/jMrS-fxnuwfi3015757.jpg")); 27 | newsList.add(new News(News.TYPE_MULTIPLE_PICTURE,AUTHOR,"“汪星人”偷偷溜进半程马拉松还混到名次","话说最近在美国阿拉巴马州的一个小镇发生了件神奇的事。Ludivine是只2岁半的猎犬,周六早晨她的主人照例放它出去溜达。万万没想到,在这户人家附近正举行一场半程马拉松,这狗一溜达就跑到了马拉松起点附近,默默和选手们一起","http://www.sinaimg.cn/dy/slidenews/1_img/2016_04/2841_656940_447365.jpg;http://www.sinaimg.cn/dy/slidenews/1_img/2016_04/2841_656941_891976.jpg")); 28 | newsList.add(new News(News.TYPE_NONE_PICTURE,AUTHOR,"清华控股将收购两家半导体制造公司","北京时间1月26日早间消息,清华控股董事长徐井宏本周在达沃斯世界经济论坛上表示,清华控股计划收购两家半导体制造公司。此举表明,中国计划进一步加强半导体制造技术。投行Stifel Nicolaus分析师阿隆·雷克斯(Aaron Rakers)表示:“获得政府支持的清华控股2016年将投资2000亿元人民币,用于并购活动。”")); 29 | newsList.add(new News(News.TYPE_NONE_PICTURE,AUTHOR,"马斯克:油价下跌正在冲击电动汽车市场","马斯克周一表示:“我认为,整个行业肯定受到了低油价的冲击。这从经济性上来说是合理的。”近期,油价下跌正在改变美国汽车市场的格局,皮卡和SUV等“油老虎”车型的销量去年出现增长。今年以来,油价的跌势仍在延续,而上周则创下12年以来最低纪录。")); 30 | newsList.add(new News(News.TYPE_NONE_PICTURE,AUTHOR,"圆通延吉店老板跑路 大量快件滞留","临近春节,又一家快递加盟公司停摆:圆通延吉公司老板被曝拖欠员工工资,疑似跑路,大量快件堆放在网点外,无人管理。去年“双11”至今,不仅是圆通,加盟制快递企业“四通一达”其余的申通、中通、百世汇通和韵达也均被媒体曝出部分加盟网点出现疑似停工、倒闭等情况。伴随着电商的红火,借势而盛的加盟制快递企业,为何在近期接连遭遇“寒潮”?快递企业又该如何加强管理和制度创新,提供更好的服务呢?")); 31 | } 32 | return newsList; 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/item_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_fragment.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 |