├── .gitignore ├── AndroidTech.iml ├── README.md ├── app ├── .gitignore ├── app.iml ├── build.gradle ├── libs │ └── gson-2.3.1.jar ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── android │ │ └── androidtech │ │ └── ApplicationTest.java │ └── main │ ├── AndroidManifest.xml │ ├── assets │ └── jpg_1920_1080.jpg │ ├── java │ └── com │ │ └── android │ │ └── androidtech │ │ ├── CrashHandler.java │ │ ├── GmfApplication.java │ │ ├── GmfSharedPreferences.java │ │ ├── activity │ │ ├── AppStartActivity.java │ │ ├── HomePageActivity.java │ │ ├── base │ │ │ ├── BaseActivity.java │ │ │ ├── BaseFragmentActivity.java │ │ │ ├── FragmentStackManager.java │ │ │ ├── IFragmentStackManager.java │ │ │ └── StackLayout.java │ │ └── ex │ │ │ └── LayoutPerActivity.java │ │ ├── androidsyncadapter │ │ ├── TestContentProvider.java │ │ └── TestSyncService.java │ │ ├── business │ │ └── contact │ │ │ ├── ContactInfo.java │ │ │ └── ContactsManager.java │ │ ├── config │ │ └── PageIndexer.java │ │ ├── database │ │ ├── DBManager.java │ │ └── tables │ │ │ ├── BaseTable.java │ │ │ ├── ContactInfoTable.java │ │ │ └── DBConfig.java │ │ ├── fragment │ │ ├── ContactFragment.java │ │ ├── PerformanceFragment.java │ │ ├── TestThirdFragment.java │ │ ├── UiPerfMoniterFragment.java │ │ ├── base │ │ │ ├── BaseFragment.java │ │ │ └── MyFragmentPagerAdapter.java │ │ ├── homepage │ │ │ ├── GmfBaseViewPager.java │ │ │ └── HomePageFragment.java │ │ └── performance │ │ │ ├── memory │ │ │ ├── BitmapMemeryFragment.java │ │ │ ├── ImageGridFragment.java │ │ │ └── Images.java │ │ │ ├── multitask │ │ │ └── JobScheduleFragment.java │ │ │ └── ui │ │ │ ├── ListViewFragment.java │ │ │ ├── OverDrawFragment.java │ │ │ ├── SingleCard.java │ │ │ ├── UiPerfFragment.java │ │ │ └── ViewStubDemoFragment.java │ │ ├── jobscheduler │ │ ├── JobScheduleManager.java │ │ └── JobSchedulerService.java │ │ ├── monitor │ │ ├── MonitorConfig.java │ │ ├── memory │ │ │ ├── LeakCanaryService.java │ │ │ └── TestDataModel.java │ │ ├── time │ │ │ ├── TimeMonitor.java │ │ │ ├── TimeMonitorConfig.java │ │ │ └── TimeMonitorManager.java │ │ └── ui │ │ │ ├── LogPrinter.java │ │ │ ├── LogPrinterListener.java │ │ │ ├── LogWriteThread.java │ │ │ ├── UiPerfMonitor.java │ │ │ ├── UiPerfMonitorConfig.java │ │ │ └── sampling │ │ │ ├── BaseSampler.java │ │ │ ├── CpuInfo.java │ │ │ └── CpuInfoSampler.java │ │ ├── ui │ │ ├── ListViewWithViewPager.java │ │ ├── MultiCardsView.java │ │ └── TopBar.java │ │ └── utils │ │ ├── CpuFreqSet.java │ │ ├── GLog.java │ │ ├── Util4Common.java │ │ ├── Util4Phone.java │ │ └── dex │ │ ├── ClassLoaderUtil.java │ │ ├── DexUtil.java │ │ ├── MultiDex.java │ │ ├── MultiDexExtractor.java │ │ ├── ReflectUtil.java │ │ └── ZipUtil.java │ └── res │ ├── drawable │ ├── hp_button_right.xml │ ├── ic_red_dot.xml │ └── img_top_back.xml │ ├── layout │ ├── activity_app_start.xml │ ├── activity_homepage.xml │ ├── activity_layout_per.xml │ ├── common_top_bar.xml │ ├── fm_listview.xml │ ├── fm_overdraw.xml │ ├── fm_performance.xml │ ├── fm_ui_perf.xml │ ├── fm_xml_show.xml │ ├── fragment_homepage.xml │ ├── fragment_test_sec.xml │ ├── fragment_third.xml │ ├── fragmet_test.xml │ ├── item_listview_tag.xml │ ├── item_listview_test.xml │ ├── layout_bitmap_show.xml │ ├── list.xml │ ├── list_item.xml │ ├── view_item.xml │ └── viewstub_text_layout1.xml │ ├── menu │ └── menu_layout_per.xml │ ├── mipmap-hdpi │ └── ic_launcher.png │ ├── mipmap-mdpi │ └── ic_launcher.png │ ├── mipmap-xhdpi │ ├── activity_back_normal.png │ ├── activity_back_pressed.png │ ├── ic_launcher.png │ ├── logo.png │ ├── main_bg.png │ ├── maintabbar_button_search_highlight.png │ ├── maintabbar_button_search_normal.png │ ├── maintabbar_button_search_selector.xml │ └── test3.jpg │ ├── mipmap-xxhdpi │ └── ic_launcher.png │ ├── values-w820dp │ └── dimens.xml │ └── values │ ├── attrs.xml │ ├── colors.xml │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── miniimageloder ├── .gitignore ├── build.gradle ├── miniimageloder.iml ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── android │ │ └── miniimageloader │ │ └── ApplicationTest.java │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── android │ │ └── miniimageloader │ │ ├── AsyncTask.java │ │ ├── ImageLoader.java │ │ ├── MiniImageLoader.java │ │ ├── cache │ │ ├── DiskCache.java │ │ ├── DiskLruCache.java │ │ ├── ImageCache.java │ │ └── MemoryCache.java │ │ ├── config │ │ ├── BitmapConfig.java │ │ └── MiniImageLoaderConfig.java │ │ └── utils │ │ ├── BitmapUtil.java │ │ ├── CloseUtil.java │ │ ├── FileUtil.java │ │ └── MLog.java │ └── res │ └── values │ └── strings.xml └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | /local.properties 3 | /.idea/workspace.xml 4 | /.idea/libraries 5 | .DS_Store 6 | /build 7 | /captures 8 | -------------------------------------------------------------------------------- /AndroidTech.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AndroidTech 2 | This is a performance optimization project source code, including optimization of UI/memory and other aspects. 3 | 这是一个教学DEMO,主要是性能优化方面的一些案例,架构主要分成三个方面。 4 | 一.UI层(界面) 5 | 1.全局只有两个Activity,启动页面AppStartActivity和主页面HomepageActivity,其它都是Fragment,所有界面间的切换都是Fragment的切换。 6 | 2.所有的界面都在:com.ycl.androidtech.fragment包下,下一级目录: 7 | (1)base:Fragment基类。 8 | (2)homepage:首页。 9 | (3)ui: 界面设计的一些DEMO。 10 | (4)memery:内存优化的一些DEMO。 11 | 二.工具 12 | 1.监控工具 13 | (1)UI卡顿监控 com.ycl.androidtech.monitor.ui。 14 | (2)内存监控:com.ycl.androidtech.monitor.memory。 15 | (3)耗时上报工具:com.ycl.androidtech.monitor.time 16 | 三.引擎模块 17 | 1.图片引擎:MiniImageLoader. 18 | 2.数据库引擎。 -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 22 5 | buildToolsVersion "22.0.1" 6 | 7 | defaultConfig { 8 | applicationId "com.android.androidtech" 9 | minSdkVersion 15 10 | targetSdkVersion 22 11 | versionCode 1 12 | versionName "1.0" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | compile fileTree(include: ['*.jar'], dir: 'libs') 24 | compile 'com.android.support:appcompat-v7:22.2.0' 25 | debugCompile 'com.squareup.leakcanary:leakcanary-android:1.4-beta2' 26 | releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.4-beta2' 27 | testCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.4-beta2' 28 | compile project(':miniimageloder') 29 | compile files('libs/gson-2.3.1.jar') 30 | } 31 | -------------------------------------------------------------------------------- /app/libs/gson-2.3.1.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lyc7898/AndroidTech/e34b6cf8dfb598ca3fdead27a96f4d035bb714ab/app/libs/gson-2.3.1.jar -------------------------------------------------------------------------------- /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 G:\DevSoft\adt-bundle-windows-x86-20140702\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/androidTest/java/com/android/androidtech/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.android.androidtech; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 14 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 37 | 38 | 39 | 40 | 41 | 44 | 45 | 46 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /app/src/main/assets/jpg_1920_1080.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lyc7898/AndroidTech/e34b6cf8dfb598ca3fdead27a96f4d035bb714ab/app/src/main/assets/jpg_1920_1080.jpg -------------------------------------------------------------------------------- /app/src/main/java/com/android/androidtech/CrashHandler.java: -------------------------------------------------------------------------------- 1 | package com.android.androidtech; 2 | 3 | import android.content.Context; 4 | import android.content.pm.PackageInfo; 5 | import android.content.pm.PackageManager; 6 | import android.os.Build; 7 | import android.os.Environment; 8 | 9 | import com.android.androidtech.utils.GLog; 10 | 11 | import java.io.BufferedWriter; 12 | import java.io.File; 13 | import java.io.FileWriter; 14 | import java.io.IOException; 15 | import java.io.PrintWriter; 16 | import java.text.SimpleDateFormat; 17 | import java.util.Date; 18 | 19 | import android.os.Process; 20 | 21 | /** 22 | * Created by yuchengluo on 2016/6/16. 23 | */ 24 | public class CrashHandler implements Thread.UncaughtExceptionHandler { 25 | private static final String TAG = "CrashHandler"; 26 | private static final String CRASH_FILE_NAME = "crash"; 27 | private static final String CRASH_FILE_PATH = Environment.getExternalStorageDirectory().getPath() + "/log/"; 28 | //log文件的后缀名 29 | private static final String CRASH_FILE_NAME_SUFFIX = ".txt"; 30 | 31 | 32 | //系统默认的异常处理(默认情况下,系统会终止当前的异常程序) 33 | private Thread.UncaughtExceptionHandler mDefaultCrashHandler; 34 | 35 | private Context mContext; 36 | 37 | //这里主要完成初始化工作 38 | public void init(Context context) { 39 | //获取系统默认的异常处理器 40 | mDefaultCrashHandler = Thread.getDefaultUncaughtExceptionHandler(); 41 | //将当前实例设为系统默认的异常处理器 42 | Thread.setDefaultUncaughtExceptionHandler(this); 43 | //获取Context,方便内部使用 44 | mContext = context; 45 | //可以在初始化后在异步线程中上报上次保存的Crash信息 46 | } 47 | 48 | /** 49 | * 这个是最关键的方法,当程序中有未被捕获的异常,系统将会自动调用#uncaughtException方法 50 | * thread为出现未捕获异常的线程,ex为未捕获的异常,有了这个ex,我们就可以得到异常信息。 51 | */ 52 | @Override 53 | public void uncaughtException(Thread thread, Throwable ex) { 54 | try { 55 | //导出异常信息到SD卡中 56 | dumpExceptionToSDCard(ex); 57 | //这里可以通过网络上传异常信息到服务器,便于开发人员分析日志从而解决bug 58 | } catch (IOException e) { 59 | e.printStackTrace(); 60 | } 61 | 62 | //打印出当前调用栈信息 63 | ex.printStackTrace(); 64 | 65 | //如果系统提供了默认的异常处理器,则交给系统去结束我们的程序,否则就由我们自己结束自己 66 | if (mDefaultCrashHandler != null) { 67 | mDefaultCrashHandler.uncaughtException(thread, ex); 68 | } else { 69 | Process.killProcess(Process.myPid()); 70 | } 71 | 72 | } 73 | 74 | private void dumpExceptionToSDCard(Throwable ex) throws IOException { 75 | //如果SD卡不存在或无法使用,则无法把异常信息写入SD卡 76 | if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { 77 | GLog.e(TAG, "sdcard unmounted,skip dump exception"); 78 | return; 79 | } 80 | File dir = new File(CRASH_FILE_PATH); 81 | if (!dir.exists()) { 82 | dir.mkdirs(); 83 | } 84 | long current = System.currentTimeMillis(); 85 | String time = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(current)); 86 | //以当前时间创建log文件 87 | File file = new File(CRASH_FILE_PATH + CRASH_FILE_NAME + time + CRASH_FILE_NAME_SUFFIX); 88 | 89 | try { 90 | PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter(file))); 91 | //导出发生异常的时间 92 | pw.println(time); 93 | //获取手机信息 94 | getPhoneInfo(pw); 95 | 96 | pw.println(); 97 | //导出异常的调用栈信息 98 | ex.printStackTrace(pw); 99 | 100 | pw.close(); 101 | } catch (Exception e) { 102 | GLog.e(TAG, "dump crash info failed"); 103 | } 104 | } 105 | 106 | private void getPhoneInfo(PrintWriter pw) throws PackageManager.NameNotFoundException { 107 | //TODO 上报一些辅助信息,如应用版本号,系统版本号,手机型号等,方便数据分析和归类 108 | } 109 | } -------------------------------------------------------------------------------- /app/src/main/java/com/android/androidtech/GmfApplication.java: -------------------------------------------------------------------------------- 1 | package com.android.androidtech; 2 | 3 | import android.app.Application; 4 | import android.content.Context; 5 | import android.content.res.Configuration; 6 | 7 | import com.android.androidtech.business.contact.ContactsManager; 8 | import com.android.miniimageloader.MiniImageLoader; 9 | import com.squareup.leakcanary.AndroidExcludedRefs; 10 | import com.squareup.leakcanary.LeakCanary; 11 | import com.squareup.leakcanary.RefWatcher; 12 | import com.android.androidtech.database.DBManager; 13 | import com.android.androidtech.monitor.memory.LeakCanaryService; 14 | import com.android.androidtech.monitor.time.TimeMonitorConfig; 15 | import com.android.androidtech.monitor.time.TimeMonitorManager; 16 | /** 17 | * Created by yuchengluo on 2015/6/25. 18 | */ 19 | public class GmfApplication extends Application { 20 | 21 | private static Context mContext = null; 22 | private static RefWatcher mRefWatcher = null; 23 | @Override 24 | protected void attachBaseContext(Context base) { 25 | super.attachBaseContext(base); 26 | mContext = this; 27 | TimeMonitorManager.getInstance().resetTimeMonitor(TimeMonitorConfig.TIME_MONITOR_ID_APPLICATION_START); 28 | //初始化图片引擎 29 | MiniImageLoader.progrem(mContext); 30 | MiniImageLoader.getInstance(); 31 | GmfSharedPreferences.progrem(mContext); 32 | ContactsManager.programStart(mContext); 33 | } 34 | public static Context getmContext(){ 35 | return mContext; 36 | } 37 | @Override 38 | public void onCreate() { 39 | super.onCreate(); 40 | mRefWatcher = LeakCanary.install(this, LeakCanaryService.class, AndroidExcludedRefs.createAppDefaults().build()); 41 | 42 | InitModule(); 43 | TimeMonitorManager.getInstance().getTimeMonitor(TimeMonitorConfig.TIME_MONITOR_ID_APPLICATION_START).recodingTimeTag("ApplicationCreate"); 44 | } 45 | public static RefWatcher getRefWatcher(){ 46 | return mRefWatcher; 47 | } 48 | @Override 49 | public void onTerminate() { 50 | super.onTerminate(); 51 | } 52 | @Override 53 | public void onConfigurationChanged(Configuration newConfig) { 54 | super.onConfigurationChanged(newConfig); 55 | } 56 | @Override 57 | public void onLowMemory() { 58 | super.onLowMemory(); 59 | } 60 | @Override 61 | public void onTrimMemory(int level) { 62 | super.onTrimMemory(level); 63 | } 64 | 65 | public static Context getContext(){ 66 | return mContext; 67 | } 68 | 69 | private void InitModule(){ 70 | DBManager.InitDB(mContext); 71 | CrashHandler crashHandler = new CrashHandler(); 72 | crashHandler.init(this); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /app/src/main/java/com/android/androidtech/GmfSharedPreferences.java: -------------------------------------------------------------------------------- 1 | package com.android.androidtech; 2 | 3 | import android.content.Context; 4 | import android.content.SharedPreferences; 5 | 6 | /** 7 | * Created by yuchengluo on 2016/6/1. 8 | */ 9 | public class GmfSharedPreferences { 10 | private final String SHAREPREFERENCES_NAME = "GmfSharedPreferences"; 11 | private final String KEY_SYNC_SYSTEM_CONTACT_STATE = "KEY_SYNC_SYSTEM_CONTACT_STATE"; 12 | 13 | 14 | 15 | 16 | private static GmfSharedPreferences mInstance = null; 17 | private static Context mContext = null; 18 | protected SharedPreferences mPreferences; 19 | public static void progrem(Context ctx){ 20 | mContext = ctx; 21 | } 22 | public static GmfSharedPreferences getInstance(){ 23 | if(null == mInstance){ 24 | mInstance = new GmfSharedPreferences(); 25 | } 26 | return mInstance; 27 | } 28 | public GmfSharedPreferences(){ 29 | if (mPreferences == null) { 30 | if (mContext != null) { 31 | mPreferences = mContext.getSharedPreferences(SHAREPREFERENCES_NAME, Context.MODE_PRIVATE); 32 | } 33 | } 34 | } 35 | 36 | public void setSyncSysContactState(boolean enable) { 37 | if (mPreferences != null) { 38 | SharedPreferences.Editor editor = mPreferences.edit(); 39 | editor.putBoolean(KEY_SYNC_SYSTEM_CONTACT_STATE, enable); 40 | editor.commit(); 41 | } 42 | } 43 | 44 | public boolean getSyncSysContactState() { 45 | if (mPreferences != null) { 46 | return mPreferences.getBoolean(KEY_SYNC_SYSTEM_CONTACT_STATE, false); 47 | } 48 | return true; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /app/src/main/java/com/android/androidtech/activity/AppStartActivity.java: -------------------------------------------------------------------------------- 1 | package com.android.androidtech.activity; 2 | 3 | /** 4 | * First activity. 5 | * */ 6 | import android.animation.Animator; 7 | import android.animation.AnimatorSet; 8 | import android.animation.ObjectAnimator; 9 | import android.app.Activity; 10 | import android.content.Intent; 11 | import android.os.Bundle; 12 | import android.os.Handler; 13 | import android.os.Message; 14 | import android.view.View; 15 | import android.view.animation.Animation; 16 | import android.view.animation.AnimationSet; 17 | import android.view.animation.RotateAnimation; 18 | import android.view.animation.ScaleAnimation; 19 | import android.widget.ImageView; 20 | 21 | import com.android.androidtech.R; 22 | import com.android.androidtech.monitor.time.TimeMonitorConfig; 23 | import com.android.androidtech.monitor.time.TimeMonitorManager; 24 | 25 | 26 | public class AppStartActivity extends Activity { 27 | 28 | ImageView mLogo = null; 29 | private final int TIME_ANIMATION = 1500; 30 | @Override 31 | protected void onCreate(Bundle savedInstanceState) { 32 | TimeMonitorManager.getInstance().getTimeMonitor(TimeMonitorConfig.TIME_MONITOR_ID_APPLICATION_START).recodingTimeTag("AppStartActivity_create"); 33 | super.onCreate(savedInstanceState); 34 | 35 | setContentView(R.layout.activity_app_start); 36 | mLogo = (ImageView) this.findViewById(R.id.logo); 37 | //mStartHandler.sendEmptyMessageDelayed(0,1000); 38 | // useAnimation(); 39 | useAnimator(); 40 | TimeMonitorManager.getInstance().getTimeMonitor(TimeMonitorConfig.TIME_MONITOR_ID_APPLICATION_START).recodingTimeTag("AppStartActivity_createOver"); 41 | } 42 | 43 | @Override 44 | protected void onStart() { 45 | super.onStart(); 46 | TimeMonitorManager.getInstance().getTimeMonitor(TimeMonitorConfig.TIME_MONITOR_ID_APPLICATION_START).end("AppStartActivity_start", false); 47 | } 48 | 49 | /* 50 | AlphaAnimation 51 | ScaleAnimation 52 | TranslateAnimation 53 | RotateAnimation 54 | * */ 55 | private void useAnimation() { 56 | Animation mRota = new RotateAnimation(0, 360, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); 57 | ScaleAnimation mScale = new ScaleAnimation(0.0f, 1f, 0.0f, 1f, 58 | Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); 59 | mScale.setAnimationListener(new Animation.AnimationListener() { 60 | @Override 61 | public void onAnimationStart(Animation animation) { 62 | 63 | } 64 | 65 | @Override 66 | public void onAnimationEnd(Animation animation) { 67 | mStartHandler.sendEmptyMessageDelayed(0, 0); 68 | } 69 | 70 | @Override 71 | public void onAnimationRepeat(Animation animation) { 72 | 73 | } 74 | }); 75 | AnimationSet animationSet = new AnimationSet(true); 76 | animationSet.addAnimation(mRota); 77 | animationSet.addAnimation(mScale); 78 | animationSet.setDuration(TIME_ANIMATION); 79 | mLogo.startAnimation(animationSet); 80 | } 81 | 82 | //AnimatorSet 83 | private void useAnimator() { 84 | mLogo.setLayerType(View.LAYER_TYPE_HARDWARE,null); 85 | ObjectAnimator scalex = ObjectAnimator.ofFloat(mLogo, "scaleX", 0, 1); 86 | ObjectAnimator scaley = ObjectAnimator.ofFloat(mLogo, "scaleY", 0, 1); 87 | ObjectAnimator rotation = ObjectAnimator.ofFloat(mLogo, "rotation", 0.0f, 360f); 88 | rotation.addListener(new ObjectAnimator.AnimatorListener() { 89 | @Override 90 | public void onAnimationStart(Animator animation) { 91 | } 92 | 93 | @Override 94 | public void onAnimationEnd(Animator animation) { 95 | mLogo.setLayerType(View.LAYER_TYPE_NONE,null); 96 | mStartHandler.sendEmptyMessageDelayed(0, 0); 97 | } 98 | 99 | @Override 100 | public void onAnimationCancel(Animator animation) { 101 | } 102 | 103 | @Override 104 | public void onAnimationRepeat(Animator animation) { 105 | } 106 | }); 107 | AnimatorSet mSetPlayer = new AnimatorSet(); 108 | mSetPlayer.setDuration(TIME_ANIMATION); 109 | mSetPlayer.play(scalex).with(scaley).with(rotation); 110 | mSetPlayer.start(); 111 | } 112 | 113 | private Handler mStartHandler = new Handler() { 114 | @Override 115 | public void handleMessage(Message msg) { 116 | //test 117 | Intent it = new Intent(AppStartActivity.this, HomePageActivity.class); 118 | startActivity(it); 119 | finish(); 120 | } 121 | }; 122 | } 123 | -------------------------------------------------------------------------------- /app/src/main/java/com/android/androidtech/activity/HomePageActivity.java: -------------------------------------------------------------------------------- 1 | package com.android.androidtech.activity; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.view.KeyEvent; 6 | 7 | 8 | import com.android.androidtech.R; 9 | import com.android.androidtech.activity.base.BaseFragmentActivity; 10 | import com.android.androidtech.activity.base.StackLayout; 11 | import com.android.androidtech.fragment.base.BaseFragment; 12 | import com.android.androidtech.fragment.homepage.HomePageFragment; 13 | import com.android.androidtech.utils.GLog; 14 | 15 | /** 16 | * Created by yuchengluo on 2015/6/26. 17 | */ 18 | public class HomePageActivity extends BaseFragmentActivity { 19 | 20 | private final static String TAG = "MusicMainWithMiniBarActivity"; 21 | private int mFocusedTextColor, mTextColor; 22 | private StackLayout mMainFragmentContainer; 23 | private static final String MAIN_FRAGMENT_CONTENT = "main_content"; 24 | public static final int CONTAINER_ID = R.id.homepage_fragment_detail; 25 | private int mViewIndex = TAB_VIEW_00; 26 | 27 | 28 | @Override 29 | public void onCreate(Bundle savedInstanceState) { 30 | super.onCreate(savedInstanceState); 31 | setContentView(R.layout.activity_homepage); 32 | mMainFragmentContainer = (StackLayout) findViewById(R.id.homepage_fragment_detail); 33 | makeNewContentFragmentStackManager(CONTAINER_ID, MAIN_FRAGMENT_CONTENT, mMainFragmentContainer); 34 | Bundle data = new Bundle(); 35 | data.putInt(APP_INDEX_KEY, mViewIndex); 36 | addSecondFragment(HomePageFragment.class, data, null); 37 | } 38 | 39 | @Override 40 | protected void onNewIntent(Intent intent) { 41 | super.onNewIntent(intent); 42 | setIntent(intent); 43 | } 44 | 45 | @Override 46 | public boolean onKeyDown(int keyCode, KeyEvent event) { 47 | switch (keyCode) { 48 | case KeyEvent.KEYCODE_BACK: 49 | BaseFragment top = top(); 50 | if (top != null && top.onKeyDown(keyCode, event)) { 51 | return true; 52 | } 53 | if (size() > 1) { 54 | popBackStack(); 55 | return true; 56 | } 57 | break; 58 | case KeyEvent.KEYCODE_MENU: 59 | return true; 60 | } 61 | 62 | return super.onKeyDown(keyCode, event); 63 | } 64 | 65 | private static final int MSG_REFRESH_MUSIC_CIRCLE = 10000; 66 | 67 | @Override 68 | public void onStart() { 69 | super.onStart(); 70 | } 71 | 72 | @Override 73 | protected void onResume() { 74 | super.onResume(); 75 | GLog.d(TAG, "On Resume" + getClass().getSimpleName()); 76 | } 77 | 78 | @Override 79 | protected void onPause() { 80 | super.onPause(); 81 | GLog.d(TAG, "onPause " + getClass().getSimpleName()); 82 | } 83 | 84 | @Override 85 | protected void onDestroy() { 86 | super.onDestroy(); 87 | } 88 | 89 | @Override 90 | public void onStop() { 91 | super.onStop(); 92 | } 93 | 94 | @Override 95 | public void finish() { 96 | super.finish(); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /app/src/main/java/com/android/androidtech/activity/base/BaseActivity.java: -------------------------------------------------------------------------------- 1 | package com.android.androidtech.activity.base; 2 | 3 | import android.os.Build; 4 | import android.os.Bundle; 5 | import android.support.v4.app.FragmentActivity; 6 | import android.view.View; 7 | import android.view.Window; 8 | import android.view.WindowManager; 9 | 10 | import com.android.androidtech.config.PageIndexer; 11 | 12 | 13 | /** 14 | * Created by yuchengluo on 2015/6/26. 15 | */ 16 | public abstract class BaseActivity extends FragmentActivity implements PageIndexer { 17 | @Override 18 | protected void onCreate(Bundle savedInstanceState) { 19 | super.onCreate(savedInstanceState); 20 | requestWindowFeature(Window.FEATURE_NO_TITLE); 21 | if (Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { 22 | Window window = getWindow(); 23 | window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); 24 | window.getDecorView().setSystemUiVisibility( 25 | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE); 26 | window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); 27 | window.setStatusBarColor(0); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /app/src/main/java/com/android/androidtech/activity/base/BaseFragmentActivity.java: -------------------------------------------------------------------------------- 1 | package com.android.androidtech.activity.base; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.content.Intent; 5 | import android.os.Bundle; 6 | import android.support.v4.app.FragmentManager; 7 | 8 | import com.android.androidtech.fragment.base.BaseFragment; 9 | 10 | import java.util.HashMap; 11 | 12 | /** 13 | * 14 | * @author yuchengluo 2015-6-25 15 | */ 16 | @SuppressLint("Recycle") 17 | public abstract class BaseFragmentActivity extends BaseActivity { 18 | 19 | private static final String TAG = "BaseFragmentActivity"; 20 | 21 | private FragmentStackManager mFragmentStackManager; 22 | 23 | protected FragmentManager mManager; 24 | 25 | private int mContainerId; 26 | 27 | private String mContentTag; 28 | 29 | private StackLayout mMainFragmentContainer; 30 | 31 | protected static HashMap fragmentFields; 32 | protected int mSelectedIndex; 33 | protected Bundle mArgs; 34 | protected Class mFragmentCls; 35 | 36 | @Override 37 | protected void onCreate(Bundle savedInstanceState) { 38 | super.onCreate(savedInstanceState); 39 | 40 | mManager = getSupportFragmentManager(); 41 | } 42 | 43 | private void setContainerId(int id) { 44 | this.mContainerId = id; 45 | } 46 | 47 | private void setContentTag(String tag) { 48 | this.mContentTag = TAG; 49 | } 50 | 51 | private void setStackLayout(StackLayout layout) { 52 | this.mMainFragmentContainer = layout; 53 | } 54 | 55 | protected void makeNewContentFragmentStackManager(int id, String tag, StackLayout layout) { 56 | setContainerId(id); 57 | setContentTag(tag); 58 | setStackLayout(layout); 59 | mFragmentStackManager = new FragmentStackManager(this, mManager, mContainerId, mContentTag, 60 | mMainFragmentContainer); 61 | } 62 | 63 | public void addSecondFragment(Class cls, Bundle args, HashMap fields) { 64 | if (args == null) { 65 | args = new Bundle(); 66 | } 67 | BaseFragment topFragment = mFragmentStackManager.top(); 68 | mFragmentStackManager.push(cls, args, fields); 69 | } 70 | 71 | public void popBackStack(int requestCode, int resultCode, Intent data) { 72 | mFragmentStackManager.pop(requestCode, resultCode, data); 73 | } 74 | 75 | public void popBackStack() { 76 | mFragmentStackManager.pop(-100, -100, null); 77 | } 78 | 79 | public void clearBackStack() { 80 | mFragmentStackManager.clear(); 81 | } 82 | 83 | 84 | public void addContent() { 85 | addContent(-1); 86 | } 87 | 88 | public BaseFragment top() { 89 | return mFragmentStackManager.top(); 90 | } 91 | 92 | protected int size() { 93 | return mFragmentStackManager.size(); 94 | } 95 | 96 | public void addContent(int isDefaultTabs) { 97 | mFragmentStackManager.push(mFragmentCls, mArgs, fragmentFields); 98 | } 99 | 100 | public BaseFragment getCurrentFragment() { 101 | return top(); 102 | } 103 | 104 | } 105 | -------------------------------------------------------------------------------- /app/src/main/java/com/android/androidtech/activity/base/IFragmentStackManager.java: -------------------------------------------------------------------------------- 1 | package com.android.androidtech.activity.base; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | 6 | 7 | import com.android.androidtech.fragment.base.BaseFragment; 8 | 9 | import java.util.HashMap; 10 | 11 | /** 12 | * Created by yuchengluo on 2015/6/26. 13 | */ 14 | public interface IFragmentStackManager { 15 | void push(Class cls, Bundle args, HashMap hashMap); 16 | 17 | boolean pop(int requestCode, int resultCode, Intent data); 18 | 19 | boolean empty(); 20 | 21 | boolean full(); 22 | 23 | void clear(); 24 | 25 | int size(); 26 | 27 | BaseFragment top(); 28 | 29 | void destroy(); 30 | 31 | } 32 | -------------------------------------------------------------------------------- /app/src/main/java/com/android/androidtech/activity/ex/LayoutPerActivity.java: -------------------------------------------------------------------------------- 1 | package com.android.androidtech.activity.ex; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.os.Handler; 6 | import android.os.Message; 7 | import android.os.Bundle; 8 | import android.widget.TextView; 9 | 10 | import com.android.androidtech.R; 11 | import com.android.androidtech.monitor.memory.TestDataModel; 12 | 13 | import java.lang.ref.WeakReference; 14 | 15 | public class LayoutPerActivity extends Activity { 16 | private final String TAG = "LayoutPerActivity"; 17 | private NewHandler mHandler = new NewHandler(this); 18 | @Override 19 | protected void onCreate(Bundle savedInstanceState) { 20 | super.onCreate(savedInstanceState); 21 | this.getWindow().setBackgroundDrawable(null); 22 | setContentView(R.layout.activity_layout_per); 23 | //make a leak object 24 | TextView test = (TextView)this.findViewById(R.id.layout_per_txt_1); 25 | TestDataModel.getInstance().setRetainedTextView(test); 26 | } 27 | private static class NewHandler extends Handler{ 28 | private WeakReference mContext = null; 29 | public NewHandler(Context ctx){ 30 | mContext = new WeakReference(ctx); 31 | } 32 | @Override 33 | public void handleMessage(Message msg) { 34 | super.handleMessage(msg); 35 | } 36 | } 37 | private void doGetDataAsyncTask(){ 38 | Message msg = Message.obtain(); 39 | mHandler.sendMessage(msg); 40 | } 41 | 42 | @Override 43 | protected void onDestroy() { 44 | super.onDestroy(); 45 | mHandler.removeCallbacksAndMessages(null); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /app/src/main/java/com/android/androidtech/androidsyncadapter/TestContentProvider.java: -------------------------------------------------------------------------------- 1 | package com.android.androidtech.androidsyncadapter; 2 | 3 | import android.accounts.Account; 4 | import android.accounts.AccountManager; 5 | import android.content.ContentProvider; 6 | import android.content.ContentResolver; 7 | import android.content.ContentValues; 8 | import android.content.Context; 9 | import android.database.Cursor; 10 | import android.net.Uri; 11 | import android.os.Bundle; 12 | import android.support.annotation.Nullable; 13 | 14 | /** 15 | * Created by yuchengluo on 2016/7/14. 16 | */ 17 | 18 | public class TestContentProvider extends ContentProvider { 19 | public static final String AUTHKEY = "com.android.androidtech.androidsyncadapter"; 20 | public static final String CONTENT_URI_BASE = "content://" + AUTHKEY; 21 | public static final String TABLE_NAME = "data"; 22 | public static final Uri CONTENT_URI = Uri.parse(CONTENT_URI_BASE + "/" + TABLE_NAME); 23 | 24 | @Override 25 | public boolean onCreate() { 26 | return true; 27 | } 28 | 29 | @Nullable 30 | @Override 31 | public Cursor query(Uri uri, String[] projection, String selection, 32 | String[] selectionArgs, String sortOrder) { 33 | return null; 34 | } 35 | 36 | @Nullable 37 | @Override 38 | public String getType(Uri uri) { 39 | return new String(); 40 | } 41 | 42 | @Nullable 43 | @Override 44 | public Uri insert(Uri uri, ContentValues values) { 45 | return null; 46 | } 47 | 48 | @Override 49 | public int delete(Uri uri, String selection, String[] selectionArgs) { 50 | return 0; 51 | } 52 | 53 | @Override 54 | public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { 55 | return 0; 56 | } 57 | } -------------------------------------------------------------------------------- /app/src/main/java/com/android/androidtech/androidsyncadapter/TestSyncService.java: -------------------------------------------------------------------------------- 1 | package com.android.androidtech.androidsyncadapter; 2 | 3 | import android.accounts.Account; 4 | import android.app.Service; 5 | import android.content.AbstractThreadedSyncAdapter; 6 | import android.content.ContentProviderClient; 7 | import android.content.Context; 8 | import android.content.Intent; 9 | import android.content.SyncResult; 10 | import android.os.Bundle; 11 | import android.os.IBinder; 12 | 13 | /** 14 | * Created by yuchengluo on 2016/7/14. 15 | */ 16 | 17 | public class TestSyncService extends Service { 18 | private static final Object sSyncAdapterLock = new Object(); 19 | private static TestSyncAdapter mSyncAdapter = null; 20 | @Override 21 | public void onCreate() { 22 | synchronized (sSyncAdapterLock) { 23 | if (mSyncAdapter == null) { 24 | mSyncAdapter = new TestSyncAdapter(getApplicationContext(), true); 25 | } 26 | } 27 | } 28 | 29 | @Override 30 | public IBinder onBind(Intent intent) { 31 | return mSyncAdapter.getSyncAdapterBinder(); 32 | } 33 | 34 | static class TestSyncAdapter extends AbstractThreadedSyncAdapter { 35 | public TestSyncAdapter(Context context, boolean autoInitialize) { 36 | super(context, autoInitialize); 37 | } 38 | @Override 39 | public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult) { 40 | //具体的同步操作,这里主要是为了提高进程优先级 41 | //getContext().getContentResolver().notifyChange(XXAccountProvider.CONTENT_URI, null, false); 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /app/src/main/java/com/android/androidtech/business/contact/ContactInfo.java: -------------------------------------------------------------------------------- 1 | package com.android.androidtech.business.contact; 2 | 3 | import android.os.Parcelable; 4 | 5 | import java.io.Serializable; 6 | 7 | /** 8 | * Created by yuchengluo on 2016/5/31. 9 | */ 10 | public class ContactInfo{ 11 | private long contactId = -1; 12 | private String contactName,contactNum; 13 | public ContactInfo(long id,String name,String number){ 14 | this.contactId = id; 15 | this.contactName = name; 16 | this.contactNum = number; 17 | } 18 | public void setName(String name){ 19 | this.contactName = name; 20 | } 21 | public String getContactName(){ 22 | return this.contactName; 23 | } 24 | public void setNumber(String number){ 25 | this.contactNum = number; 26 | } 27 | public String getContactNum(){ 28 | return this.contactNum; 29 | } 30 | public void setID(long id){ 31 | this.contactId = id; 32 | } 33 | public long getContactId(){ 34 | return contactId; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /app/src/main/java/com/android/androidtech/business/contact/ContactsManager.java: -------------------------------------------------------------------------------- 1 | package com.android.androidtech.business.contact; 2 | 3 | import android.content.Context; 4 | import android.database.Cursor; 5 | 6 | import com.android.androidtech.database.tables.ContactInfoTable; 7 | import com.android.androidtech.monitor.time.TimeMonitor; 8 | import com.android.androidtech.monitor.time.TimeMonitorConfig; 9 | import com.android.androidtech.monitor.time.TimeMonitorManager; 10 | import com.android.androidtech.utils.GLog; 11 | 12 | import java.io.IOException; 13 | import java.util.ArrayList; 14 | 15 | /** 16 | * Created by yuchengluo on 2016/3/25. 17 | */ 18 | public class ContactsManager { 19 | private static ContactsManager mContactsManager = null; 20 | private static Context mContext = null; 21 | private ArrayList contactInfos = new ArrayList(); 22 | private ContactInfoTable mContactInfoTable = null; 23 | private final String TAG = "ContactsManager"; 24 | 25 | public static void programStart(Context ctx) { 26 | mContext = ctx; 27 | } 28 | 29 | public static synchronized ContactsManager getInstance() { 30 | if (null == mContactsManager) { 31 | mContactsManager = new ContactsManager(); 32 | } 33 | return mContactsManager; 34 | } 35 | 36 | public ContactsManager() { 37 | mContactInfoTable = new ContactInfoTable(mContext); 38 | } 39 | 40 | public ArrayList createTestContactInfo() { 41 | TimeMonitorManager.getInstance().getTimeMonitor(TimeMonitorConfig.TIME_MONITOR_ID_SQLITE).startMoniter(); 42 | mContactInfoTable.getSqliteDB().beginTransaction(); 43 | try { 44 | for (int i = 1; i <= 10000; i++) { 45 | ContactInfo info = new ContactInfo(i, "姓名" + i, "1389832" + (0000 + i)); 46 | contactInfos.add(info); 47 | boolean insert = mContactInfoTable.insertContactInfoForStat(info); 48 | GLog.d(TAG, "insert Contact info :" + insert); 49 | } 50 | mContactInfoTable.getSqliteDB().setTransactionSuccessful(); 51 | } catch (Exception e) { 52 | GLog.e(TAG,e.getMessage()); 53 | }finally { 54 | mContactInfoTable.getSqliteDB().endTransaction(); 55 | } 56 | TimeMonitorManager.getInstance().getTimeMonitor(TimeMonitorConfig.TIME_MONITOR_ID_SQLITE).end("wirte_sql", false); 57 | return contactInfos; 58 | } 59 | public ArrayList getTestContactInfo(){ 60 | TimeMonitorManager.getInstance().getTimeMonitor(TimeMonitorConfig.TIME_MONITOR_ID_SQLITE).startMoniter(); 61 | ArrayList songList = mContactInfoTable.getAllContacts(); 62 | TimeMonitorManager.getInstance().getTimeMonitor(TimeMonitorConfig.TIME_MONITOR_ID_SQLITE).end("read_sql", false); 63 | GLog.d(TAG,"getTestContactInfo SIZE:" + songList.size()); 64 | return songList; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /app/src/main/java/com/android/androidtech/config/PageIndexer.java: -------------------------------------------------------------------------------- 1 | package com.android.androidtech.config; 2 | 3 | /** 4 | * Created by yuchengluo on 2015/6/26. 5 | * 各页面的定义,如页面的ID 6 | */ 7 | public interface PageIndexer { 8 | 9 | //首页TAB ID 10 | public static final int TAB_VIEW_00 = 0; 11 | public static final int TAB_VIEW_01 = 1; 12 | public static final int TAB_VIEW_02 = 2; 13 | public static final int TAB_VIEW_03 = 3; 14 | /* 15 | * 首页三个页面index 16 | */ 17 | public final static int APP_MAIN_1 = 1000; 18 | public final static int APP_MAIN_2 = 1001; 19 | public final static int APP_MAIN_3 = 1002; 20 | public final static int APP_MAIN_4 = 1003; 21 | 22 | //Activity跳转Bundle Key 23 | public final static String APP_INDEX_KEY = "app_index_key"; 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/java/com/android/androidtech/database/DBManager.java: -------------------------------------------------------------------------------- 1 | package com.android.androidtech.database; 2 | 3 | import android.content.Context; 4 | import android.database.sqlite.SQLiteDatabase; 5 | import android.database.sqlite.SQLiteOpenHelper; 6 | 7 | import com.android.androidtech.database.tables.ContactInfoTable; 8 | import com.android.androidtech.database.tables.DBConfig; 9 | import com.android.androidtech.utils.GLog; 10 | 11 | 12 | /** 13 | * * Copyright (C) 1998-2014 TENCENT Inc.All Rights Reserved. 14 | * 15 | * @author yuchengluo 16 | * @Description: DB管理类,主要为创建表及DB升级 17 | * @date 2013-2-15 modify 18 | */ 19 | public class DBManager implements DBConfig { 20 | private static final String TAG = "DBManager"; 21 | private static SQLiteDatabase mDB = null; 22 | private static SQLiteDatabase mDBReadable = null; 23 | private static DatabaseHelper mDatabaseHelper = null; 24 | 25 | public static void close() { 26 | if (mDB != null) { 27 | try { 28 | mDB.close(); 29 | } catch (Exception e) { 30 | } 31 | mDB = null; 32 | GLog.i(TAG, "[DBManager]close()"); 33 | } 34 | if (mDBReadable != null) { 35 | try { 36 | mDBReadable.close(); 37 | } catch (Exception e) { 38 | } 39 | mDBReadable = null; 40 | GLog.i(TAG, "[DBManager] mDBReadable close()"); 41 | } 42 | } 43 | 44 | private static DatabaseHelper getDatabaseHelper(Context AppContex) { 45 | if (mDatabaseHelper == null) { 46 | mDatabaseHelper = new DatabaseHelper(AppContex); 47 | } 48 | return mDatabaseHelper; 49 | } 50 | 51 | /** 52 | * @param AppContext 这里的Context一定要用ApplicationContext 初始化DB 53 | * @return 54 | */ 55 | public static synchronized void InitDB(Context AppContext) { 56 | // GLog.i(TAG, "getDB"); 57 | // 暂时在启动初始化,如果初始化时间较长,在第一次使用初使化也是一种考虑方法 58 | getWriteDB(AppContext); 59 | getReadDB(AppContext); 60 | } 61 | 62 | /** 63 | * 获取写DB 64 | */ 65 | public static synchronized SQLiteDatabase getWriteDB(Context AppContext) { 66 | // GLog.i(TAG, "getDB"); 67 | if (mDB == null || !mDB.isOpen()) { 68 | mDB = getDatabaseHelper(AppContext).getWritableDatabase(); 69 | // if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) { 70 | // // mDB.enableWriteAheaGLogging(); 71 | // GLog.i(TAG, "[DBManager]getDB() enableWriteAheaGLogging"); 72 | // } 73 | GLog.i(TAG, "[DBManager]getWriteDB()"); 74 | } 75 | return mDB; 76 | } 77 | 78 | /** 79 | * 获取只读DBHelper 80 | */ 81 | public static synchronized SQLiteDatabase getReadDB(Context AppContext) { 82 | // GLog.i(TAG, "getDB"); 83 | if (mDBReadable == null || !mDBReadable.isOpen()) { 84 | mDBReadable = getDatabaseHelper(AppContext).getReadableDatabase(); 85 | 86 | GLog.i(TAG, "[DBManager]getReadDB()"); 87 | } 88 | return mDBReadable; 89 | } 90 | 91 | private static class DatabaseHelper extends SQLiteOpenHelper { 92 | 93 | // 这里的Context一定要用ApplicationContext 94 | private Context mContext = null; 95 | 96 | DatabaseHelper(Context context) { 97 | super(context, DATABASE_FILE, null, DBConfig.DB_VER); 98 | mContext = context; 99 | } 100 | 101 | @Override 102 | public void onCreate(SQLiteDatabase db) { 103 | // 创建+读入歌曲数据库表 104 | GLog.i(TAG, "[DatabaseHelper]CreateDB :"); 105 | // 创建表,如果有新增字段必须进入CreateTable里面来加入新的字段 106 | createTable(db); 107 | } 108 | 109 | @Override 110 | public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 111 | 112 | } 113 | 114 | @Override 115 | public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) { 116 | try { 117 | GLog.i(TAG, "数据库降级 old:" + oldVersion + " newVersion:" + newVersion); 118 | 119 | //用来触发重新扫描 120 | } catch (Exception e) { 121 | GLog.e(TAG, e); 122 | } 123 | } 124 | 125 | private void createTable(SQLiteDatabase db) { 126 | //创建表 127 | db.execSQL("DROP TABLE IF EXISTS " + ContactInfoTable.CONTACT_INFO_TABLE); 128 | //创建表中具体的字段 129 | db.execSQL(ContactInfoTable.TABLE_CREATE); 130 | } 131 | } 132 | } 133 | 134 | -------------------------------------------------------------------------------- /app/src/main/java/com/android/androidtech/database/tables/BaseTable.java: -------------------------------------------------------------------------------- 1 | package com.android.androidtech.database.tables; 2 | 3 | import android.content.ContentResolver; 4 | import android.content.Context; 5 | import android.database.Cursor; 6 | import android.database.sqlite.SQLiteDatabase; 7 | import android.database.sqlite.SQLiteStatement; 8 | 9 | import com.android.androidtech.database.DBManager; 10 | import com.android.androidtech.utils.GLog; 11 | 12 | 13 | /** 14 | * 基于SqliteDataBase存储的数据抽象表 15 | * Created by yuchengluo on 2015/6/29. 16 | */ 17 | public abstract class BaseTable { 18 | /** 19 | * 上下文指针 20 | */ 21 | private Context mContext; 22 | 23 | /** 24 | * 构造函数 25 | * 26 | * @param context 27 | */ 28 | public BaseTable(Context context) { 29 | mContext = context; 30 | } 31 | 32 | /** 33 | * 获取上下文指针 34 | * 35 | * @return 36 | */ 37 | public Context getContext() { 38 | return mContext; 39 | } 40 | 41 | /** 42 | * 设置上下文指针 43 | * 44 | * @param context 45 | */ 46 | public void setContext(Context context) { 47 | this.mContext = context; 48 | 49 | } 50 | 51 | /** 52 | * 获取ContentResolver 53 | * 54 | * @return 55 | */ 56 | public ContentResolver getContentResolver() { 57 | return (mContext == null) ? null : mContext.getContentResolver(); 58 | } 59 | 60 | /** 61 | * 获取表所属数据库 62 | * 63 | * @return 64 | */ 65 | public SQLiteDatabase getSqliteDB() { 66 | return DBManager.getWriteDB(mContext.getApplicationContext()); 67 | } 68 | 69 | /** 70 | * 获取表读数据库 71 | * 72 | * @return 73 | */ 74 | public SQLiteDatabase getSqliteReadDB() { 75 | return DBManager.getReadDB(mContext.getApplicationContext()); 76 | } 77 | /** 78 | * 获取SQL STATEMENT 79 | * */ 80 | public abstract SQLiteStatement getSQLiteStatement(); 81 | /** 82 | * 获取表名 83 | * 84 | * @return 85 | */ 86 | public abstract String getTableName(); 87 | /* 88 | * 获取所有键名 89 | * */ 90 | public abstract String[] getAllKey(); 91 | /** 92 | * @author kenzhang 查询表中元素数量,比原有的cursor.getCount()更高效 93 | * @return 94 | */ 95 | public int getTotalCount() { 96 | Cursor cursor = null; 97 | try { 98 | SQLiteDatabase sqliteDb = getSqliteDB(); 99 | if (sqliteDb != null) { 100 | cursor = sqliteDb.rawQuery("select count(*) from " + getTableName(), null); 101 | if (cursor != null && cursor.moveToFirst()) { 102 | int i = cursor.getInt(0); 103 | return i; 104 | } 105 | } 106 | } catch (Exception e) { 107 | GLog.e("BaseTable", e); 108 | } finally { 109 | if (cursor != null) { 110 | cursor.close(); 111 | } 112 | } 113 | return -1; 114 | } 115 | 116 | protected static String kv(String key, String value) { 117 | return key + "=" + value; 118 | } 119 | 120 | protected static String kv(String key, long value) { 121 | return key + "=" + value; 122 | } 123 | 124 | protected static String kv(String key, int value) { 125 | return key + "=" + value; 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /app/src/main/java/com/android/androidtech/database/tables/ContactInfoTable.java: -------------------------------------------------------------------------------- 1 | package com.android.androidtech.database.tables; 2 | 3 | import android.content.ContentValues; 4 | import android.content.Context; 5 | import android.database.Cursor; 6 | import android.database.sqlite.SQLiteStatement; 7 | 8 | import com.android.androidtech.business.contact.ContactInfo; 9 | 10 | import java.util.ArrayList; 11 | 12 | /** 13 | * Created by yuchengluo on 2015/6/29. 14 | */ 15 | public class ContactInfoTable extends BaseTable { 16 | private static String TAG = "ContactInfoTable"; 17 | public static final String CONTACT_INFO_TABLE = "ContactInfo_table"; // 账户信息table 18 | private static final String KEY_CONTACT_ID = "contack_num"; 19 | private static final String KEY_CONTACT_NAME = "contack_name"; 20 | private static final String KEY_USER_PHONE_NUM = "contack_phonenumber"; 21 | private SQLiteStatement mSQLiteStatement = null; 22 | public static final String TABLE_CREATE = "create table if not exists " + CONTACT_INFO_TABLE + " (" + KEY_CONTACT_ID 23 | + " LONG primary key , " + KEY_CONTACT_NAME + " TEXT," + KEY_USER_PHONE_NUM + " TEXT " 24 | + ");"; 25 | public final String STR_INSERT_STATEMENT_CONTACTS = "insert into " + CONTACT_INFO_TABLE 26 | + "(" + KEY_CONTACT_ID 27 | + "," + KEY_CONTACT_NAME 28 | + "," + KEY_USER_PHONE_NUM 29 | + ") values(?,?,?)"; 30 | 31 | /** 32 | * 构造函数 33 | * 34 | * @param context 35 | */ 36 | public ContactInfoTable(Context context) { 37 | super(context); 38 | } 39 | 40 | @Override 41 | public String getTableName() { 42 | return CONTACT_INFO_TABLE; 43 | } 44 | 45 | @Override 46 | public String[] getAllKey() { 47 | return new String[]{ 48 | CONTACT_INFO_TABLE + "." + KEY_CONTACT_ID, 49 | CONTACT_INFO_TABLE + "." + KEY_CONTACT_NAME, 50 | CONTACT_INFO_TABLE + "." + KEY_USER_PHONE_NUM 51 | }; 52 | } 53 | 54 | @Override 55 | public SQLiteStatement getSQLiteStatement() { 56 | if (null == mSQLiteStatement) { 57 | mSQLiteStatement = getSqliteDB().compileStatement(STR_INSERT_STATEMENT_CONTACTS); 58 | } 59 | return mSQLiteStatement; 60 | } 61 | 62 | public boolean insertContactInfoForStat(ContactInfo info) { 63 | getSQLiteStatement().clearBindings(); 64 | getSQLiteStatement().bindLong(1, info.getContactId()); 65 | getSQLiteStatement().bindString(2, info.getContactName()); 66 | getSQLiteStatement().bindString(3, info.getContactNum()); 67 | return getSQLiteStatement().executeInsert() > 0; 68 | } 69 | 70 | public boolean insertContactInfo(ContactInfo info) { 71 | return getSqliteDB().insert(CONTACT_INFO_TABLE, null, transContactInfo(info)) > 0; 72 | } 73 | 74 | public boolean updateContactInfo(ContactInfo info) { 75 | return getSqliteDB().update(CONTACT_INFO_TABLE, transContactInfo(info), kv(KEY_CONTACT_ID, info.getContactId()), null) > 0; 76 | } 77 | 78 | public boolean deleteContactInfo(ContactInfo info) { 79 | return getSqliteDB().delete(CONTACT_INFO_TABLE, kv(KEY_CONTACT_ID, info.getContactId()), null) > 0; 80 | } 81 | 82 | public ArrayList getAllContacts() { 83 | ArrayList songList = new ArrayList(); 84 | Cursor cursors = null; 85 | cursors = getSqliteDB().query(true, 86 | CONTACT_INFO_TABLE, 87 | new String[]{KEY_CONTACT_ID, KEY_CONTACT_NAME, KEY_USER_PHONE_NUM}, 88 | null 89 | , null, null, null, null, null); 90 | if(null != cursors && cursors.moveToFirst()){ 91 | do{ 92 | songList.add(transContactCursor(cursors)); 93 | }while(cursors.moveToNext()); 94 | } 95 | return songList; 96 | } 97 | private ContactInfo transContactCursor(Cursor cursor){ 98 | long id = cursor.getLong(cursor.getColumnIndex(KEY_CONTACT_ID)); 99 | String name = cursor.getString(cursor.getColumnIndex(KEY_CONTACT_NAME)); 100 | String number = cursor.getString(cursor.getColumnIndex(KEY_USER_PHONE_NUM)); 101 | return new ContactInfo(id,name,number); 102 | } 103 | private ContentValues transContactInfo(ContactInfo info) { 104 | ContentValues value = new ContentValues(); 105 | value.put(KEY_CONTACT_ID, info.getContactId()); 106 | value.put(KEY_CONTACT_NAME, info.getContactName()); 107 | value.put(KEY_USER_PHONE_NUM, info.getContactNum()); 108 | return value; 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /app/src/main/java/com/android/androidtech/database/tables/DBConfig.java: -------------------------------------------------------------------------------- 1 | package com.android.androidtech.database.tables; 2 | 3 | /** 4 | * Created by yuchengluo on 2015/6/29. 5 | */ 6 | public interface DBConfig { 7 | public static final String DATABASE_FILE = "QmfDb"; // DB文件名 8 | public static final int DB_VER = 1; // 9 | } 10 | -------------------------------------------------------------------------------- /app/src/main/java/com/android/androidtech/fragment/ContactFragment.java: -------------------------------------------------------------------------------- 1 | package com.android.androidtech.fragment; 2 | 3 | import android.content.Context; 4 | import android.os.Bundle; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.view.animation.Animation; 9 | import android.widget.BaseAdapter; 10 | import android.widget.ImageView; 11 | import android.widget.ListView; 12 | import android.widget.TextView; 13 | 14 | import com.android.androidtech.GmfSharedPreferences; 15 | import com.android.androidtech.R; 16 | import com.android.androidtech.business.contact.ContactInfo; 17 | import com.android.androidtech.business.contact.ContactsManager; 18 | import com.android.androidtech.fragment.base.BaseFragment; 19 | 20 | import java.util.ArrayList; 21 | 22 | 23 | /** 24 | * Created by yuchengluo on 2015/6/29. 25 | */ 26 | public class ContactFragment extends BaseFragment { 27 | //private List> mData; 28 | private ArrayList mData; 29 | private ListView listView; 30 | private Context mContext; 31 | boolean bool = false; 32 | @Override 33 | protected View createView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 34 | mContext = getHostActivity(); 35 | View view = inflater.inflate(R.layout.fm_listview, container, false); 36 | 37 | MyAdapter adapter = new MyAdapter(mContext);//创建一个适配器 38 | 39 | listView = (ListView) view.findViewById(R.id.listView);//实例化ListView 40 | if(!GmfSharedPreferences.getInstance().getSyncSysContactState()) { 41 | mData = ContactsManager.getInstance().getTestContactInfo();//为刚才的变量赋值 42 | } 43 | listView.setAdapter(adapter);//为ListView控件绑定适配器 44 | return view; 45 | } 46 | 47 | @Override 48 | protected void resume() { 49 | 50 | } 51 | 52 | @Override 53 | protected void stop() { 54 | 55 | } 56 | 57 | @Override 58 | protected void pause() { 59 | 60 | } 61 | 62 | @Override 63 | protected void start() { 64 | 65 | } 66 | 67 | @Override 68 | public void onEnterAnimationEnd(Animation animation) { 69 | 70 | } 71 | 72 | @Override 73 | public void clearView() { 74 | 75 | } 76 | 77 | @Override 78 | public void clear() { 79 | 80 | } 81 | 82 | @Override 83 | protected void initData(Bundle data) { 84 | 85 | } 86 | 87 | /** 88 | * 自定义适配器 89 | */ 90 | public class MyAdapter extends BaseAdapter { 91 | private LayoutInflater mInflater;// 动态布局映射 92 | 93 | private class ItemHolder { 94 | TextView title; 95 | TextView time; 96 | TextView info; 97 | } 98 | public MyAdapter(Context context) { 99 | this.mInflater = LayoutInflater.from(context); 100 | } 101 | 102 | // 决定ListView有几行可见 103 | @Override 104 | public int getCount() { 105 | if(null == mData){ 106 | return 0; 107 | } 108 | return mData.size();// ListView的条目数 109 | } 110 | 111 | @Override 112 | public Object getItem(int arg0) { 113 | return null; 114 | } 115 | 116 | @Override 117 | public long getItemId(int arg0) { 118 | return 0; 119 | } 120 | 121 | @Override 122 | public View getView(int position, View convertView, ViewGroup parent) { 123 | ItemHolder itemHolder = null; 124 | if(convertView == null) { 125 | convertView = mInflater.inflate(R.layout.item_listview_test, null);//根据布局文件实例化view 126 | itemHolder = new ItemHolder(); 127 | itemHolder.title = (TextView) convertView.findViewById(R.id.title);//找某个控件 128 | itemHolder.time = (TextView) convertView.findViewById(R.id.time);//找某个控件 129 | itemHolder.info = (TextView) convertView.findViewById(R.id.info); 130 | convertView.setTag(itemHolder); 131 | }else{ 132 | itemHolder = (ItemHolder)convertView.getTag(); 133 | } 134 | itemHolder.info.setText(mData.get(position).getContactId()+ ""); 135 | itemHolder.time.setText(mData.get(position).getContactNum() );//给该控件设置数据(数据从集合类中来) 136 | itemHolder.title.setText(mData.get(position).getContactName());//给该控件设置数据(数据从集合类中来) 137 | return convertView; 138 | } 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /app/src/main/java/com/android/androidtech/fragment/PerformanceFragment.java: -------------------------------------------------------------------------------- 1 | package com.android.androidtech.fragment; 2 | 3 | import android.content.Context; 4 | import android.os.Bundle; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.view.animation.Animation; 9 | import android.widget.Button; 10 | 11 | import com.android.androidtech.R; 12 | import com.android.androidtech.activity.HomePageActivity; 13 | import com.android.androidtech.fragment.base.BaseFragment; 14 | import com.android.androidtech.fragment.performance.memory.BitmapMemeryFragment; 15 | import com.android.androidtech.fragment.performance.memory.ImageGridFragment; 16 | import com.android.androidtech.fragment.performance.ui.UiPerfFragment; 17 | 18 | /** 19 | * Created by yuchengluo on 2015/7/16. 20 | */ 21 | public class PerformanceFragment extends BaseFragment implements View.OnClickListener { 22 | 23 | private Button mBtn_UiPerf,mBtn_MenPerf ,mBtn_BitMap,mBtn_Contact= null; 24 | private Context mContext = null; 25 | @Override 26 | protected View createView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 27 | mContext = getHostActivity(); 28 | View view = inflater.inflate(R.layout.fm_performance, container, false); 29 | mBtn_UiPerf = (Button)view.findViewById(R.id.btn_ui_perf); 30 | mBtn_UiPerf.setOnClickListener(this); 31 | 32 | mBtn_MenPerf = (Button)view.findViewById(R.id.btn_men_perf); 33 | mBtn_MenPerf.setOnClickListener(this); 34 | 35 | mBtn_BitMap = (Button)view.findViewById(R.id.btn_bitmap_men); 36 | mBtn_BitMap.setOnClickListener(this); 37 | 38 | mBtn_Contact = (Button)view.findViewById(R.id.btn_contact); 39 | mBtn_Contact.setOnClickListener(this); 40 | return view; 41 | } 42 | 43 | @Override 44 | protected void resume() { 45 | 46 | } 47 | 48 | @Override 49 | protected void stop() { 50 | 51 | } 52 | 53 | @Override 54 | protected void pause() { 55 | 56 | } 57 | 58 | @Override 59 | protected void start() { 60 | 61 | } 62 | 63 | @Override 64 | public void onEnterAnimationEnd(Animation animation) { 65 | 66 | } 67 | 68 | @Override 69 | public void clearView() { 70 | 71 | } 72 | 73 | @Override 74 | public void clear() { 75 | 76 | } 77 | 78 | @Override 79 | protected void initData(Bundle data) { 80 | 81 | } 82 | 83 | @Override 84 | public void onClick(View v) { 85 | if(v.getId() == mBtn_UiPerf.getId()){ 86 | Bundle mBundle = new Bundle(); 87 | ((HomePageActivity) mContext).addSecondFragment(UiPerfFragment.class, mBundle, null); 88 | }else if(v.getId() == mBtn_MenPerf.getId()){ 89 | Bundle mBundle = new Bundle(); 90 | ((HomePageActivity) mContext).addSecondFragment(ImageGridFragment.class, mBundle, null); 91 | }else if(v.getId() == mBtn_BitMap.getId()){ 92 | Bundle mBundle = new Bundle(); 93 | ((HomePageActivity) mContext).addSecondFragment(BitmapMemeryFragment.class, mBundle, null); 94 | }else if(v.getId() == mBtn_Contact.getId()){ 95 | Bundle mBundle = new Bundle(); 96 | ((HomePageActivity) mContext).addSecondFragment(ContactFragment.class, mBundle, null); 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /app/src/main/java/com/android/androidtech/fragment/TestThirdFragment.java: -------------------------------------------------------------------------------- 1 | package com.android.androidtech.fragment; 2 | 3 | import android.os.Bundle; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | import android.view.animation.Animation; 8 | 9 | import com.android.androidtech.R; 10 | import com.android.androidtech.fragment.base.BaseFragment; 11 | 12 | 13 | /** 14 | * Created by yuchengluo on 2015/6/29. 15 | */ 16 | public class TestThirdFragment extends BaseFragment { 17 | @Override 18 | protected View createView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 19 | View mView = inflater.inflate(R.layout.fragment_third, container, false); 20 | return mView; 21 | } 22 | 23 | @Override 24 | protected void resume() { 25 | 26 | } 27 | 28 | @Override 29 | protected void stop() { 30 | 31 | } 32 | 33 | @Override 34 | protected void pause() { 35 | 36 | } 37 | 38 | @Override 39 | protected void start() { 40 | 41 | } 42 | 43 | @Override 44 | public void onEnterAnimationEnd(Animation animation) { 45 | 46 | } 47 | 48 | @Override 49 | public void clearView() { 50 | 51 | } 52 | 53 | @Override 54 | public void clear() { 55 | 56 | } 57 | 58 | @Override 59 | protected void initData(Bundle data) { 60 | 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /app/src/main/java/com/android/androidtech/fragment/UiPerfMoniterFragment.java: -------------------------------------------------------------------------------- 1 | package com.android.androidtech.fragment; 2 | 3 | import android.content.Context; 4 | import android.graphics.Color; 5 | import android.os.Bundle; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | import android.view.animation.Animation; 10 | import android.widget.Button; 11 | import android.widget.RelativeLayout; 12 | 13 | import com.android.androidtech.R; 14 | import com.android.androidtech.fragment.base.BaseFragment; 15 | import com.android.androidtech.monitor.ui.UiPerfMonitor; 16 | 17 | /** 18 | * Created by yuchengluo on 2015/6/29. 19 | * UI Performance Monitor Framgent 20 | */ 21 | public class UiPerfMoniterFragment extends BaseFragment { 22 | RelativeLayout mtest = null; 23 | Button mJump = null; 24 | int mColor = Color.WHITE; 25 | private Context mContext = null; 26 | 27 | @Override 28 | protected View createView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 29 | View view = inflater.inflate(R.layout.fragmet_test, container, false); 30 | mContext = getHostActivity(); 31 | mtest = (RelativeLayout) view.findViewById(R.id.test_bg); 32 | mtest.setBackgroundColor(mColor); 33 | mJump = (Button) view.findViewById(R.id.btn_start_perfmon); 34 | mJump.setOnClickListener(new View.OnClickListener() { 35 | @Override 36 | public void onClick(View v) { 37 | changeMonitorPerf(); 38 | } 39 | } 40 | 41 | ); 42 | return view; 43 | } 44 | 45 | public void setBg(int color) { 46 | //mColor = color; 47 | } 48 | private void changeMonitorPerf(){ 49 | if(UiPerfMonitor.getmInstance().isMonitoring()) { 50 | UiPerfMonitor.getmInstance().stopMonitor(); 51 | mJump.setText(this.getResources().getText(R.string.monitor_control_start)); 52 | }else{ 53 | UiPerfMonitor.getmInstance().startMonitor(); 54 | mJump.setText(this.getResources().getText(R.string.monitor_control_stop)); 55 | } 56 | } 57 | @Override 58 | protected void resume() { 59 | 60 | } 61 | 62 | @Override 63 | protected void stop() { 64 | 65 | } 66 | 67 | @Override 68 | protected void pause() { 69 | 70 | } 71 | 72 | @Override 73 | protected void start() { 74 | 75 | } 76 | 77 | @Override 78 | public void onEnterAnimationEnd(Animation animation) { 79 | 80 | } 81 | 82 | @Override 83 | public void clearView() { 84 | 85 | } 86 | 87 | @Override 88 | public void clear() { 89 | 90 | } 91 | 92 | @Override 93 | protected void initData(Bundle data) { 94 | 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /app/src/main/java/com/android/androidtech/fragment/base/MyFragmentPagerAdapter.java: -------------------------------------------------------------------------------- 1 | package com.android.androidtech.fragment.base; 2 | 3 | import android.os.Parcelable; 4 | import android.os.SystemClock; 5 | import android.support.v4.app.Fragment; 6 | import android.support.v4.app.FragmentManager; 7 | import android.support.v4.app.FragmentTransaction; 8 | import android.support.v4.view.PagerAdapter; 9 | import android.view.View; 10 | 11 | import com.android.androidtech.utils.GLog; 12 | 13 | 14 | public abstract class MyFragmentPagerAdapter extends PagerAdapter { 15 | 16 | private static final String TAG = "MyFragmentPagerAdapter"; 17 | private static final boolean DEBUG = false; 18 | private String mTag; 19 | 20 | private final FragmentManager mFragmentManager; 21 | private FragmentTransaction mCurTransaction = null; 22 | private Fragment mCurrentPrimaryItem = null; 23 | 24 | public MyFragmentPagerAdapter(FragmentManager fm) { 25 | this(fm, "time is:" + SystemClock.currentThreadTimeMillis()); 26 | } 27 | 28 | public MyFragmentPagerAdapter(FragmentManager fm, String Tag) { 29 | mFragmentManager = fm; 30 | mTag = Tag; 31 | } 32 | 33 | public abstract Fragment getItem(int position); 34 | 35 | @Override 36 | public void startUpdate(View container) { 37 | } 38 | 39 | @Override 40 | public Object instantiateItem(View container, int position) { 41 | if (mCurTransaction == null) { 42 | mCurTransaction = mFragmentManager.beginTransaction(); 43 | } 44 | 45 | // Do we already have this fragment? 46 | String name = makeFragmentName(container.getId(), position); 47 | GLog.d(TAG, "instantiateItem name is:" + name); 48 | Fragment fragment = mFragmentManager.findFragmentByTag(name); 49 | GLog.d(TAG, "instantiateItem fragment is:" + fragment); 50 | if (fragment != null) { 51 | if (DEBUG) 52 | GLog.d(TAG, "Attaching item #" + position + ": f=" + fragment); 53 | mCurTransaction.attach(fragment); 54 | } else { 55 | fragment = getItem(position); 56 | if (fragment == null) { 57 | return null; 58 | } 59 | GLog.d(TAG, "instantiateItem getItem fragment is:" + fragment); 60 | if (DEBUG) 61 | GLog.d(TAG, "Adding item #" + position + ": f=" + fragment); 62 | mCurTransaction.add(container.getId(), fragment, makeFragmentName(container.getId(), position)); 63 | } 64 | if (fragment != mCurrentPrimaryItem) { 65 | fragment.setMenuVisibility(false); 66 | } 67 | 68 | return fragment; 69 | } 70 | 71 | @Override 72 | public void destroyItem(View container, int position, Object object) { 73 | if (mCurTransaction == null) { 74 | mCurTransaction = mFragmentManager.beginTransaction(); 75 | } 76 | if (DEBUG) 77 | GLog.d(TAG, "Detaching item #" + position + ": f=" + object + " v=" + ((Fragment) object).getView()); 78 | mCurTransaction.detach((Fragment) object); 79 | } 80 | 81 | @Override 82 | public void setPrimaryItem(View container, int position, Object object) { 83 | Fragment fragment = (Fragment) object; 84 | if (fragment != mCurrentPrimaryItem) { 85 | if (mCurrentPrimaryItem != null) { 86 | mCurrentPrimaryItem.setMenuVisibility(false); 87 | } 88 | if (fragment != null) { 89 | fragment.setMenuVisibility(true); 90 | } 91 | mCurrentPrimaryItem = fragment; 92 | } 93 | } 94 | 95 | @Override 96 | public void finishUpdate(View container) { 97 | if (mCurTransaction != null) { 98 | mCurTransaction.commitAllowingStateLoss(); 99 | mCurTransaction = null; 100 | mFragmentManager.executePendingTransactions(); 101 | } 102 | } 103 | 104 | @Override 105 | public boolean isViewFromObject(View view, Object object) { 106 | return ((Fragment) object).getView() == view; 107 | } 108 | 109 | @Override 110 | public Parcelable saveState() { 111 | return null; 112 | } 113 | 114 | @Override 115 | public void restoreState(Parcelable state, ClassLoader loader) { 116 | } 117 | 118 | private String makeFragmentName(int viewId, int index) { 119 | return "android:switcher:" + viewId + ":" + index + ":" + mTag; 120 | } 121 | 122 | public void clear() { 123 | if (mCurTransaction == null) { 124 | mCurTransaction = mFragmentManager.beginTransaction(); 125 | } 126 | try { 127 | for (int i = 0; i < getCount(); i++) { 128 | Fragment f = (Fragment) getItem(i); 129 | mCurTransaction.remove(f); 130 | } 131 | mCurTransaction.commitAllowingStateLoss(); 132 | } catch (Exception e) { 133 | e.printStackTrace(); 134 | } 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /app/src/main/java/com/android/androidtech/fragment/performance/memory/BitmapMemeryFragment.java: -------------------------------------------------------------------------------- 1 | package com.android.androidtech.fragment.performance.memory; 2 | 3 | import android.graphics.Bitmap; 4 | import android.graphics.BitmapFactory; 5 | import android.os.Bundle; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | import android.view.animation.Animation; 10 | import android.widget.ImageView; 11 | import android.widget.TextView; 12 | 13 | import com.android.androidtech.GmfApplication; 14 | import com.android.androidtech.R; 15 | import com.android.androidtech.fragment.base.BaseFragment; 16 | import com.android.androidtech.utils.GLog; 17 | 18 | import java.io.IOException; 19 | import java.io.InputStream; 20 | 21 | /** 22 | * Created by yuchengluo on 2015/11/17. 23 | */ 24 | public class BitmapMemeryFragment extends BaseFragment { 25 | 26 | ImageView mImageview = null; 27 | TextView mTexBm = null; 28 | private final String TAG = "BitmapMemeryFragment"; 29 | @Override 30 | protected View createView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 31 | View v = inflater.inflate(R.layout.layout_bitmap_show, container, false); 32 | mImageview = (ImageView) v.findViewById(R.id.viewstub_demo_imageview); 33 | mTexBm = (TextView) v.findViewById(R.id.text_bm_mem); 34 | showBitMap(); 35 | // testMemeny(); 36 | return v; 37 | } 38 | Bitmap[] mBitmap = null; 39 | private void testMemeny() { 40 | mBitmap = new Bitmap[10]; 41 | new Thread() { 42 | public void run() { 43 | InputStream in = null; 44 | try { 45 | for (int i = 0; i < 10; i++) { 46 | Thread.sleep(2000); 47 | 48 | in = GmfApplication.getContext().getResources().getAssets().open("jpg_1920_1080.jpg"); 49 | BitmapFactory.Options opts = getSampledBitmapOptionsFromStream(in, 1080, 1080); 50 | 51 | mBitmap[i] = BitmapFactory.decodeStream(in, null, opts); 52 | GLog.d(TAG,"testMemeny:" + i + "||size:" + mBitmap[i].getByteCount()); 53 | } 54 | } catch (IOException e) { 55 | e.printStackTrace(); 56 | } catch (InterruptedException e) { 57 | e.printStackTrace(); 58 | } 59 | } 60 | }.start(); 61 | } 62 | 63 | private void showBitMap() { 64 | InputStream in = null; 65 | try { 66 | in = GmfApplication.getContext().getResources().getAssets().open("jpg_1920_1080.jpg"); 67 | if (null == in) { 68 | return; 69 | } 70 | BitmapFactory.Options opts = getSampledBitmapOptionsFromStream(in, 1080, 1080); 71 | Bitmap bitmap = BitmapFactory.decodeStream(in, null, opts); 72 | // Bitmap bitmap = BitmapFactory.decodeStream(in); 73 | if (null != bitmap) { 74 | mImageview.setImageBitmap(bitmap); 75 | mTexBm.setText("Bitmap.565&inSam:" + bitmap.getByteCount()); 76 | GLog.d(TAG, "||size:" + bitmap.getByteCount()); 77 | } 78 | } catch (IOException e) { 79 | e.printStackTrace(); 80 | } finally { 81 | if (in != null) { 82 | try { 83 | in.close(); 84 | } catch (IOException e) { 85 | e.printStackTrace(); 86 | } 87 | } 88 | } 89 | } 90 | 91 | 92 | public static BitmapFactory.Options getSampledBitmapOptionsFromStream( 93 | InputStream is, int reqWidth, int reqHeight) { 94 | final BitmapFactory.Options options = new BitmapFactory.Options(); 95 | options.inJustDecodeBounds = true; 96 | BitmapFactory.decodeStream(is, null, options); 97 | options.inPreferredConfig = Bitmap.Config.RGB_565; 98 | // 计算缩放比例 99 | options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); 100 | options.inJustDecodeBounds = false; 101 | 102 | return options; 103 | } 104 | 105 | /** 106 | * @param @param options 107 | * @param @param reqWidth 108 | * @param @param reqHeight 109 | * @param @return 110 | * @return int 缩小的比例 111 | * @throws 112 | * @Description: 计算图片缩放比例 113 | */ 114 | public static int calculateInSampleSize(BitmapFactory.Options options, 115 | int reqWidth, int reqHeight) { 116 | 117 | final int height = options.outHeight; 118 | final int width = options.outWidth; 119 | int inSampleSize = 1; 120 | 121 | if (height > reqHeight || width > reqWidth) { 122 | 123 | final int halfHeight = height / 2; 124 | final int halfWidth = width / 2; 125 | 126 | while ((halfHeight / inSampleSize) > reqHeight 127 | && (halfWidth / inSampleSize) > reqWidth) { 128 | inSampleSize *= 2; 129 | } 130 | } 131 | return inSampleSize; 132 | } 133 | 134 | @Override 135 | protected void resume() { 136 | 137 | } 138 | 139 | @Override 140 | protected void stop() { 141 | 142 | } 143 | 144 | @Override 145 | protected void pause() { 146 | 147 | } 148 | 149 | @Override 150 | protected void start() { 151 | 152 | } 153 | 154 | @Override 155 | public void onEnterAnimationEnd(Animation animation) { 156 | 157 | } 158 | 159 | @Override 160 | public void clearView() { 161 | 162 | } 163 | 164 | @Override 165 | public void clear() { 166 | 167 | } 168 | 169 | @Override 170 | protected void initData(Bundle data) { 171 | 172 | } 173 | } 174 | -------------------------------------------------------------------------------- /app/src/main/java/com/android/androidtech/fragment/performance/memory/ImageGridFragment.java: -------------------------------------------------------------------------------- 1 | 2 | package com.android.androidtech.fragment.performance.memory; 3 | 4 | import android.content.Context; 5 | import android.os.Bundle; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | import android.view.animation.Animation; 10 | import android.widget.AbsListView; 11 | import android.widget.BaseAdapter; 12 | import android.widget.ImageView; 13 | import android.widget.ListView; 14 | 15 | import com.android.androidtech.R; 16 | import com.android.androidtech.fragment.base.BaseFragment; 17 | import com.android.miniimageloader.MiniImageLoader; 18 | import com.android.miniimageloader.config.BitmapConfig; 19 | 20 | public class ImageGridFragment extends BaseFragment { 21 | private static final String TAG = "ImageGridFragment"; 22 | // private ImageWorker mImageWorker; 23 | private ImageAdapter mAdapter; 24 | @Override 25 | public void onCreate(Bundle savedInstanceState) { 26 | super.onCreate(savedInstanceState); 27 | 28 | // mImageWorker = new ImageFetcher(getActivity(), 50); 29 | 30 | // ImageCache.ImageCacheParams cacheParams = new ImageCache.ImageCacheParams(); 31 | // 32 | // // 33 | // cacheParams.setMemCacheSizePercent(0.25f); 34 | 35 | // mImageWorker.initImageCache(getActivity().getSupportFragmentManager(), cacheParams); 36 | } 37 | 38 | 39 | @Override 40 | protected View createView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 41 | View v = inflater.inflate(R.layout.list, container, false); 42 | ListView listView = (ListView) v.findViewById(R.id.image_list); 43 | mAdapter = new ImageAdapter(getHostActivity()); 44 | listView.setAdapter(mAdapter); 45 | 46 | listView.setOnScrollListener(new AbsListView.OnScrollListener() { 47 | @Override 48 | public void onScrollStateChanged(AbsListView absListView, int scrollState) { 49 | 50 | if (scrollState == AbsListView.OnScrollListener.SCROLL_STATE_FLING) { 51 | MiniImageLoader.getInstance().setPauseWork(true); 52 | } else { 53 | MiniImageLoader.getInstance().setPauseWork(false); 54 | } 55 | } 56 | 57 | @Override 58 | public void onScroll(AbsListView absListView, int firstVisibleItem, 59 | int visibleItemCount, int totalItemCount) { 60 | } 61 | }); 62 | 63 | return v; 64 | } 65 | 66 | @Override 67 | protected void resume() { 68 | mAdapter.notifyDataSetChanged(); 69 | } 70 | 71 | @Override 72 | protected void stop() { 73 | 74 | } 75 | 76 | @Override 77 | protected void pause() { 78 | } 79 | 80 | @Override 81 | protected void start() { 82 | 83 | } 84 | 85 | @Override 86 | public void onEnterAnimationEnd(Animation animation) { 87 | 88 | } 89 | 90 | 91 | @Override 92 | public void onDestroy() { 93 | super.onDestroy(); 94 | } 95 | 96 | @Override 97 | public void clearView() { 98 | 99 | } 100 | 101 | @Override 102 | public void clear() { 103 | 104 | } 105 | 106 | @Override 107 | protected void initData(Bundle data) { 108 | 109 | } 110 | 111 | private class ImageAdapter extends BaseAdapter { 112 | private LayoutInflater mInflater; 113 | 114 | public ImageAdapter(Context context) { 115 | this.mInflater = LayoutInflater.from(context); 116 | } 117 | 118 | @Override 119 | public int getCount() { 120 | return Images.imageThumbUrls.length; 121 | } 122 | 123 | @Override 124 | public Object getItem(int position) { 125 | return null; 126 | } 127 | 128 | @Override 129 | public long getItemId(int position) { 130 | return 0; 131 | } 132 | 133 | @Override 134 | public View getView(int position, View convertView, ViewGroup parent) { 135 | ImageView imageView; 136 | 137 | if (convertView == null) { 138 | convertView = mInflater.inflate(R.layout.list_item, parent, false); 139 | imageView = (ImageView) convertView.findViewById(R.id.img); 140 | } else { 141 | imageView = (ImageView) convertView.findViewById(R.id.img); 142 | } 143 | MiniImageLoader.getInstance().loadImage(Images.imageThumbUrls[position], imageView,new BitmapConfig(50,50)); 144 | return convertView; 145 | } 146 | } 147 | } -------------------------------------------------------------------------------- /app/src/main/java/com/android/androidtech/fragment/performance/memory/Images.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.android.androidtech.fragment.performance.memory; 18 | 19 | /** 20 | * 21 | */ 22 | public class Images { 23 | public final static String[] imageThumbUrls = new String[] { 24 | "http://img05.tooopen.com/images/20140918/sy_71194121997.jpg", 25 | "http://img05.tooopen.com/images/20140903/sy_70117661946.jpg", 26 | "http://img05.tooopen.com/images/20140905/sy_70190092521.jpg", 27 | "http://img05.tooopen.com/images/20140909/sy_70256312597.jpg", 28 | "http://img05.tooopen.com/images/20140913/sy_70653675171.jpg", 29 | "http://img05.tooopen.com/images/20140915/sy_70861473822.jpg", 30 | "http://img05.tooopen.com/images/20140916/sy_71033051178.jpg", 31 | "http://img05.tooopen.com/images/20140918/sy_71123992934.jpg", 32 | "http://img05.tooopen.com/images/20140918/sy_71124089781.jpg", 33 | "http://img05.tooopen.com/images/20140919/sy_71289385762.jpg", 34 | "http://img05.tooopen.com/images/20140916/sy_70976292543.jpg", 35 | "http://img05.tooopen.com/images/20140910/sy_70319359141.jpg" 36 | }; 37 | } 38 | -------------------------------------------------------------------------------- /app/src/main/java/com/android/androidtech/fragment/performance/multitask/JobScheduleFragment.java: -------------------------------------------------------------------------------- 1 | package com.android.androidtech.fragment.performance.multitask; 2 | 3 | import android.content.Context; 4 | import android.os.Bundle; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.view.ViewStub; 9 | import android.view.animation.Animation; 10 | 11 | import com.android.androidtech.R; 12 | import com.android.androidtech.fragment.base.BaseFragment; 13 | 14 | /** 15 | * Created by yuchengluo on 2016/6/30. 16 | */ 17 | 18 | public class JobScheduleFragment extends BaseFragment { 19 | private Context mContext = null; 20 | static private boolean changeView = false; 21 | @Override 22 | protected View createView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 23 | mContext = getHostActivity(); 24 | View view = inflater.inflate(R.layout.fm_xml_show, container, false); 25 | if (changeView) { 26 | ViewStub stub = (ViewStub) view.findViewById(R.id.viewstub_text); 27 | stub.inflate(); 28 | changeView = false; 29 | } else { 30 | ViewStub stub = (ViewStub) view.findViewById(R.id.viewstub_image); 31 | stub.inflate(); 32 | changeView = true; 33 | } 34 | return view; 35 | } 36 | 37 | @Override 38 | protected void resume() { 39 | 40 | } 41 | 42 | @Override 43 | protected void stop() { 44 | 45 | } 46 | 47 | @Override 48 | protected void pause() { 49 | 50 | } 51 | 52 | @Override 53 | protected void start() { 54 | 55 | } 56 | 57 | @Override 58 | public void onEnterAnimationEnd(Animation animation) { 59 | 60 | } 61 | 62 | @Override 63 | public void clearView() { 64 | 65 | } 66 | 67 | @Override 68 | public void clear() { 69 | 70 | } 71 | 72 | @Override 73 | protected void initData(Bundle data) { 74 | 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /app/src/main/java/com/android/androidtech/fragment/performance/ui/ListViewFragment.java: -------------------------------------------------------------------------------- 1 | package com.android.androidtech.fragment.performance.ui; 2 | 3 | import android.content.Context; 4 | import android.os.Bundle; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.view.animation.Animation; 9 | import android.widget.BaseAdapter; 10 | import android.widget.ImageView; 11 | import android.widget.ListView; 12 | import android.widget.TextView; 13 | 14 | import com.android.androidtech.R; 15 | import com.android.androidtech.fragment.base.BaseFragment; 16 | 17 | import java.util.ArrayList; 18 | import java.util.HashMap; 19 | import java.util.List; 20 | 21 | /** 22 | * Created by yuchengluo on 2015/8/5. 23 | */ 24 | public class ListViewFragment extends BaseFragment { 25 | 26 | private List> mData; 27 | private ListView listView; 28 | private Context mContext; 29 | boolean bool = false; 30 | @Override 31 | protected View createView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 32 | mContext = getHostActivity(); 33 | View view = inflater.inflate(R.layout.fm_listview, container, false); 34 | mData = getData();//为刚才的变量赋值 35 | MyAdapter adapter = new MyAdapter(mContext);//创建一个适配器 36 | 37 | listView = (ListView) view.findViewById(R.id.listView);//实例化ListView 38 | listView.setAdapter(adapter);//为ListView控件绑定适配器 39 | return view; 40 | } 41 | 42 | @Override 43 | protected void resume() { 44 | 45 | } 46 | 47 | @Override 48 | protected void stop() { 49 | 50 | } 51 | 52 | @Override 53 | protected void pause() { 54 | 55 | } 56 | 57 | @Override 58 | protected void start() { 59 | 60 | } 61 | 62 | @Override 63 | public void onEnterAnimationEnd(Animation animation) { 64 | 65 | } 66 | 67 | @Override 68 | public void clearView() { 69 | 70 | } 71 | 72 | @Override 73 | public void clear() { 74 | 75 | } 76 | 77 | @Override 78 | protected void initData(Bundle data) { 79 | 80 | } 81 | 82 | /** 83 | * 自定义适配器 84 | */ 85 | public class MyAdapter extends BaseAdapter { 86 | private LayoutInflater mInflater;// 动态布局映射 87 | 88 | private class ItemHolder { 89 | TextView title; 90 | TextView time; 91 | TextView info; 92 | ImageView img; 93 | } 94 | public MyAdapter(Context context) { 95 | this.mInflater = LayoutInflater.from(context); 96 | } 97 | 98 | // 决定ListView有几行可见 99 | @Override 100 | public int getCount() { 101 | return mData.size();// ListView的条目数 102 | } 103 | 104 | @Override 105 | public Object getItem(int arg0) { 106 | return null; 107 | } 108 | 109 | @Override 110 | public long getItemId(int arg0) { 111 | return 0; 112 | } 113 | 114 | @Override 115 | public View getView(int position, View convertView, ViewGroup parent) { 116 | ItemHolder itemHolder = null; 117 | if(convertView == null) { 118 | convertView = mInflater.inflate(R.layout.item_listview_test, null);//根据布局文件实例化view 119 | itemHolder = new ItemHolder(); 120 | itemHolder.title = (TextView) convertView.findViewById(R.id.title);//找某个控件 121 | itemHolder.time = (TextView) convertView.findViewById(R.id.time);//找某个控件 122 | itemHolder.info = (TextView) convertView.findViewById(R.id.info); 123 | itemHolder.img = (ImageView) convertView.findViewById(R.id.img); 124 | convertView.setTag(itemHolder); 125 | }else{ 126 | itemHolder = (ItemHolder)convertView.getTag(); 127 | } 128 | itemHolder.info.setText(mData.get(position).get("info").toString()); 129 | itemHolder.time.setText(mData.get(position).get("time").toString());//给该控件设置数据(数据从集合类中来) 130 | itemHolder.title.setText(mData.get(position).get("title").toString());//给该控件设置数据(数据从集合类中来) 131 | itemHolder.img.setBackgroundResource((Integer) mData.get(position).get("img")); 132 | return convertView; 133 | } 134 | } 135 | 136 | // 初始化一个List 137 | private List> getData() { 138 | // 新建一个集合类,用于存放多条数据 139 | ArrayList> list = new ArrayList>(); 140 | HashMap map = null; 141 | for (int i = 1; i <= 40; i++) { 142 | map = new HashMap(); 143 | map.put("title", "姓名" + i); 144 | map.put("time", "08-05"); 145 | map.put("info", "我通过了你的好友验证请求"); 146 | map.put("img", R.mipmap.ic_launcher); 147 | list.add(map); 148 | } 149 | 150 | return list; 151 | } 152 | 153 | public void showInfo(int position) { 154 | getData(); 155 | } 156 | 157 | } 158 | -------------------------------------------------------------------------------- /app/src/main/java/com/android/androidtech/fragment/performance/ui/SingleCard.java: -------------------------------------------------------------------------------- 1 | package com.android.androidtech.fragment.performance.ui; 2 | 3 | import android.graphics.Bitmap; 4 | import android.graphics.Canvas; 5 | import android.graphics.Paint; 6 | import android.graphics.RectF; 7 | 8 | /** 9 | * Created by yuchengluo on 2015/7/12. 10 | * 11 | */ 12 | public class SingleCard { 13 | public RectF area; 14 | private Bitmap bitmap; 15 | private Paint paint = new Paint(); 16 | 17 | public SingleCard(RectF area) { 18 | this.area = area; 19 | } 20 | 21 | public void setBitmap(Bitmap bitmap) { 22 | this.bitmap = bitmap; 23 | } 24 | 25 | public void draw(Canvas canvas) { 26 | canvas.drawBitmap(bitmap, null, area, paint); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /app/src/main/java/com/android/androidtech/fragment/performance/ui/UiPerfFragment.java: -------------------------------------------------------------------------------- 1 | package com.android.androidtech.fragment.performance.ui; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | import android.os.Bundle; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | import android.view.animation.Animation; 10 | import android.widget.Button; 11 | 12 | import com.android.androidtech.R; 13 | import com.android.androidtech.activity.HomePageActivity; 14 | import com.android.androidtech.activity.ex.LayoutPerActivity; 15 | import com.android.androidtech.fragment.base.BaseFragment; 16 | 17 | /** 18 | * Created by yuchengluo on 2015/7/16. 19 | * UI Home page Fragment 20 | */ 21 | public class UiPerfFragment extends BaseFragment implements View.OnClickListener { 22 | private Button mBtn_OverDraw,mBtn_Xml,mBtn_ListView,mBtn_Merge; 23 | private Context mContext = null; 24 | @Override 25 | protected View createView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 26 | mContext = getHostActivity(); 27 | View view = inflater.inflate(R.layout.fm_ui_perf, container, false); 28 | mBtn_OverDraw = (Button)view.findViewById(R.id.btn_overdraw); 29 | mBtn_OverDraw.setOnClickListener(this); 30 | mBtn_Xml = (Button)view.findViewById(R.id.btn_xml); 31 | mBtn_Xml.setOnClickListener(this); 32 | mBtn_ListView = (Button)view.findViewById(R.id.btn_listview); 33 | mBtn_ListView.setOnClickListener(this); 34 | mBtn_Merge = (Button)view.findViewById(R.id.btn_merge_layout); 35 | mBtn_Merge.setOnClickListener(new View.OnClickListener() { 36 | @Override 37 | public void onClick(View v) { 38 | Intent it = new Intent(getHostActivity(), LayoutPerActivity.class); 39 | ((HomePageActivity) mContext).startActivity(it); 40 | } 41 | }); 42 | return view; 43 | } 44 | 45 | @Override 46 | protected void resume() { 47 | 48 | } 49 | 50 | @Override 51 | protected void stop() { 52 | 53 | } 54 | 55 | @Override 56 | protected void pause() { 57 | 58 | } 59 | 60 | @Override 61 | protected void start() { 62 | 63 | } 64 | 65 | @Override 66 | public void onEnterAnimationEnd(Animation animation) { 67 | 68 | } 69 | 70 | @Override 71 | public void clearView() { 72 | 73 | } 74 | 75 | @Override 76 | public void clear() { 77 | 78 | } 79 | 80 | @Override 81 | protected void initData(Bundle data) { 82 | 83 | } 84 | 85 | @Override 86 | public void onClick(View v) { 87 | if(v.getId() == mBtn_OverDraw.getId()){ 88 | Bundle mBundle = new Bundle(); 89 | ((HomePageActivity) mContext).addSecondFragment(OverDrawFragment.class, mBundle, null); 90 | }else if(v.getId() == mBtn_Xml.getId()){ 91 | Bundle mBundle = new Bundle(); 92 | ((HomePageActivity) mContext).addSecondFragment(ViewStubDemoFragment.class, mBundle, null); 93 | }else if(v.getId() == mBtn_ListView.getId()){ 94 | Bundle mBundle = new Bundle(); 95 | ((HomePageActivity) mContext).addSecondFragment(ListViewFragment.class, mBundle, null); 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /app/src/main/java/com/android/androidtech/fragment/performance/ui/ViewStubDemoFragment.java: -------------------------------------------------------------------------------- 1 | package com.android.androidtech.fragment.performance.ui; 2 | 3 | import android.content.Context; 4 | import android.os.Bundle; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.view.ViewStub; 9 | import android.view.animation.Animation; 10 | 11 | import com.android.androidtech.R; 12 | import com.android.androidtech.fragment.base.BaseFragment; 13 | 14 | /** 15 | * Created by yuchengluo on 2015/7/30. 16 | * ViewStub 17 | */ 18 | public class ViewStubDemoFragment extends BaseFragment{ 19 | private Context mContext = null; 20 | static private boolean changeView = false; 21 | @Override 22 | protected View createView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 23 | mContext = getHostActivity(); 24 | View view = inflater.inflate(R.layout.fm_xml_show, container, false); 25 | if (changeView) { 26 | ViewStub stub = (ViewStub) view.findViewById(R.id.viewstub_text); 27 | stub.inflate(); 28 | changeView = false; 29 | } else { 30 | ViewStub stub = (ViewStub) view.findViewById(R.id.viewstub_image); 31 | stub.inflate(); 32 | changeView = true; 33 | } 34 | return view; 35 | } 36 | 37 | @Override 38 | protected void resume() { 39 | 40 | } 41 | 42 | @Override 43 | protected void stop() { 44 | 45 | } 46 | 47 | @Override 48 | protected void pause() { 49 | 50 | } 51 | 52 | @Override 53 | protected void start() { 54 | 55 | } 56 | 57 | @Override 58 | public void onEnterAnimationEnd(Animation animation) { 59 | 60 | } 61 | 62 | @Override 63 | public void clearView() { 64 | 65 | } 66 | 67 | @Override 68 | public void clear() { 69 | 70 | } 71 | 72 | @Override 73 | protected void initData(Bundle data) { 74 | 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /app/src/main/java/com/android/androidtech/jobscheduler/JobScheduleManager.java: -------------------------------------------------------------------------------- 1 | package com.android.androidtech.jobscheduler; 2 | 3 | import android.app.job.JobInfo; 4 | import android.app.job.JobScheduler; 5 | import android.content.ComponentName; 6 | import android.content.Context; 7 | 8 | /** 9 | * Created by yuchengluo on 2016/6/30. 10 | */ 11 | 12 | public class JobScheduleManager { 13 | private static JobScheduleManager mInstance = null; 14 | private Context mContext = null; 15 | private JobScheduler mJS = null; 16 | 17 | public static JobScheduleManager getmInstance(Context ctx) { 18 | if (null == mInstance) { 19 | mInstance = new JobScheduleManager(ctx); 20 | } 21 | return mInstance; 22 | } 23 | 24 | public JobScheduleManager(Context ctx) { 25 | mContext = ctx; 26 | mJS = (JobScheduler) mContext.getSystemService(Context.JOB_SCHEDULER_SERVICE); 27 | } 28 | 29 | public boolean addJobScheduleTask(int task_id) { 30 | JobInfo.Builder builder = new JobInfo.Builder(task_id, 31 | new ComponentName("PackgeName", 32 | JobSchedulerService.class.getName())); 33 | switch (task_id){ 34 | case 1: 35 | builder.setPeriodic(1000); 36 | break; 37 | case 2: 38 | builder.setPersisted(false); 39 | break; 40 | default: 41 | 42 | } 43 | if(mJS != null) { 44 | return mJS.schedule(builder.build()) > 0; 45 | }else{ 46 | return false; 47 | } 48 | } 49 | //create JobInfo 50 | 51 | } 52 | -------------------------------------------------------------------------------- /app/src/main/java/com/android/androidtech/jobscheduler/JobSchedulerService.java: -------------------------------------------------------------------------------- 1 | package com.android.androidtech.jobscheduler; 2 | 3 | import android.app.job.JobParameters; 4 | import android.app.job.JobService; 5 | 6 | /** 7 | * Created by yuchengluo on 2016/6/30. 8 | */ 9 | 10 | public class JobSchedulerService extends JobService{ 11 | @Override 12 | public boolean onStartJob(JobParameters params) { 13 | return false; 14 | } 15 | 16 | @Override 17 | public boolean onStopJob(JobParameters params) { 18 | return false; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /app/src/main/java/com/android/androidtech/monitor/MonitorConfig.java: -------------------------------------------------------------------------------- 1 | package com.android.androidtech.monitor; 2 | 3 | /** 4 | * Created by yuchengluo on 2016/3/31. 5 | */ 6 | public class MonitorConfig { 7 | static boolean ENABLE_UI_PERF_MONITOR = true; 8 | } 9 | -------------------------------------------------------------------------------- /app/src/main/java/com/android/androidtech/monitor/memory/LeakCanaryService.java: -------------------------------------------------------------------------------- 1 | package com.android.androidtech.monitor.memory; 2 | 3 | import com.squareup.leakcanary.AnalysisResult; 4 | import com.squareup.leakcanary.DisplayLeakService; 5 | import com.squareup.leakcanary.HeapDump; 6 | import com.android.androidtech.utils.GLog; 7 | 8 | /** 9 | * Created by yuchengluo on 2016/4/20. 10 | */ 11 | public class LeakCanaryService extends DisplayLeakService{ 12 | private final String TAG = "LeakCanaryService"; 13 | @Override 14 | protected void afterDefaultHandling(HeapDump heapDump, AnalysisResult result, String leakInfo) { 15 | GLog.d(TAG,"afterDefaultHandling:" + leakInfo); 16 | //super.afterDefaultHandling(heapDump, result, leakInfo); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /app/src/main/java/com/android/androidtech/monitor/memory/TestDataModel.java: -------------------------------------------------------------------------------- 1 | package com.android.androidtech.monitor.memory; 2 | 3 | import android.widget.TextView; 4 | 5 | public class TestDataModel { 6 | 7 | private static TestDataModel sInstance; 8 | private TextView mRetainedTextView; 9 | 10 | public static TestDataModel getInstance() { 11 | if (sInstance == null) { 12 | sInstance = new TestDataModel(); 13 | } 14 | return sInstance; 15 | } 16 | 17 | public void setRetainedTextView(TextView textView) { 18 | mRetainedTextView = textView; 19 | } 20 | } -------------------------------------------------------------------------------- /app/src/main/java/com/android/androidtech/monitor/time/TimeMonitor.java: -------------------------------------------------------------------------------- 1 | package com.android.androidtech.monitor.time; 2 | 3 | import com.android.androidtech.utils.GLog; 4 | 5 | import java.util.HashMap; 6 | import java.util.Iterator; 7 | import java.util.LinkedHashMap; 8 | 9 | /** 10 | * Created by yuchengluo on 2016/3/25. 11 | */ 12 | public class TimeMonitor { 13 | private final String TAG = "TimeMonitor"; 14 | private int monitorId = -1; 15 | private LinkedHashMap mTimeTag = new LinkedHashMap(); 16 | private long mStartTime = 0; 17 | 18 | public TimeMonitor(int id) { 19 | GLog.d(TAG,"init TimeMonitor id:" + id); 20 | monitorId = id; 21 | startMoniter(); 22 | } 23 | 24 | public int getMonitorId() { 25 | return monitorId; 26 | } 27 | 28 | public void startMoniter() { 29 | if (mTimeTag.size() > 0) { 30 | mTimeTag.clear(); 31 | } 32 | mStartTime = System.currentTimeMillis(); 33 | } 34 | 35 | public void recodingTimeTag(String tag) { 36 | if (mTimeTag.get(tag) != null) { 37 | mTimeTag.remove(tag); 38 | } 39 | long time = System.currentTimeMillis() - mStartTime; 40 | GLog.d(TAG, tag + ":" + time + "ms"); 41 | mTimeTag.put(tag, time); 42 | } 43 | public void end(String tag,boolean writeLog){ 44 | recodingTimeTag(tag); 45 | end(writeLog); 46 | } 47 | public void end(boolean writeLog) { 48 | if (writeLog) { 49 | //TODO write local 50 | } 51 | testShowData(); 52 | } 53 | public void testShowData(){ 54 | if(mTimeTag.size() <= 0){ 55 | GLog.e(TAG,"mTimeTag is empty!"); 56 | return; 57 | } 58 | Iterator iterator = mTimeTag.keySet().iterator(); 59 | while (iterator != null && iterator.hasNext()){ 60 | String tag = (String)iterator.next(); 61 | GLog.d(TAG,tag + ":" + mTimeTag.get(tag)); 62 | } 63 | } 64 | public HashMap getTimeTags() { 65 | return mTimeTag; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /app/src/main/java/com/android/androidtech/monitor/time/TimeMonitorConfig.java: -------------------------------------------------------------------------------- 1 | package com.android.androidtech.monitor.time; 2 | 3 | /** 4 | * Created by yuchengluo on 2016/3/25. 5 | */ 6 | public class TimeMonitorConfig { 7 | public static final int TIME_MONITOR_ID_APPLICATION_START = 1; 8 | public static final int TIME_MONITOR_ID_SQLITE= 2; 9 | } 10 | -------------------------------------------------------------------------------- /app/src/main/java/com/android/androidtech/monitor/time/TimeMonitorManager.java: -------------------------------------------------------------------------------- 1 | package com.android.androidtech.monitor.time; 2 | 3 | import android.content.Context; 4 | 5 | import java.util.HashMap; 6 | 7 | /** 8 | * Created by yuchengluo on 2016/3/25. 9 | */ 10 | public class TimeMonitorManager { 11 | private static TimeMonitorManager mTimeMonitorManager = null; 12 | private static Context mContext = null; 13 | private HashMap timeMonitorList = null; 14 | public synchronized static TimeMonitorManager getInstance(){ 15 | if(mTimeMonitorManager == null){ 16 | mTimeMonitorManager = new TimeMonitorManager(); 17 | } 18 | return mTimeMonitorManager; 19 | } 20 | public TimeMonitorManager(){ 21 | timeMonitorList = new HashMap(); 22 | } 23 | public void resetTimeMonitor(int id){ 24 | if(timeMonitorList.get(id) != null){ 25 | timeMonitorList.remove(id); 26 | } 27 | getTimeMonitor(id); 28 | } 29 | public TimeMonitor getTimeMonitor(int id){ 30 | TimeMonitor monitor = timeMonitorList.get(id); 31 | if(monitor == null){ 32 | monitor = new TimeMonitor(id); 33 | timeMonitorList.put(id,monitor); 34 | } 35 | return monitor; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /app/src/main/java/com/android/androidtech/monitor/ui/LogPrinter.java: -------------------------------------------------------------------------------- 1 | package com.android.androidtech.monitor.ui; 2 | 3 | import android.util.Printer; 4 | 5 | import com.android.androidtech.utils.GLog; 6 | 7 | /** 8 | * Created by yuchengluo on 2016/3/31. 9 | * hook loop 10 | */ 11 | public class LogPrinter implements Printer, UiPerfMonitorConfig { 12 | private final String TAG = "LogPrinter"; 13 | private LogPrinterListener mLogPrinter = null; 14 | private long startTime = 0; 15 | 16 | public LogPrinter(LogPrinterListener listener) { 17 | mLogPrinter = listener; 18 | } 19 | 20 | @Override 21 | public void println(String x) { 22 | if (startTime <= 0) { 23 | //发送消息,同时启动线程保存状态 24 | startTime = System.currentTimeMillis(); 25 | mLogPrinter.onStartLoop(); 26 | } else { 27 | //执行消息,同时复位ANR线程状态 28 | long endtime = System.currentTimeMillis(); 29 | 30 | execuTime(x, startTime,endtime); 31 | startTime = 0; 32 | } 33 | } 34 | 35 | private void execuTime(String loginfo, long starttime,long endtime) { 36 | int level = 0; 37 | long time = endtime - starttime; 38 | GLog.d(TAG, "dispatch handler time : " + time); 39 | if (time > TIME_WARNING_LEVEL_2) { 40 | GLog.e(TAG, "Warning_LEVEL_2:\r\n" + "println:" + loginfo); 41 | level = UI_PERF_LEVEL_2; 42 | } else if (time > TIME_WARNING_LEVEL_1) { 43 | GLog.d(TAG, "Warning_LEVEL_1:\r\n" + "println:" + loginfo); 44 | level = UI_PERF_LEVEL_1; 45 | } 46 | mLogPrinter.onEndLoop(starttime,endtime,loginfo, level); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /app/src/main/java/com/android/androidtech/monitor/ui/LogPrinterListener.java: -------------------------------------------------------------------------------- 1 | package com.android.androidtech.monitor.ui; 2 | 3 | /** 4 | * Created by yuchengluo on 2016/4/1. 5 | */ 6 | public interface LogPrinterListener { 7 | void onStartLoop(); 8 | void onEndLoop(long starttime,long endtime,String loginfo,int level); 9 | } 10 | -------------------------------------------------------------------------------- /app/src/main/java/com/android/androidtech/monitor/ui/LogWriteThread.java: -------------------------------------------------------------------------------- 1 | package com.android.androidtech.monitor.ui; 2 | 3 | import android.os.Handler; 4 | import android.os.HandlerThread; 5 | import android.util.Log; 6 | 7 | import com.android.androidtech.utils.GLog; 8 | 9 | import java.io.BufferedWriter; 10 | import java.io.File; 11 | import java.io.FileOutputStream; 12 | import java.io.IOException; 13 | import java.io.OutputStreamWriter; 14 | import java.io.RandomAccessFile; 15 | import java.text.SimpleDateFormat; 16 | 17 | /** 18 | * Created by yuchengluo on 2015/4/5. 19 | * д��־�߳� 20 | */ 21 | public class LogWriteThread implements UiPerfMonitorConfig{ 22 | private Handler mWriteHandler = null; 23 | private final Object FILE_LOCK = new Object(); 24 | private final SimpleDateFormat FILE_NAME_FORMATTER = new SimpleDateFormat("yyyy-MM-dd"); 25 | private final SimpleDateFormat TIME_FORMATTER = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 26 | private final String TAG = "LogWriteThread"; 27 | public void saveLog(final String loginfo) { 28 | getmControlHandler().post(new Runnable() { 29 | @Override 30 | public void run() { 31 | synchronized (FILE_LOCK) { 32 | saveLog2Local(loginfo); 33 | } 34 | } 35 | }); 36 | } 37 | private void saveLog2Local(String info){ 38 | long time = System.currentTimeMillis(); 39 | File logFile = new File(LOG_PATH + "/" + FILENAME + "-" + FILE_NAME_FORMATTER.format(time) + ".txt"); 40 | StringBuffer mSb = new StringBuffer("/***************************************/\r\n"); 41 | mSb.append(TIME_FORMATTER.format(time)); 42 | mSb.append("\r\n/***************************************/\r\n"); 43 | mSb.append(info+ "\r\n"); 44 | GLog.d(TAG, "saveLogToSDCard: "+ mSb.toString()); 45 | if(logFile.exists()){ 46 | writeLog4SameFile(logFile.getPath(),mSb.toString()); 47 | }else{ 48 | BufferedWriter writer = null; 49 | try { 50 | OutputStreamWriter out = new OutputStreamWriter(new FileOutputStream(logFile.getPath(), true), "UTF-8"); 51 | writer = new BufferedWriter(out); 52 | writer.write(mSb.toString()); 53 | writer.flush(); 54 | writer.close(); 55 | writer = null; 56 | } catch (Throwable t) { 57 | Log.e(TAG, "saveLogToSDCard: ", t); 58 | } finally { 59 | try { 60 | if (writer != null) { 61 | writer.close(); 62 | writer = null; 63 | } 64 | } catch (Exception e) { 65 | GLog.e(TAG, "saveLogToSDCard: ", e); 66 | } 67 | } 68 | } 69 | } 70 | /** 71 | * 72 | * @param fileName 73 | * @param content 74 | */ 75 | public static void writeLog4SameFile(String fileName, String content) { 76 | RandomAccessFile randomFile = null; 77 | try { 78 | randomFile = new RandomAccessFile(fileName, "rw"); 79 | long fileLength = randomFile.length(); 80 | randomFile.seek(fileLength); 81 | randomFile.writeBytes(content); 82 | } catch (IOException e) { 83 | e.printStackTrace(); 84 | }finally { 85 | if(randomFile != null){ 86 | try { 87 | randomFile.close(); 88 | } catch (IOException e) { 89 | e.printStackTrace(); 90 | } 91 | } 92 | } 93 | } 94 | public void send2Server(){ 95 | getmControlHandler().post(new Runnable() { 96 | @Override 97 | public void run() { 98 | //TODO send to server 99 | } 100 | }); 101 | } 102 | private Handler getmControlHandler() { 103 | if (null == mWriteHandler) { 104 | HandlerThread mHT = new HandlerThread("SamplerThread"); 105 | mHT.start(); 106 | mWriteHandler = new Handler(mHT.getLooper()); 107 | } 108 | return mWriteHandler; 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /app/src/main/java/com/android/androidtech/monitor/ui/UiPerfMonitor.java: -------------------------------------------------------------------------------- 1 | package com.android.androidtech.monitor.ui; 2 | 3 | import android.os.Looper; 4 | 5 | import com.android.androidtech.monitor.ui.sampling.CpuInfo; 6 | import com.android.androidtech.monitor.ui.sampling.CpuInfoSampler; 7 | import com.android.androidtech.utils.GLog; 8 | 9 | import java.io.File; 10 | 11 | /** 12 | * Created by yuchengluo on 2016/3/31. 13 | * UI Performance Monitor Manager 14 | */ 15 | public class UiPerfMonitor implements UiPerfMonitorConfig, LogPrinterListener { 16 | private static UiPerfMonitor mInstance = null; 17 | private final String TAG = "UiPerfMonitor"; 18 | private LogPrinter mLogPrinter; 19 | private LogWriteThread mLogWriteThread; 20 | private int monitorState = UI_PERF_MONITER_STOP; 21 | private CpuInfoSampler mCpuInfoSampler = null; 22 | 23 | public synchronized static UiPerfMonitor getmInstance() { 24 | if (null == mInstance) { 25 | mInstance = new UiPerfMonitor(); 26 | } 27 | return mInstance; 28 | } 29 | 30 | // 31 | public UiPerfMonitor() { 32 | mCpuInfoSampler = new CpuInfoSampler(); 33 | mLogPrinter = new LogPrinter(this); 34 | mLogWriteThread = new LogWriteThread(); 35 | initLogpath(); 36 | } 37 | 38 | public void startMonitor() { 39 | Looper.getMainLooper().setMessageLogging(mLogPrinter); 40 | monitorState = UI_PERF_MONITER_START; 41 | } 42 | 43 | public void stopMonitor() { 44 | Looper.getMainLooper().setMessageLogging(null); 45 | mCpuInfoSampler.stop(); 46 | monitorState = UI_PERF_MONITER_STOP; 47 | } 48 | 49 | public boolean isMonitoring() { 50 | return monitorState == UI_PERF_MONITER_START; 51 | } 52 | 53 | //Init Log file dir 54 | private void initLogpath() { 55 | File logpath = new File(LOG_PATH); 56 | if (!logpath.exists()) { 57 | boolean mkdir = logpath.mkdir(); 58 | GLog.d(TAG, "mkdir:" + mkdir + ":" + LOG_PATH); 59 | } 60 | } 61 | 62 | 63 | @Override 64 | public void onStartLoop() { 65 | mCpuInfoSampler.start(); 66 | } 67 | 68 | @Override 69 | public void onEndLoop(long starttime, long endtime, String loginfo, @PER_LEVEL int level) { 70 | mCpuInfoSampler.stop(); 71 | switch (level) { 72 | case UI_PERF_LEVEL_1: 73 | GLog.d(TAG, "onEndLoop TIME_WARNING_LEVEL_1 & cpusize:" + mCpuInfoSampler.getStatCpuInfoList().size()); 74 | if (mCpuInfoSampler.getStatCpuInfoList().size() > 0) { 75 | StringBuffer sb = new StringBuffer("startTime:"); 76 | sb.append(starttime); 77 | sb.append(" endTime:"); 78 | sb.append(endtime); 79 | sb.append(" handleTime:"); 80 | sb.append(endtime-starttime); 81 | for (CpuInfo info : mCpuInfoSampler.getStatCpuInfoList()) { 82 | sb.append("\r\n"); 83 | sb.append(info.toString()); 84 | } 85 | mLogWriteThread.saveLog(sb.toString()); 86 | } 87 | break; 88 | case UI_PERF_LEVEL_2: 89 | break; 90 | default: 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /app/src/main/java/com/android/androidtech/monitor/ui/UiPerfMonitorConfig.java: -------------------------------------------------------------------------------- 1 | package com.android.androidtech.monitor.ui; 2 | 3 | import android.os.Environment; 4 | import android.support.annotation.IntDef; 5 | 6 | import java.lang.annotation.Retention; 7 | import java.lang.annotation.RetentionPolicy; 8 | 9 | /** 10 | * Created by yuchengluo on 2016/3/31. 11 | */ 12 | public interface UiPerfMonitorConfig { 13 | 14 | //time level 15 | public final int TIME_WARNING_LEVEL_1 = 100; // 16 | public final int TIME_WARNING_LEVEL_2 = 300;// 17 | // 18 | public final int UI_PERF_LEVEL_0 = 0; 19 | public final int UI_PERF_LEVEL_1 = 1; 20 | public final int UI_PERF_LEVEL_2 = 2; 21 | // 22 | @IntDef({UI_PERF_LEVEL_0, UI_PERF_LEVEL_1,UI_PERF_LEVEL_2}) 23 | @Retention(RetentionPolicy.SOURCE) 24 | public @interface PER_LEVEL { 25 | } 26 | public final int UI_PERF_MONITER_START = 0x01; 27 | public final int UI_PERF_MONITER_STOP = 0x01 << 1; 28 | 29 | public final String LOG_PATH = Environment.getExternalStorageDirectory().getPath() + "/androidtech"; 30 | public final String FILENAME = "UiMonitorLog"; 31 | } 32 | -------------------------------------------------------------------------------- /app/src/main/java/com/android/androidtech/monitor/ui/sampling/BaseSampler.java: -------------------------------------------------------------------------------- 1 | package com.android.androidtech.monitor.ui.sampling; 2 | 3 | import android.os.Handler; 4 | import android.os.HandlerThread; 5 | 6 | import com.android.androidtech.utils.GLog; 7 | 8 | import java.util.concurrent.atomic.AtomicBoolean; 9 | 10 | /** 11 | * Created by yuchengluo on 2016/4/1. 12 | */ 13 | public abstract class BaseSampler { 14 | private final String TAG = "BaseSampler"; 15 | private Handler mControlHandler = null; 16 | private int intervalTime = 50; //ms������� 17 | private AtomicBoolean mIsSampling = new AtomicBoolean(false); 18 | public BaseSampler(){ 19 | GLog.d(TAG,"Init BaseSampler"); 20 | } 21 | public void start(){ 22 | if(!mIsSampling.get()) { 23 | GLog.d(TAG,"start Sampler"); 24 | getmControlHandler().removeCallbacks(mRunnable); 25 | getmControlHandler().post(mRunnable); 26 | mIsSampling.set(true); 27 | } 28 | } 29 | public void stop(){ 30 | if(mIsSampling.get()){ 31 | GLog.d(TAG,"stop Sampler"); 32 | getmControlHandler().removeCallbacks(mRunnable); 33 | mIsSampling.set(false); 34 | } 35 | } 36 | private Handler getmControlHandler(){ 37 | if(null == mControlHandler){ 38 | HandlerThread mHT = new HandlerThread("SamplerThread"); 39 | mHT.start(); 40 | mControlHandler = new Handler(mHT.getLooper()); 41 | } 42 | return mControlHandler; 43 | } 44 | abstract void doSample(); 45 | private Runnable mRunnable = new Runnable() { 46 | @Override 47 | public void run() { 48 | doSample(); 49 | if(mIsSampling.get()){ 50 | getmControlHandler().postDelayed(mRunnable,intervalTime); 51 | } 52 | } 53 | }; 54 | } 55 | -------------------------------------------------------------------------------- /app/src/main/java/com/android/androidtech/monitor/ui/sampling/CpuInfo.java: -------------------------------------------------------------------------------- 1 | package com.android.androidtech.monitor.ui.sampling; 2 | 3 | /** 4 | * Created by yuchengluo on 2016/4/5. 5 | */ 6 | public class CpuInfo { 7 | public long mId = 0; 8 | public long mCpuRate = 0; 9 | public long mAppRate = 0; 10 | public long mUserRate = 0; 11 | public long mSystemRate = 0; 12 | public long mIoWait = 0; 13 | public CpuInfo(long id) { 14 | mId = id; 15 | } 16 | public String toString() { 17 | StringBuffer mci = new StringBuffer(); 18 | mci.append("cpu:").append(mCpuRate).append("% "); 19 | mci.append("app:").append(mAppRate).append("% "); 20 | mci.append("[").append("user:").append(mUserRate).append("% "); 21 | mci.append("system:").append(mSystemRate).append("% "); 22 | mci.append("ioWait:").append(mIoWait).append("% ]"); 23 | return mci.toString(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /app/src/main/java/com/android/androidtech/monitor/ui/sampling/CpuInfoSampler.java: -------------------------------------------------------------------------------- 1 | package com.android.androidtech.monitor.ui.sampling; 2 | 3 | import android.util.Log; 4 | 5 | import com.android.androidtech.utils.GLog; 6 | 7 | import java.io.BufferedReader; 8 | import java.io.FileInputStream; 9 | import java.io.IOException; 10 | import java.io.InputStreamReader; 11 | import java.util.ArrayList; 12 | 13 | /** 14 | * Created by yuchengluo on 2016/4/1. 15 | */ 16 | public class CpuInfoSampler extends BaseSampler { 17 | private final String TAG = "CpuInfoSampler"; 18 | private int mPid = -1; 19 | private ArrayList mCpuInfoList = new ArrayList(); 20 | public CpuInfoSampler() { 21 | 22 | } 23 | @Override 24 | void doSample() { 25 | GLog.d(TAG, "doSample"); 26 | dumpCpuInfo(); 27 | } 28 | @Override 29 | public void start() { 30 | super.start(); 31 | mUserPre = 0; 32 | mSystemPre = 0; 33 | mIdlePre = 0; 34 | mIoWaitPre = 0; 35 | mTotalPre = 0; 36 | mAppCpuTimePre = 0; 37 | } 38 | public void clearCache(){ 39 | mCpuInfoList.clear(); 40 | } 41 | public ArrayList getStatCpuInfoList(){ 42 | return mCpuInfoList; 43 | } 44 | private void dumpCpuInfo() { 45 | BufferedReader cpuReader = null; 46 | BufferedReader pidReader = null; 47 | try { 48 | cpuReader = new BufferedReader(new InputStreamReader( 49 | new FileInputStream("/proc/stat")), 1024); 50 | String cpuRate = cpuReader.readLine(); 51 | if (cpuRate == null) { 52 | cpuRate = ""; 53 | } 54 | if (mPid < 0) { 55 | mPid = android.os.Process.myPid(); 56 | } 57 | pidReader = new BufferedReader(new InputStreamReader( 58 | new FileInputStream("/proc/" + mPid + "/stat")), 1024); 59 | String pidCpuRate = pidReader.readLine(); 60 | if (pidCpuRate == null) { 61 | pidCpuRate = ""; 62 | } 63 | parseCpuRate(cpuRate, pidCpuRate); 64 | } catch (Throwable ex) { 65 | Log.e(TAG, "doSample: ", ex); 66 | } finally { 67 | try { 68 | if (cpuReader != null) { 69 | cpuReader.close(); 70 | } 71 | if (pidReader != null) { 72 | pidReader.close(); 73 | } 74 | } catch (IOException e) { 75 | Log.e(TAG, "doSample: ", e); 76 | } 77 | } 78 | } 79 | private void parseCpuRate(String cpuRate, String pidCpuRate) { 80 | String[] cpuInfoArray = cpuRate.split(" "); 81 | if (cpuInfoArray.length < 9) { 82 | return; 83 | } 84 | long user_time = Long.parseLong(cpuInfoArray[2]); 85 | long nice_time = Long.parseLong(cpuInfoArray[3]); 86 | long system_time = Long.parseLong(cpuInfoArray[4]); 87 | long idle_time = Long.parseLong(cpuInfoArray[5]); 88 | long ioWait_time = Long.parseLong(cpuInfoArray[6]); 89 | long total_time = user_time + nice_time + system_time + idle_time + ioWait_time + Long.parseLong(cpuInfoArray[7]) + Long.parseLong(cpuInfoArray[8]); 90 | String[] pidCpuInfos = pidCpuRate.split(" "); 91 | if (pidCpuInfos.length < 17) { 92 | return; 93 | } 94 | long appCpu_time = Long.parseLong(pidCpuInfos[13]) + Long.parseLong(pidCpuInfos[14]) 95 | + Long.parseLong(pidCpuInfos[15]) + Long.parseLong(pidCpuInfos[16]); 96 | if (mAppCpuTimePre > 0) { 97 | CpuInfo mCi = new CpuInfo(System.currentTimeMillis()); 98 | long idleTime = idle_time - mIdlePre; 99 | long totalTime = total_time - mTotalPre; 100 | mCi.mCpuRate = (totalTime - idleTime) * 100L / totalTime; 101 | mCi.mAppRate = (appCpu_time - mAppCpuTimePre) * 100L / totalTime; 102 | mCi.mSystemRate = (system_time - mSystemPre) * 100L / totalTime; 103 | mCi.mUserRate = (user_time - mUserPre) * 100L / totalTime; 104 | mCi.mIoWait = (ioWait_time - mIoWaitPre) * 100L / totalTime; 105 | synchronized (mCpuInfoList) { 106 | mCpuInfoList.add(mCi); 107 | GLog.d(TAG,"cpu info :" + mCi.toString()); 108 | } 109 | } 110 | mUserPre = user_time; 111 | mSystemPre = system_time; 112 | mIdlePre = idle_time; 113 | mIoWaitPre = ioWait_time; 114 | mTotalPre = total_time; 115 | mAppCpuTimePre = appCpu_time; 116 | } 117 | private long mUserPre = 0; 118 | private long mSystemPre = 0; 119 | private long mIdlePre = 0; 120 | private long mIoWaitPre = 0; 121 | private long mTotalPre = 0; 122 | private long mAppCpuTimePre = 0; 123 | } 124 | -------------------------------------------------------------------------------- /app/src/main/java/com/android/androidtech/ui/ListViewWithViewPager.java: -------------------------------------------------------------------------------- 1 | package com.android.androidtech.ui; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | import android.view.MotionEvent; 6 | import android.view.View; 7 | import android.widget.ListView; 8 | 9 | public class ListViewWithViewPager extends ListView { 10 | 11 | private static final String TAG = "ListViewWithViewPager"; 12 | private static final int DISTANCE_X_SCROLL = 10; 13 | 14 | private View mHeaderView = null; 15 | private float mHeaderWidth = 0; 16 | private float mHeaderHeight = 0; 17 | 18 | public ListViewWithViewPager(Context context) { 19 | super(context); 20 | } 21 | 22 | public ListViewWithViewPager(Context context, AttributeSet attrs, int defStyle) { 23 | super(context, attrs, defStyle); 24 | 25 | } 26 | 27 | public ListViewWithViewPager(Context context, AttributeSet attrs) { 28 | super(context, attrs); 29 | } 30 | 31 | /** 32 | * touch事件分发 33 | *

34 | * 在该方法中,将对触控到非HeaderView的事件进行拦截 35 | */ 36 | @Override 37 | public boolean onInterceptTouchEvent(MotionEvent ev) { 38 | 39 | // boolean result; 40 | if (ev != null) { 41 | 42 | int action = ev.getAction(); 43 | // MLog.d(TAG, "onInterceptTouchEvent action:"+action); 44 | 45 | if (MotionEvent.ACTION_DOWN == action) { 46 | 47 | if (mHeaderView != null) { 48 | 49 | mHeaderWidth = mHeaderView.getWidth(); 50 | mHeaderHeight = mHeaderView.getHeight(); 51 | 52 | View firstVisibleView = this.getChildAt(getFirstVisiblePosition()); 53 | final float firstVisibleViewLeftY; 54 | if (firstVisibleView != null && firstVisibleView == mHeaderView) { 55 | 56 | if (Math.abs(firstVisibleView.getTop()) < mHeaderHeight) { 57 | 58 | firstVisibleViewLeftY = mHeaderHeight - (Math.abs(firstVisibleView.getTop())); 59 | 60 | // MLog.d(TAG, 61 | // "mHeaderWidth :"+mHeaderWidth+" mHeaderHeight:"+mHeaderHeight); 62 | if (mHeaderHeight != 0 && mHeaderWidth != 0) { 63 | // final float downX = ev.getX(); 64 | final float downY = ev.getY(); 65 | // MLog.d(TAG, "ev X:"+downX+" y:"+downY); 66 | // MLog.d(TAG, 67 | // "firstVisibleViewLeftY:"+firstVisibleViewLeftY); 68 | 69 | // 触控的区域为HeaderView区域,则不拦截事件 70 | if (firstVisibleViewLeftY > downY) { 71 | 72 | // MLog.d(TAG, "ListView不截获Touch事件"); 73 | 74 | return false; 75 | } 76 | 77 | } 78 | } 79 | } 80 | 81 | } 82 | } 83 | } 84 | 85 | // MLog.d(TAG, "ListView截获Touch事件"); 86 | if (ev != null) { 87 | return super.onInterceptTouchEvent(ev); 88 | } 89 | return false; 90 | } 91 | 92 | @Override 93 | public void addHeaderView(View v, Object data, boolean isSelectable) { 94 | super.addHeaderView(v, data, isSelectable); 95 | handlerView(v); 96 | } 97 | 98 | @Override 99 | public void addHeaderView(View v) { 100 | super.addHeaderView(v); 101 | handlerView(v); 102 | } 103 | 104 | private void handlerView(View v) { 105 | mHeaderView = v; 106 | } 107 | 108 | public View getHandlerHeaderView() { 109 | return mHeaderView; 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /app/src/main/java/com/android/androidtech/ui/MultiCardsView.java: -------------------------------------------------------------------------------- 1 | package com.android.androidtech.ui; 2 | 3 | import android.content.Context; 4 | import android.graphics.Canvas; 5 | import android.graphics.Rect; 6 | import android.graphics.Region; 7 | import android.util.AttributeSet; 8 | import android.view.View; 9 | 10 | import com.android.androidtech.fragment.performance.ui.SingleCard; 11 | import com.android.androidtech.utils.GLog; 12 | 13 | import java.util.ArrayList; 14 | 15 | /** 16 | * Created by yuchengluo on 2015/7/16. 17 | */ 18 | public class MultiCardsView extends View{ 19 | private ArrayList cardsList = new ArrayList(5); 20 | private boolean enableOverdrawOpt = true; 21 | 22 | public MultiCardsView(Context context) { 23 | this(context, null, 0); 24 | } 25 | public MultiCardsView(Context context, AttributeSet attrs) { 26 | this(context, attrs, 0); 27 | } 28 | public MultiCardsView(Context context, AttributeSet attrs, int defStyleAttr) { 29 | super(context, attrs, defStyleAttr); 30 | } 31 | 32 | public void addCards(SingleCard card) { 33 | cardsList.add(card); 34 | } 35 | //设置是否消除过度绘制 36 | public void enableOverdrawOpt(boolean enableOrNot) { 37 | this.enableOverdrawOpt = enableOrNot; 38 | invalidate(); 39 | } 40 | @Override 41 | public void onDraw(Canvas canvas) { 42 | super.onDraw(canvas); 43 | if (cardsList == null || canvas == null) 44 | return; 45 | Rect clip = canvas.getClipBounds(); 46 | GLog.d("draw", String.format("clip bounds %d %d %d %d", clip.left, clip.top, clip.right, clip.bottom)); 47 | //根据enableOverdrawOpt值来调用不同的绘制方法,对比效果 48 | if (enableOverdrawOpt) { 49 | drawCardsWithotOverDraw(canvas, cardsList.size() - 1); 50 | } else { 51 | drawCardsNormal(canvas, cardsList.size() - 1); 52 | } 53 | } 54 | //没有过度绘制的实现 55 | protected void drawCardsWithotOverDraw(Canvas canvas, int index) { 56 | if (canvas == null || index < 0 || index >= cardsList.size()) 57 | return; 58 | SingleCard card = cardsList.get(index); 59 | //判断是否没和某个卡片相交,从而跳过那些非矩形区域内的绘制操作 60 | if (card != null && !canvas.quickReject(card.area, Canvas.EdgeType.BW)) { 61 | int saveCount = canvas.save(Canvas.CLIP_SAVE_FLAG); 62 | //只绘制可见区域 63 | if (canvas.clipRect(card.area, Region.Op.DIFFERENCE)) { 64 | drawCardsWithotOverDraw(canvas, index - 1); 65 | } 66 | canvas.restoreToCount(saveCount); 67 | saveCount = canvas.save(Canvas.CLIP_SAVE_FLAG); 68 | //只绘制可见区域 69 | if (canvas.clipRect(card.area)) { 70 | GLog.d("draw", "overdraw opt: draw cards index: " + index); 71 | Rect clip = canvas.getClipBounds(); 72 | GLog.d("draw", String.format("current clip bounds %d %d %d %d", clip.left, clip.top, clip.right, clip.bottom)); 73 | card.draw(canvas); 74 | } 75 | canvas.restoreToCount(saveCount); 76 | }else{ 77 | drawCardsWithotOverDraw(canvas, index - 1); 78 | } 79 | } 80 | //普通绘制 81 | protected void drawCardsNormal(Canvas canvas, int index) { 82 | if (canvas == null || index < 0 || index >= cardsList.size()) 83 | return; 84 | SingleCard card = cardsList.get(index); 85 | if (card != null) { 86 | drawCardsNormal(canvas, index - 1); 87 | GLog.d("draw", "draw cards index: " + index); 88 | card.draw(canvas); 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /app/src/main/java/com/android/androidtech/ui/TopBar.java: -------------------------------------------------------------------------------- 1 | package com.android.androidtech.ui; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.widget.LinearLayout; 8 | 9 | import com.android.androidtech.R; 10 | 11 | /** 12 | * Created by yuchengluo on 2016/3/17. 13 | */ 14 | public class TopBar extends LinearLayout{ 15 | public TopBar(Context context) { 16 | this(context, null); 17 | } 18 | 19 | public TopBar(Context context, AttributeSet attrs) { 20 | super(context, attrs); 21 | InitView(context); 22 | } 23 | 24 | public TopBar(Context context, AttributeSet attrs, int defStyleAttr) { 25 | super(context, attrs, defStyleAttr); 26 | InitView(context); 27 | } 28 | 29 | public TopBar(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { 30 | super(context, attrs, defStyleAttr, defStyleRes); 31 | InitView(context); 32 | } 33 | private void InitView(Context ctx){ 34 | View view = LayoutInflater.from(ctx).inflate(R.layout.common_top_bar, this, true); 35 | } 36 | 37 | @Override 38 | public boolean isInEditMode() { 39 | return super.isInEditMode(); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /app/src/main/java/com/android/androidtech/utils/CpuFreqSet.java: -------------------------------------------------------------------------------- 1 | package com.android.androidtech.utils; 2 | 3 | import java.io.DataInputStream; 4 | import java.io.DataOutputStream; 5 | import java.io.IOException; 6 | import java.util.ArrayList; 7 | 8 | /** 9 | * Created by yuchengluo on 2016/7/5. 10 | */ 11 | 12 | public class CpuFreqSet { 13 | public class CPUFreqSetting { 14 | /** 15 | * cpu cat命令大全 16 | * cat [%cpuFreqPath%]/cpuinfo_cur_freq (当前cpu频率) 17 | * cat [%cpuFreqPath%]/cpuinfo_max_freq (最大cpu频率) 18 | * cat [%cpuFreqPath%]/cpuinfo_min_freq (最小cpu频率) 19 | * cat [%cpuFreqPath%]/related_cpus (cpu数量标号,从0开始,如果是双核,结果为0,1) 20 | * cat [%cpuFreqPath%]/scaling_available_frequencies (cpu所有可用频率) 21 | * cat [%cpuFreqPath%]/scaling_available_governors (cpu所有可用调控模式) 22 | * cat [%cpuFreqPath%]/scaling_available_governors (cpu所有可用调控模式) 23 | * cat [%cpuFreqPath%]/scaling_cur_freq (?????) 24 | * cat [%cpuFreqPath%]/scaling_driver (?????) 25 | * cat [%cpuFreqPath%]/scaling_governor (?????) 26 | * cat [%cpuFreqPath%]/scaling_max_freq (?????) 27 | * cat [%cpuFreqPath%]/scaling_min_freq (?????) 28 | * cat [%cpuFreqPath%]/scaling_setspeed (?????) 29 | * cat [%cpuFreqPath%]/cpuinfo_transition_latency (?????) 30 | */ 31 | private final String TAG = "CpuFreqSet"; 32 | private final String cpuFreqPath = "/sys/devices/system/cpu/cpu0/cpufreq"; 33 | // private final static String PERFORMANCE_GOVERNOR = "performance"; 34 | // private final static String POWER_SAVE_GOVERNOR = "performance"; 35 | // private final static String ONDEMAND_GOVERNOR = "performance"; 36 | // private final static String CONSERVATIVE_GOVERNOR = "performance"; 37 | // private final static String USERSAPCE_GOVERNOR = "performance"; 38 | /** 39 | * 获取当前CPU调控模式 40 | */ 41 | public void getCpuCurGovernor() { 42 | try { 43 | DataInputStream is = null; 44 | Process process = Runtime.getRuntime().exec("cat " + cpuFreqPath + "/scaling_governor"); 45 | is = new DataInputStream(process.getInputStream()); 46 | String line = is.readLine(); 47 | } catch (IOException e) { 48 | e.printStackTrace(); 49 | } 50 | } 51 | 52 | /** 53 | * 设置CPU调控模式 54 | */ 55 | private boolean writeCpuGovernor(String governor) { 56 | DataOutputStream os = null; 57 | byte[] buffer = new byte[256]; 58 | String command = "echo " + governor + " > " + cpuFreqPath + "/scaling_governor"; 59 | try { 60 | Process process = Runtime.getRuntime().exec("su"); 61 | os = new DataOutputStream(process.getOutputStream()); 62 | os.writeBytes(command + "\n"); 63 | os.writeBytes("exit\n"); 64 | os.flush(); 65 | process.waitFor(); 66 | } catch (IOException e) { 67 | return false; 68 | } catch (InterruptedException e) { 69 | e.printStackTrace(); 70 | } 71 | return true; 72 | } 73 | 74 | /** 75 | * 获得CPU所有调控模式 76 | * @return 77 | */ 78 | private ArrayList readCpuGovernors() { 79 | ArrayList governors = new ArrayList(); 80 | DataInputStream is = null; 81 | try { 82 | Process process = Runtime.getRuntime().exec("cat " + cpuFreqPath + "/scaling_available_governors"); 83 | is = new DataInputStream(process.getInputStream()); 84 | String line = is.readLine(); 85 | 86 | String[] strs = line.split(" "); 87 | for (int i = 0; i < strs.length; i++) 88 | governors.add(strs[i]); 89 | } catch (IOException e) { 90 | } 91 | return governors; 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /app/src/main/java/com/android/androidtech/utils/GLog.java: -------------------------------------------------------------------------------- 1 | package com.android.androidtech.utils; 2 | 3 | import android.util.Log; 4 | 5 | /** 6 | * Created by yuchengluo on 2015/6/26. 7 | */ 8 | public class GLog { 9 | private final static String TAG = "YCLog"; 10 | public static void d(String tag,String value){ 11 | Log.d(tag,value); 12 | } 13 | 14 | public static void e(String tag,String value){ 15 | Log.e(tag, value); 16 | } 17 | 18 | public static void w(String tag,String value){ 19 | Log.w(tag, value); 20 | } 21 | 22 | public static void i(String tag,String value){ 23 | Log.i(tag, value); 24 | } 25 | public static void e(String tag,Throwable t){ 26 | e(tag,"",t); 27 | } 28 | public static void e(String tag, String info, Throwable t) { 29 | try { 30 | if (tag != null && info != null && t != null) { 31 | e(tag, info + "\n" + Log.getStackTraceString(t)); 32 | } 33 | } catch (Exception e) { 34 | GLog.e(TAG, e.getMessage()); 35 | } 36 | 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /app/src/main/java/com/android/androidtech/utils/Util4Common.java: -------------------------------------------------------------------------------- 1 | package com.android.androidtech.utils; 2 | 3 | import android.view.View; 4 | import android.view.ViewParent; 5 | 6 | import java.lang.reflect.Field; 7 | 8 | /** 9 | * Created by yuchengluo on 2015/6/26. 10 | */ 11 | public class Util4Common { 12 | public static boolean findView(View viewParent, Object findView) { 13 | if (viewParent == null || findView == null) { 14 | return false; 15 | } 16 | 17 | if (findView == viewParent) { 18 | return true; 19 | } 20 | 21 | boolean result = false; 22 | if (findView instanceof View) { 23 | View view = (View) findView; 24 | ViewParent parent = view.getParent(); 25 | while (parent != null) { 26 | if (parent == viewParent) { 27 | result = true; 28 | break; 29 | } 30 | 31 | parent = parent.getParent(); 32 | } 33 | } 34 | return result; 35 | } 36 | public static Field getgetObjectField(Object obj, String fieldName){ 37 | java.lang.reflect.Field field = null; 38 | try { 39 | 40 | Class parentClass = obj.getClass(); 41 | while (field == null) { 42 | try { 43 | field = parentClass.getDeclaredField(fieldName); 44 | } catch (Throwable e) { 45 | e.printStackTrace(); 46 | } 47 | 48 | try { 49 | parentClass = parentClass.getSuperclass(); 50 | if (parentClass == null) { 51 | break; 52 | } 53 | } catch (Throwable e) { 54 | e.printStackTrace(); 55 | } 56 | 57 | } 58 | 59 | if (field != null && !field.isAccessible()) { 60 | field.setAccessible(true); 61 | } 62 | } catch (Throwable e) { 63 | e.printStackTrace(); 64 | } 65 | 66 | return field; 67 | } 68 | public static Object getObjectFieldValue(Object obj, String fieldName) { 69 | Object result = null; 70 | try { 71 | java.lang.reflect.Field field = getgetObjectField(obj, fieldName); 72 | if (field != null) { 73 | field.setAccessible(true); 74 | result = field.get(obj); 75 | } 76 | } catch (Throwable e) { 77 | e.printStackTrace(); 78 | } 79 | 80 | return result; 81 | } 82 | public static boolean setObjectField(Object obj, String fieldName, Object newValue) { 83 | boolean result = false; 84 | try { 85 | Field field = getgetObjectField(obj,fieldName); 86 | field.setAccessible(true); 87 | field.set(obj, newValue); 88 | result = true; 89 | } catch (Throwable e) { 90 | e.printStackTrace(); 91 | } 92 | 93 | return result; 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /app/src/main/java/com/android/androidtech/utils/Util4Phone.java: -------------------------------------------------------------------------------- 1 | package com.android.androidtech.utils; 2 | 3 | import android.os.Build; 4 | 5 | /** 6 | * Created by yuchengluo on 2015/6/26. 7 | */ 8 | public class Util4Phone { 9 | 10 | /** 11 | * 12 | * @Discription:TODO 13 | * @return 14 | */ 15 | public static boolean isSupportAnimation() { 16 | return android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB; 17 | } 18 | } 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/java/com/android/androidtech/utils/dex/DexUtil.java: -------------------------------------------------------------------------------- 1 | package com.android.androidtech.utils.dex; 2 | 3 | import android.text.TextUtils; 4 | 5 | import java.io.File; 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | 9 | import dalvik.system.PathClassLoader; 10 | 11 | /** 12 | * Created by yuchengluo on 2015/10/30. 13 | */ 14 | public class DexUtil { 15 | public static boolean loadDexToClassLoader(String dexFilePath, String libPath, String optimizedDirectoryPath, 16 | PathClassLoader classLoader) { 17 | boolean result = false; 18 | if (TextUtils.isEmpty(dexFilePath) || classLoader == null) { 19 | return false; 20 | } 21 | 22 | try { 23 | List additionalClassPathEntries = new ArrayList(); 24 | additionalClassPathEntries.add(new File(dexFilePath)); 25 | MultiDex.installSecondaryDexes(classLoader, new File(optimizedDirectoryPath), additionalClassPathEntries); 26 | result = true; 27 | } catch (Throwable e) { 28 | e.printStackTrace(); 29 | } 30 | return result; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /app/src/main/java/com/android/androidtech/utils/dex/ReflectUtil.java: -------------------------------------------------------------------------------- 1 | package com.android.androidtech.utils.dex; 2 | 3 | import java.lang.reflect.Field; 4 | import java.lang.reflect.Method; 5 | import java.util.Arrays; 6 | 7 | /** 8 | * Created by yuchengluo on 2015/10/30. 9 | */ 10 | public class ReflectUtil { 11 | 12 | public static boolean setObjectField(Object obj, String fieldName, Object newValue) { 13 | boolean result = false; 14 | try { 15 | Field field = obj.getClass().getDeclaredField(fieldName); 16 | field.setAccessible(true); 17 | field.set(obj, newValue); 18 | result = true; 19 | } catch (Throwable e) { 20 | // e.printStackTrace(); 21 | } 22 | 23 | return result; 24 | } 25 | 26 | public static Method getObjectMethod(Object obj, String methodName) { 27 | try { 28 | Method[] methods = obj.getClass().getDeclaredMethods(); 29 | if (methods != null) { 30 | for (Method method : methods) { 31 | if (method != null && method.getName().equals(methodName)) { 32 | return method; 33 | } 34 | } 35 | } 36 | } catch (Throwable e) { 37 | } 38 | 39 | return null; 40 | } 41 | 42 | public static Method getObjectMethodByArgs(Object instance, String name, Class... parameterTypes) 43 | throws NoSuchMethodException { 44 | Class clazz = instance.getClass(); 45 | 46 | while (clazz != null) { 47 | try { 48 | Method method = clazz.getDeclaredMethod(name, parameterTypes); 49 | if (!method.isAccessible()) { 50 | method.setAccessible(true); 51 | } 52 | 53 | return method; 54 | } catch (NoSuchMethodException var5) { 55 | clazz = clazz.getSuperclass(); 56 | } 57 | } 58 | throw new NoSuchMethodException("Method " + name + " with parameters " + Arrays.asList(parameterTypes) 59 | + " not found in " + instance.getClass()); 60 | } 61 | 62 | public static Field getObjectField(Object obj, String fieldName) { 63 | Field field = null; 64 | try { 65 | 66 | Class parentClass = obj.getClass(); 67 | while (field == null) { 68 | try { 69 | field = parentClass.getDeclaredField(fieldName); 70 | } catch (Throwable e) { 71 | e.printStackTrace(); 72 | } 73 | 74 | try { 75 | parentClass = parentClass.getSuperclass(); 76 | if (parentClass == null) { 77 | break; 78 | } 79 | } catch (Throwable e) { 80 | e.printStackTrace(); 81 | } 82 | 83 | } 84 | 85 | if (field != null && !field.isAccessible()) { 86 | field.setAccessible(true); 87 | } 88 | } catch (Throwable e) { 89 | e.printStackTrace(); 90 | } 91 | 92 | return field; 93 | } 94 | 95 | public static Object getObjectFieldValue(Object obj, String fieldName) { 96 | Object result = null; 97 | try { 98 | Field field = getObjectField(obj, fieldName); 99 | if (field != null) { 100 | field.setAccessible(true); 101 | result = field.get(obj); 102 | } 103 | } catch (Throwable e) { 104 | e.printStackTrace(); 105 | } 106 | 107 | return result; 108 | } 109 | 110 | public static Object invoke(Object obj, String methodName, Object[] args) { 111 | Object result = null; 112 | try { 113 | Method method = getObjectMethod(obj, methodName); 114 | if (method != null) { 115 | method.setAccessible(true); 116 | result = method.invoke(obj, args); 117 | } 118 | } catch (Throwable e) { 119 | e.printStackTrace(); 120 | } 121 | 122 | return result; 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /app/src/main/java/com/android/androidtech/utils/dex/ZipUtil.java: -------------------------------------------------------------------------------- 1 | package com.android.androidtech.utils.dex; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | import java.io.RandomAccessFile; 6 | import java.util.zip.CRC32; 7 | import java.util.zip.ZipException; 8 | 9 | /** 10 | * Created by yuchengluo on 2015/10/30. 11 | */ 12 | public class ZipUtil { 13 | 14 | static class CentralDirectory { 15 | long offset; 16 | long size; 17 | } 18 | 19 | /* redefine those constant here because of bug 13721174 preventing to compile using the 20 | * constants defined in ZipFile */ 21 | private static final int ENDHDR = 22; 22 | private static final int ENDSIG = 0x6054b50; 23 | 24 | /** 25 | * Size of reading buffers. 26 | */ 27 | private static final int BUFFER_SIZE = 0x4000; 28 | 29 | /** 30 | * Compute crc32 of the central directory of an apk. The central directory contains 31 | * the crc32 of each entries in the zip so the computed result is considered valid for the whole 32 | * zip file. Does not support zip64 nor multidisk but it should be OK for now since ZipFile does 33 | * not either. 34 | */ 35 | static long getZipCrc(File apk) throws IOException { 36 | RandomAccessFile raf = new RandomAccessFile(apk, "r"); 37 | try { 38 | CentralDirectory dir = findCentralDirectory(raf); 39 | 40 | return computeCrcOfCentralDir(raf, dir); 41 | } finally { 42 | raf.close(); 43 | } 44 | } 45 | 46 | /* Package visible for testing */ 47 | static CentralDirectory findCentralDirectory(RandomAccessFile raf) throws IOException, 48 | ZipException { 49 | long scanOffset = raf.length() - ENDHDR; 50 | if (scanOffset < 0) { 51 | throw new ZipException("File too short to be a zip file: " + raf.length()); 52 | } 53 | 54 | long stopOffset = scanOffset - 0x10000 /* ".ZIP file comment"'s max length */; 55 | if (stopOffset < 0) { 56 | stopOffset = 0; 57 | } 58 | 59 | int endSig = Integer.reverseBytes(ENDSIG); 60 | while (true) { 61 | raf.seek(scanOffset); 62 | if (raf.readInt() == endSig) { 63 | break; 64 | } 65 | 66 | scanOffset--; 67 | if (scanOffset < stopOffset) { 68 | throw new ZipException("End Of Central Directory signature not found"); 69 | } 70 | } 71 | // Read the End Of Central Directory. ENDHDR includes the signature 72 | // bytes, 73 | // which we've already read. 74 | 75 | // Pull out the information we need. 76 | raf.skipBytes(2); // diskNumber 77 | raf.skipBytes(2); // diskWithCentralDir 78 | raf.skipBytes(2); // numEntries 79 | raf.skipBytes(2); // totalNumEntries 80 | CentralDirectory dir = new CentralDirectory(); 81 | dir.size = Integer.reverseBytes(raf.readInt()) & 0xFFFFFFFFL; 82 | dir.offset = Integer.reverseBytes(raf.readInt()) & 0xFFFFFFFFL; 83 | return dir; 84 | } 85 | 86 | /* Package visible for testing */ 87 | static long computeCrcOfCentralDir(RandomAccessFile raf, CentralDirectory dir) 88 | throws IOException { 89 | CRC32 crc = new CRC32(); 90 | long stillToRead = dir.size; 91 | raf.seek(dir.offset); 92 | int length = (int) Math.min(BUFFER_SIZE, stillToRead); 93 | byte[] buffer = new byte[BUFFER_SIZE]; 94 | length = raf.read(buffer, 0, length); 95 | while (length != -1) { 96 | crc.update(buffer, 0, length); 97 | stillToRead -= length; 98 | if (stillToRead == 0) { 99 | break; 100 | } 101 | length = (int) Math.min(BUFFER_SIZE, stillToRead); 102 | length = raf.read(buffer, 0, length); 103 | } 104 | return crc.getValue(); 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/hp_button_right.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_red_dot.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/img_top_back.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_app_start.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 14 | 19 | 27 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_homepage.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 12 | 13 | 14 | 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_layout_per.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 11 | 21 | 32 | 41 | 42 | -------------------------------------------------------------------------------- /app/src/main/res/layout/common_top_bar.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 13 | 25 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fm_listview.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 14 | 18 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fm_overdraw.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 20 | 21 | 22 | 23 | 29 | 30 |