package net.oschina.app.ui; import java.lang.ref.WeakReference; import net.oschina.app.R; import net.oschina.app.base.BaseActivity; import net.oschina.app.base.BaseFragment; import net.oschina.app.bean.SimpleBackPage; import net.oschina.app.emoji.OnSendClickListener; import net.oschina.app.fragment.MessageDetailFragment; import net.oschina.app.fragment.TweetPubFragment; import net.oschina.app.fragment.TweetsFragment; import net.oschina.app.util.UIHelper; import android.content.Intent; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentTransaction; import android.text.Editable; import android.view.KeyEvent; import android.view.Menu; import android.view.MenuItem; import android.view.View; public class SimpleBackActivity extends BaseActivity implements OnSendClickListener { public final static String BUNDLE_KEY_PAGE = "BUNDLE_KEY_PAGE"; public final static String BUNDLE_KEY_ARGS = "BUNDLE_KEY_ARGS"; private static final String TAG = "FLAG_TAG"; protected WeakReference<Fragment> mFragment; protected int mPageValue = -1; @Override protected int getLayoutId() { return R.layout.activity_simple_fragment; } @Override protected boolean hasBackButton() { return true; } @Override protected void init(Bundle savedInstanceState) { super.init(savedInstanceState); if (mPageValue == -1) { mPageValue = getIntent().getIntExtra(BUNDLE_KEY_PAGE, 0); } initFromIntent(mPageValue, getIntent()); } protected void initFromIntent(int pageValue, Intent data) { if (data == null) { throw new RuntimeException( "you must provide a page info to display"); } SimpleBackPage page = SimpleBackPage.getPageByValue(pageValue); if (page == null) { throw new IllegalArgumentException("can not find page by value:" + pageValue); } setActionBarTitle(page.getTitle()); try { Fragment fragment = (Fragment) page.getClz().newInstance(); Bundle args = data.getBundleExtra(BUNDLE_KEY_ARGS); if (args != null) { fragment.setArguments(args); } FragmentTransaction trans = getSupportFragmentManager() .beginTransaction(); trans.replace(R.id.container, fragment, TAG); trans.commitAllowingStateLoss(); mFragment = new WeakReference<Fragment>(fragment); } catch (Exception e) { e.printStackTrace(); throw new IllegalArgumentException( "generate fragment error. by value:" + pageValue); } } @Override protected void onResume() { super.onResume(); if (mFragment.get() instanceof TweetsFragment) { setActionBarTitle("话题"); } } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.public_menu_send: if (mFragment.get() instanceof TweetsFragment) { sendTopic(); } else { return super.onOptionsItemSelected(item); } break; default: break; } return super.onOptionsItemSelected(item); } @Override public boolean onCreateOptionsMenu(Menu menu) { if (mFragment.get() instanceof TweetsFragment) { getMenuInflater().inflate(R.menu.pub_topic_menu, menu); } return super.onCreateOptionsMenu(menu); } /** * 发送话题 */ private void sendTopic() { Bundle bundle = new Bundle(); bundle.putInt(TweetPubFragment.ACTION_TYPE, TweetPubFragment.ACTION_TYPE_TOPIC); bundle.putString("tweet_topic", "#" + ((TweetsFragment) mFragment.get()).getTopic() + "# "); UIHelper.showTweetActivity(this, SimpleBackPage.TWEET_PUB, bundle); } @Override public void onBackPressed() { if (mFragment != null && mFragment.get() != null && mFragment.get() instanceof BaseFragment) { BaseFragment bf = (BaseFragment) mFragment.get(); if (!bf.onBackPressed()) { super.onBackPressed(); } } else { super.onBackPressed(); } } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.ACTION_DOWN && mFragment.get() instanceof BaseFragment) { ((BaseFragment) mFragment.get()).onBackPressed(); } return super.onKeyDown(keyCode, event); } @Override protected void onActivityResult(int arg0, int arg1, Intent arg2) { super.onActivityResult(arg0, arg1, arg2); } @Override public void onClick(View v) {} @Override public void initView() {} @Override public void initData() {} @Override public void onClickSendButton(Editable str) { if (mFragment.get() instanceof MessageDetailFragment) { ((OnSendClickListener) mFragment.get()).onClickSendButton(str); ((MessageDetailFragment) mFragment.get()).emojiFragment.clean(); } } @Override public void onClickFlagButton() {} }
AndroidManifest.xml 文件
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="net.oschina.app" android:versionCode="44" android:versionName="2.2.1" > <uses-sdk android:minSdkVersion="11" android:targetSdkVersion="20" /> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.READ_PHONE_STATE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.RESTART_PACKAGES" /> <uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.FLASHLIGHT" /> <uses-permission android:name="android.permission.VIBRATE" /> <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" /> <uses-permission android:name="android.permission.RECORD_AUDIO" /> <uses-permission android:name="android.permission.GET_ACCOUNTS" /> <uses-permission android:name="android.permission.USE_CREDENTIALS" /> <uses-permission android:name="android.permission.MANAGE_ACCOUNTS" /> <uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" /> <uses-permission android:name="com.android.launcher.permission.READ_SETTINGS" /> <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" /> <uses-permission android:name="android.permission.BROADCAST_STICKY" /> <uses-permission android:name="android.permission.WRITE_SETTINGS" /> <uses-permission android:name="android.permission.CALL_PHONE" /> <uses-feature android:name="android.hardware.camera" /> <uses-feature android:name="android.hardware.camera.autofocus" /> <supports-screens android:anyDensity="true" android:largeScreens="true" android:normalScreens="true" android:smallScreens="true" android:xlargeScreens="true" /> <application android:name=".AppContext" android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/ActionBarBaseTheme" > <activity android:name=".AppStart" android:label="@string/app_name" android:screenOrientation="portrait" android:theme="@style/Theme.AppStartLoad" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".ui.MainActivity" android:launchMode="singleTask" android:screenOrientation="portrait" > <intent-filter> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.BROWSABLE" /> <category android:name="android.intent.category.DEFAULT" /> <data android:host="www.oschina.net" android:scheme="http" /> </intent-filter> <intent-filter> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.BROWSABLE" /> <category android:name="android.intent.category.DEFAULT" /> <data android:host="www.oschina.net" android:scheme="https" /> </intent-filter> <intent-filter> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.BROWSABLE" /> <category android:name="android.intent.category.DEFAULT" /> <data android:host="my.oschina.net" android:scheme="http" /> </intent-filter> <intent-filter> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.BROWSABLE" /> <category android:name="android.intent.category.DEFAULT" /> <data android:host="my.oschina.net" android:scheme="https" /> </intent-filter> </activity> <activity android:name="net.oschina.app.ui.TweetActivity" android:label="发送到动弹" android:screenOrientation="portrait" > <intent-filter> <action android:name="android.intent.action.SEND" /> <category android:name="android.intent.category.DEFAULT" /> <data android:mimeType="image/*" /> </intent-filter> <intent-filter> <action android:name="android.intent.action.SEND" /> <category android:name="android.intent.category.DEFAULT" /> <data android:mimeType="text/plain" /> </intent-filter> <intent-filter> <action android:name="android.intent.action.SEND_MULTIPLE" /> <category android:name="android.intent.category.DEFAULT" /> <data android:mimeType="image/*" /> </intent-filter> </activity> <activity android:name=".ui.EventLocationActivity" /> <activity android:name=".ui.LoginActivity" android:configChanges="keyboardHidden|orientation" android:screenOrientation="portrait" > </activity> <activity android:name=".ui.DetailActivity" android:configChanges="keyboardHidden|orientation" android:screenOrientation="portrait" android:theme="@style/ActionBarBaseTheme" android:windowSoftInputMode="stateHidden|adjustResize" /> <activity android:name=".ui.ImagePreviewActivity" android:configChanges="keyboardHidden|orientation" android:screenOrientation="portrait" /> <activity android:name=".ui.SimpleBackActivity" android:configChanges="keyboardHidden|orientation" android:screenOrientation="portrait" /> <activity android:name=".team.ui.TeamMainActivity" android:screenOrientation="portrait" /> <activity android:name=".team.ui.TeamNewActiveActivity" android:configChanges="keyboardHidden|orientation" android:screenOrientation="portrait" android:windowSoftInputMode="stateHidden|adjustResize" /> <activity android:name="com.dtr.zxing.activity.CaptureActivity" android:label="@string/actionbar_title_qr_scan" android:screenOrientation="portrait" > </activity> <service android:name="net.oschina.app.LogUploadService" /> <!-- ############ QQ空间和QQ SSO授权的Activity注册 ############ --> <activity android:name="com.tencent.tauth.AuthActivity" android:launchMode="singleTask" android:noHistory="true" > <intent-filter> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE" /> <!-- 100424468,如果你使用的公用账号,则不需要修改;否则修改成你在QQ开放平台申请的 APP ID --> <data android:scheme="tencent100424468" /> </intent-filter> </activity> <activity android:name="com.tencent.connect.common.AssistActivity" android:screenOrientation="portrait" android:theme="@android:style/Theme.Translucent.NoTitleBar" > </activity> <service android:name="net.oschina.app.service.ServerTaskService" > <intent-filter> <action android:name="net.oschina.app.ACTION_PUB_BLOG_COMMENT" /> </intent-filter> <intent-filter> <action android:name="net.oschina.app.ACTION_PUB_COMMENT" /> </intent-filter> <intent-filter> <action android:name="net.oschina.app.ACTION_PUB_POST" /> </intent-filter> <intent-filter> <action android:name="net.oschina.app.ACTION_PUB_TWEET" /> </intent-filter> <intent-filter> <action android:name="net.oschina.app.ACTION_PUB_SOFTWARE_TWEET" /> </intent-filter> </service> <receiver android:name="net.oschina.app.broadcast.AlarmReceiver" /> <service android:name="net.oschina.app.service.NoticeService" android:process=":notice" /> <service android:name="net.oschina.app.service.DownloadService" /> <meta-data android:name="UMENG_APPKEY" android:value="53cb520c56240bbd7d076ce5" > </meta-data> <meta-data android:name="UMENG_CHANNEL" android:value="channel_beta" > </meta-data> <meta-data android:name="com.baidu.lbsapi.API_KEY" android:value="pIbgtjFevz8LlkbNsYUNl4Qp" /> <service android:name="com.baidu.location.f" android:enabled="true" android:process=":remote" > </service> <activity android:name="com.tencent.tauth.AuthActivity" android:launchMode="singleTask" android:noHistory="true" > <intent-filter> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE" /> <data android:scheme="tencent100942993" /> </intent-filter> </activity> <activity android:name="com.tencent.connect.common.AssistActivity" android:configChanges="orientation|keyboardHidden|screenSize" android:theme="@android:style/Theme.Translucent.NoTitleBar" /> </application> </manifest>
proguard-project.txt 文件
# To enable ProGuard in your project, edit project.properties # to define the proguard.config property as described in that file. # # Add project specific ProGuard rules here. # By default, the flags in this file are appended to flags specified # in ${sdk.dir}/tools/proguard/proguard-android.txt # You can edit the include path and order by changing the ProGuard # include property in project.properties. # # For more details, see # http://developer.android.com/guide/developing/tools/proguard.html # Add any project specific keep options here: # If your project uses WebView with JS, uncomment the following # and specify the fully qualified class name to the JavaScript interface # class: #-keepclassmembers class fqcn.of.javascript.interface.for.webview { # public *; #} -libraryjars /libs/android-async-http-1.4.6.jar -libraryjars /libs/android-support-v4.jar -libraryjars /libs/baidumapapi_v3_2_0.jar -libraryjars /libs/butterknife-5.1.2.jar -libraryjars /libs/core-2.3.0.jar -libraryjars /libs/KJFrameForAndroid_V2.03.jar -libraryjars /libs/locSDK_3.1.jar -libraryjars /libs/universal-image-loader-1.9.3.jar -libraryjars /libs/xstream-1.4.7.jar -dontwarn butterknife.** -dontwarn com.tencent.** -dontwarn com.thoughtworks.xstream.** -dontwarn com.baidu.** -keep class com.baidu.** { *; } -keep class vi.com.gdi.bgl.android.**{*;} -keep class android.support.v4.** {*; } -keep class com.tencent.connect.** {*;} #友盟 -dontshrink -dontoptimize -dontwarn com.google.android.maps.** -dontwarn android.webkit.WebView -dontwarn com.umeng.** -dontwarn com.tencent.weibo.sdk.** -dontwarn com.facebook.** -keep enum com.facebook.** -keepattributes Exceptions,InnerClasses,Signature -keepattributes *Annotation* -keepattributes SourceFile,LineNumberTable -keep public interface com.facebook.** -keep public interface com.tencent.** -keep public interface com.umeng.socialize.** -keep public interface com.umeng.socialize.sensor.** -keep public interface com.umeng.scrshot.** -keep public class com.umeng.socialize.* {*;} -keep public class javax.** -keep public class android.webkit.** -keep class com.facebook.** -keep class com.umeng.scrshot.** -keep public class com.tencent.** {*;} -keep class com.umeng.socialize.sensor.** -keep class com.tencent.mm.sdk.modelmsg.WXMediaMessage {*;} -keep class com.tencent.mm.sdk.modelmsg.** implements com.tencent.mm.sdk.modelmsg.WXMediaMessage$IMediaObject {*;} -keep class im.yixin.sdk.api.YXMessage {*;} -keep class im.yixin.sdk.api.** implements im.yixin.sdk.api.YXMessage$YXMessageData{*;} -keep public class [your_pkg].R$*{ public static final int *; }
project.properties
# This file is automatically generated by Android Tools. # Do not modify this file -- YOUR CHANGES WILL BE ERASED! # # This file must be checked in Version Control Systems. # # To customize properties used by the Ant build system edit # "ant.properties", and override values to adapt the script to your # project structure. # # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt # Project target. target=android-20 android.library.reference.1=../osc-android-app-appcompat-v7 android.library.reference.2=../libraries/UmengShareLib android.library.reference.3=../libraries/PhotoView-library
lint.xml
<?xml version="1.0" encoding="UTF-8"?> <lint> <issue id="AaptCrash" severity="ignore" /> <issue id="AccidentalOctal" severity="ignore" /> <issue id="AdapterViewChildren" severity="ignore" /> <issue id="AddJavascriptInterface" severity="ignore" /> <issue id="AllowBackup" severity="ignore" /> <issue id="AlwaysShowAction" severity="ignore" /> <issue id="AndroidGradlePluginVersion" severity="ignore" /> <issue id="AppCompatMethod" severity="ignore" /> <issue id="AppCompatResource" severity="ignore" /> <issue id="Assert" severity="ignore" /> <issue id="ButtonCase" severity="ignore" /> <issue id="ButtonOrder" severity="ignore" /> <issue id="ButtonStyle" severity="ignore" /> <issue id="ByteOrderMark" severity="ignore" /> <issue id="ClickableViewAccessibility" severity="ignore" /> <issue id="CommitPrefEdits" severity="ignore" /> <issue id="CommitTransaction" severity="ignore" /> <issue id="ContentDescription" severity="ignore" /> <issue id="CutPasteId" severity="ignore" /> <issue id="DalvikOverride" severity="ignore" /> <issue id="DefaultLocale" severity="ignore" /> <issue id="Deprecated" severity="ignore" /> <issue id="DeviceAdmin" severity="ignore" /> <issue id="DisableBaselineAlignment" severity="ignore" /> <issue id="DrawAllocation" severity="ignore" /> <issue id="DuplicateActivity" severity="ignore" /> <issue id="DuplicateDefinition" severity="ignore" /> <issue id="DuplicateIds" severity="ignore" /> <issue id="DuplicateIncludedIds" severity="ignore" /> <issue id="DuplicateUsesFeature" severity="ignore" /> <issue id="EnforceUTF8" severity="ignore" /> <issue id="ExportedContentProvider" severity="ignore" /> <issue id="ExportedPreferenceActivity" severity="ignore" /> <issue id="ExportedReceiver" severity="ignore" /> <issue id="ExportedService" severity="ignore" /> <issue id="ExtraText" severity="ignore" /> <issue id="ExtraTranslation" severity="ignore" /> <issue id="FloatMath" severity="ignore" /> <issue id="GetInstance" severity="ignore" /> <issue id="GifUsage" severity="ignore" /> <issue id="GradleCompatible" severity="ignore" /> <issue id="GradleDependency" severity="ignore" /> <issue id="GradleDeprecated" severity="ignore" /> <issue id="GradleGetter" severity="ignore" /> <issue id="GradleIdeError" severity="ignore" /> <issue id="GradleOverrides" severity="ignore" /> <issue id="GradlePath" severity="ignore" /> <issue id="GrantAllUris" severity="ignore" /> <issue id="GridLayout" severity="ignore" /> <issue id="HandlerLeak" severity="ignore" /> <issue id="HardcodedDebugMode" severity="ignore" /> <issue id="HardcodedText" severity="ignore" /> <issue id="IconColors" severity="ignore" /> <issue id="IconDensities" severity="ignore" /> <issue id="IconDipSize" severity="ignore" /> <issue id="IconDuplicates" severity="ignore" /> <issue id="IconDuplicatesConfig" severity="ignore" /> <issue id="IconExtension" severity="ignore" /> <issue id="IconLauncherShape" severity="ignore" /> <issue id="IconLocation" severity="ignore" /> <issue id="IconMissingDensityFolder" severity="ignore" /> <issue id="IconMixedNinePatch" severity="ignore" /> <issue id="IconNoDpi" severity="ignore" /> <issue id="IconXmlAndPng" severity="ignore" /> <issue id="IllegalResourceRef" severity="ignore" /> <issue id="ImpliedQuantity" severity="ignore" /> <issue id="ImproperProjectLevelStatement" severity="ignore" /> <issue id="InOrMmUsage" severity="ignore" /> <issue id="IncludeLayoutParam" severity="ignore" /> <issue id="InconsistentArrays" severity="ignore" /> <issue id="InconsistentLayout" severity="ignore" /> <issue id="InefficientWeight" severity="ignore" /> <issue id="InflateParams" severity="ignore" /> <issue id="InlinedApi" severity="ignore" /> <issue id="InnerclassSeparator" severity="ignore" /> <issue id="Instantiatable" severity="ignore" /> <issue id="InvalidId" severity="ignore" /> <issue id="InvalidPackage" severity="ignore" /> <issue id="JavascriptInterface" severity="ignore" /> <issue id="LabelFor" severity="ignore" /> <issue id="LibraryCustomView" severity="ignore" /> <issue id="LocalSuppress" severity="ignore" /> <issue id="LocaleFolder" severity="ignore" /> <issue id="MangledCRLF" severity="ignore" /> <issue id="ManifestOrder" severity="ignore" /> <issue id="ManifestTypo" severity="ignore" /> <issue id="MenuTitle" severity="ignore" /> <issue id="MergeRootFrame" severity="ignore" /> <issue id="MisplacedStatement" severity="ignore" /> <issue id="MissingApplicationIcon" severity="ignore" /> <issue id="MissingId" severity="ignore" /> <issue id="MissingPrefix" severity="ignore" /> <issue id="MissingQuantity" severity="ignore" /> <issue id="MissingRegistered" severity="ignore" /> <issue id="MissingSuperCall" severity="ignore" /> <issue id="MissingTranslation" severity="ignore" /> <issue id="MissingVersion" severity="ignore" /> <issue id="MockLocation" severity="ignore" /> <issue id="MultipleUsesSdk" severity="ignore" /> <issue id="NamespaceTypo" severity="ignore" /> <issue id="NestedScrolling" severity="ignore" /> <issue id="NestedWeights" severity="ignore" /> <issue id="NewApi" severity="ignore" /> <issue id="NfcTechWhitespace" severity="ignore" /> <issue id="NotSibling" severity="ignore" /> <issue id="ObsoleteLayoutParam" severity="ignore" /> <issue id="OldTargetApi" severity="ignore" /> <issue id="OnClick" severity="ignore" /> <issue id="Orientation" severity="ignore" /> <issue id="Overdraw" severity="ignore" /> <issue id="Override" severity="ignore" /> <issue id="PackagedPrivateKey" severity="ignore" /> <issue id="ParcelCreator" severity="ignore" /> <issue id="PrivateResource" severity="ignore" /> <issue id="Proguard" severity="ignore" /> <issue id="ProguardSplit" severity="ignore" /> <issue id="PropertyEscape" severity="ignore" /> <issue id="ProtectedPermissions" severity="ignore" /> <issue id="PxUsage" severity="ignore" /> <issue id="Recycle" severity="ignore" /> <issue id="ReferenceType" severity="ignore" /> <issue id="Registered" severity="ignore" /> <issue id="RequiredSize" severity="ignore" /> <issue id="ResAuto" severity="ignore" /> <issue id="ResourceAsColor" severity="ignore" /> <issue id="ResourceCycle" severity="ignore" /> <issue id="ResourceName" severity="ignore" /> <issue id="ScrollViewCount" severity="ignore" /> <issue id="ScrollViewSize" severity="ignore" /> <issue id="SdCardPath" severity="ignore" /> <issue id="SecureRandom" severity="ignore" /> <issue id="ServiceCast" severity="ignore" /> <issue id="SetJavaScriptEnabled" severity="ignore" /> <issue id="ShowToast" severity="ignore" /> <issue id="SignatureOrSystemPermissions" severity="ignore" /> <issue id="SimpleDateFormat" severity="ignore" /> <issue id="SmallSp" severity="ignore" /> <issue id="SpUsage" severity="ignore" /> <issue id="StateListReachable" severity="ignore" /> <issue id="StringFormatCount" severity="ignore" /> <issue id="StringFormatInvalid" severity="ignore" /> <issue id="StringFormatMatches" severity="ignore" /> <issue id="StringShouldBeInt" severity="ignore" /> <issue id="Suspicious0dp" severity="ignore" /> <issue id="SuspiciousImport" severity="ignore" /> <issue id="TextFields" severity="ignore" /> <issue id="TextViewEdits" severity="ignore" /> <issue id="TooDeepLayout" severity="ignore" /> <issue id="TooManyViews" severity="ignore" /> <issue id="TrulyRandom" severity="ignore" /> <issue id="TypographyDashes" severity="ignore" /> <issue id="TypographyEllipsis" severity="ignore" /> <issue id="TypographyFractions" severity="ignore" /> <issue id="TypographyOther" severity="ignore" /> <issue id="Typos" severity="ignore" /> <issue id="UniquePermission" severity="ignore" /> <issue id="UnknownId" severity="ignore" /> <issue id="UnknownIdInLayout" severity="ignore" /> <issue id="UnlocalizedSms" severity="ignore" /> <issue id="UnusedAttribute" severity="ignore" /> <issue id="UnusedNamespace" severity="ignore" /> <issue id="UnusedQuantity" severity="ignore" /> <issue id="UnusedResources" severity="ignore" /> <issue id="UseCheckPermission" severity="ignore" /> <issue id="UseCompoundDrawables" severity="ignore" /> <issue id="UseSparseArrays" severity="ignore" /> <issue id="UseValueOf" severity="ignore" /> <issue id="UselessLeaf" severity="ignore" /> <issue id="UselessParent" severity="ignore" /> <issue id="UsesMinSdkAttributes" severity="ignore" /> <issue id="ValidFragment" severity="ignore" /> <issue id="ViewConstructor" severity="ignore" /> <issue id="ViewHolder" severity="ignore" /> <issue id="ViewTag" severity="ignore" /> <issue id="Wakelock" severity="ignore" /> <issue id="WebViewLayout" severity="ignore" /> <issue id="WorldReadableFiles" severity="ignore" /> <issue id="WorldWriteableFiles" severity="ignore" /> <issue id="WrongCall" severity="ignore" /> <issue id="WrongCase" severity="ignore" /> <issue id="WrongFolder" severity="ignore" /> <issue id="WrongManifestParent" severity="ignore" /> <issue id="WrongViewCast" severity="ignore" /> </lint>
BaseApplication.java
package net.oschina.app.base; import net.oschina.app.R; import net.oschina.app.util.StringUtils; import android.annotation.SuppressLint; import android.annotation.TargetApi; import android.app.Activity; import android.app.Application; import android.content.Context; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; import android.content.res.Resources; import android.os.Build; import android.util.DisplayMetrics; import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; import android.widget.ImageView; import android.widget.TextView; import android.widget.Toast; @SuppressLint("InflateParams") public class BaseApplication extends Application { private static String PREF_NAME = "creativelocker.pref"; private static String LAST_REFRESH_TIME = "last_refresh_time.pref"; static Context _context; static Resources _resource; private static String lastToast = ""; private static long lastToastTime; private static boolean sIsAtLeastGB; static { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) { sIsAtLeastGB = true; } } @Override public void onCreate() { super.onCreate(); _context = getApplicationContext(); _resource = _context.getResources(); } public static synchronized BaseApplication context() { return (BaseApplication) _context; } public static Resources resources() { return _resource; } /** * 放入已读文章列表中 * * @param id */ public static void putReadedPostList(String prefFileName, String key, String value) { SharedPreferences preferences = getPreferences(prefFileName); int size = preferences.getAll().size(); Editor editor = preferences.edit(); if (size >= 100) { editor.clear(); } editor.putString(key, value); apply(editor); } /** * 读取是否是已读的文章列表 * * @param id * @return */ public static boolean isOnReadedPostList(String prefFileName, String key) { return getPreferences(prefFileName).contains(key); } /*** * 记录列表上次刷新时间 * @author 火蚁 * 2015-2-9 下午2:21:37 * * @return void * @param key * @param value */ public static void putToLastRefreshTime(String key, String value) { SharedPreferences preferences = getPreferences(LAST_REFRESH_TIME); Editor editor = preferences.edit(); editor.putString(key, value); apply(editor); } /*** * 获取列表的上次刷新时间 * @author 火蚁 * 2015-2-9 下午2:22:04 * * @return String * @param key * @return */ public static String getLastRefreshTime(String key) { return getPreferences(LAST_REFRESH_TIME).getString(key, StringUtils.getCurTimeStr()); } @TargetApi(Build.VERSION_CODES.GINGERBREAD) public static void apply(SharedPreferences.Editor editor) { if (sIsAtLeastGB) { editor.apply(); } else { editor.commit(); } } public static void set(String key, boolean value) { Editor editor = getPreferences().edit(); editor.putBoolean(key, value); apply(editor); } public static void set(String key, String value) { Editor editor = getPreferences().edit(); editor.putString(key, value); apply(editor); } public static boolean get(String key, boolean defValue) { return getPreferences().getBoolean(key, defValue); } public static String get(String key, String defValue) { return getPreferences().getString(key, defValue); } public static int get(String key, int defValue) { return getPreferences().getInt(key, defValue); } public static long get(String key, long defValue) { return getPreferences().getLong(key, defValue); } public static float get(String key, float defValue) { return getPreferences().getFloat(key, defValue); } @TargetApi(Build.VERSION_CODES.HONEYCOMB) public static SharedPreferences getPreferences() { SharedPreferences pre = context().getSharedPreferences(PREF_NAME, Context.MODE_MULTI_PROCESS); return pre; } @TargetApi(Build.VERSION_CODES.HONEYCOMB) public static SharedPreferences getPreferences(String prefName) { return context().getSharedPreferences(prefName, Context.MODE_MULTI_PROCESS); } public static int[] getDisplaySize() { return new int[] { getPreferences().getInt("screen_width", 480), getPreferences().getInt("screen_height", 854) }; } public static void saveDisplaySize(Activity activity) { DisplayMetrics displaymetrics = new DisplayMetrics(); activity.getWindowManager().getDefaultDisplay() .getMetrics(displaymetrics); SharedPreferences.Editor editor = getPreferences().edit(); editor.putInt("screen_width", displaymetrics.widthPixels); editor.putInt("screen_height", displaymetrics.heightPixels); editor.putFloat("density", displaymetrics.density); editor.commit(); } public static String string(int id) { return _resource.getString(id); } public static String string(int id, Object... args) { return _resource.getString(id, args); } public static void showToast(int message) { showToast(message, Toast.LENGTH_LONG, 0); } public static void showToast(String message) { showToast(message, Toast.LENGTH_LONG, 0, Gravity.BOTTOM); } public static void showToast(int message, int icon) { showToast(message, Toast.LENGTH_LONG, icon); } public static void showToast(String message, int icon) { showToast(message, Toast.LENGTH_LONG, icon, Gravity.BOTTOM); } public static void showToastShort(int message) { showToast(message, Toast.LENGTH_SHORT, 0); } public static void showToastShort(String message) { showToast(message, Toast.LENGTH_SHORT, 0, Gravity.BOTTOM); } public static void showToastShort(int message, Object... args) { showToast(message, Toast.LENGTH_SHORT, 0, Gravity.BOTTOM, args); } public static void showToast(int message, int duration, int icon) { showToast(message, duration, icon, Gravity.BOTTOM); } public static void showToast(int message, int duration, int icon, int gravity) { showToast(context().getString(message), duration, icon, gravity); } public static void showToast(int message, int duration, int icon, int gravity, Object... args) { showToast(context().getString(message, args), duration, icon, gravity); } public static void showToast(String message, int duration, int icon, int gravity) { if (message != null && !message.equalsIgnoreCase("")) { long time = System.currentTimeMillis(); if (!message.equalsIgnoreCase(lastToast) || Math.abs(time - lastToastTime) > 2000) { View view = LayoutInflater.from(context()).inflate( R.layout.view_toast, null); ((TextView) view.findViewById(R.id.title_tv)).setText(message); if (icon != 0) { ((ImageView) view.findViewById(R.id.icon_iv)) .setImageResource(icon); ((ImageView) view.findViewById(R.id.icon_iv)) .setVisibility(View.VISIBLE); } Toast toast = new Toast(context()); toast.setView(view); if (gravity == Gravity.CENTER) { toast.setGravity(gravity, 0, 0); } else { toast.setGravity(gravity, 0, 35); } toast.setDuration(duration); toast.show(); lastToast = message; lastToastTime = System.currentTimeMillis(); } } } }
BaseActivity.java
package net.oschina.app.base; import net.oschina.app.AppManager; import net.oschina.app.R; import net.oschina.app.interf.BaseViewInterface; import net.oschina.app.ui.dialog.CommonToast; import net.oschina.app.ui.dialog.DialogControl; import net.oschina.app.ui.dialog.DialogHelper; import net.oschina.app.ui.dialog.WaitDialog; import net.oschina.app.util.TDevice; import org.kymjs.kjframe.utils.StringUtils; import android.os.Bundle; import android.support.v7.app.ActionBar; import android.support.v7.app.ActionBar.LayoutParams; import android.support.v7.app.ActionBarActivity; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.View.OnClickListener; import android.widget.Spinner; import android.widget.TextView; import butterknife.ButterKnife; /** * baseActionBar Activity * * @author FireAnt(http://my.oschina.net/LittleDY) * @created 2014年9月25日 上午11:30:15 引用自:tonlin */ public abstract class BaseActivity extends ActionBarActivity implements DialogControl, View.OnClickListener, BaseViewInterface { public static final String INTENT_ACTION_EXIT_APP = "INTENT_ACTION_EXIT_APP"; private boolean _isVisible; private WaitDialog _waitDialog; protected LayoutInflater mInflater; protected ActionBar mActionBar; private TextView mTvActionTitle; @Override protected void onDestroy() { super.onDestroy(); TDevice.hideSoftKeyboard(getCurrentFocus()); ButterKnife.reset(this); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); AppManager.getAppManager().addActivity(this); if (!hasActionBar()) { // supportRequestWindowFeature(Window.FEATURE_NO_TITLE); } onBeforeSetContentLayout(); if (getLayoutId() != 0) { setContentView(getLayoutId()); } mActionBar = getSupportActionBar(); mInflater = getLayoutInflater(); if (hasActionBar()) { initActionBar(mActionBar); } // 通过注解绑定控件 ButterKnife.inject(this); init(savedInstanceState); initView(); initData(); _isVisible = true; } protected void onBeforeSetContentLayout() {} protected boolean hasActionBar() { return true; } protected int getLayoutId() { return 0; } protected View inflateView(int resId) { return mInflater.inflate(resId, null); } protected int getActionBarTitle() { return R.string.app_name; } protected boolean hasBackButton() { return false; } protected int getActionBarCustomView() { return 0; } protected boolean haveSpinner() { return false; } protected void init(Bundle savedInstanceState) {} protected void initActionBar(ActionBar actionBar) { if (actionBar == null) return; if (hasBackButton()) { mActionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM); int layoutRes = getActionBarCustomView(); View view = inflateView(layoutRes == 0 ? R.layout.actionbar_custom_backtitle : layoutRes); View back = view.findViewById(R.id.btn_back); if (back == null) { throw new IllegalArgumentException( "can not find R.id.btn_back in customView"); } back.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { TDevice.hideSoftKeyboard(getCurrentFocus()); onBackPressed(); } }); mTvActionTitle = (TextView) view .findViewById(R.id.tv_actionbar_title); if (mTvActionTitle == null) { throw new IllegalArgumentException( "can not find R.id.tv_actionbar_title in customView"); } int titleRes = getActionBarTitle(); if (titleRes != 0) { mTvActionTitle.setText(titleRes); } LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); actionBar.setCustomView(view, params); View spinner = actionBar.getCustomView().findViewById(R.id.spinner); if (haveSpinner()) { spinner.setVisibility(View.VISIBLE); } else { spinner.setVisibility(View.GONE); } } else { actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_TITLE); actionBar.setDisplayUseLogoEnabled(false); int titleRes = getActionBarTitle(); if (titleRes != 0) { actionBar.setTitle(titleRes); } } } protected Spinner getSpinner() { return (Spinner) mActionBar.getCustomView().findViewById(R.id.spinner); } public void setActionBarTitle(int resId) { if (resId != 0) { setActionBarTitle(getString(resId)); } } public void setActionBarTitle(String title) { if (StringUtils.isEmpty(title)) { title = getString(R.string.app_name); } if (hasActionBar() && mActionBar != null) { if (mTvActionTitle != null) { mTvActionTitle.setText(title); } mActionBar.setTitle(title); } } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case android.R.id.home: onBackPressed(); break; default: break; } return super.onOptionsItemSelected(item); } @Override protected void onPause() { super.onPause(); } @Override protected void onResume() { super.onResume(); } public void showToast(int msgResid, int icon, int gravity) { showToast(getString(msgResid), icon, gravity); } public void showToast(String message, int icon, int gravity) { CommonToast toast = new CommonToast(this); toast.setMessage(message); toast.setMessageIc(icon); toast.setLayoutGravity(gravity); toast.show(); } @Override public WaitDialog showWaitDialog() { return showWaitDialog(R.string.loading); } @Override public WaitDialog showWaitDialog(int resid) { return showWaitDialog(getString(resid)); } @Override public WaitDialog showWaitDialog(String message) { if (_isVisible) { if (_waitDialog == null) { _waitDialog = DialogHelper.getWaitDialog(this, message); } if (_waitDialog != null) { _waitDialog.setMessage(message); _waitDialog.show(); } return _waitDialog; } return null; } @Override public void hideWaitDialog() { if (_isVisible && _waitDialog != null) { try { _waitDialog.dismiss(); _waitDialog = null; } catch (Exception ex) { ex.printStackTrace(); } } } @Override public boolean onMenuOpened(int featureId, Menu menu) { // setOverflowIconVisible(featureId, menu); return super.onMenuOpened(featureId, menu); } }
BaseFragment.java
package net.oschina.app.base; import net.oschina.app.AppContext; import net.oschina.app.R; import net.oschina.app.interf.BaseFragmentInterface; import net.oschina.app.ui.dialog.DialogControl; import net.oschina.app.ui.dialog.WaitDialog; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentActivity; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; /** * 碎片基类 * * @author FireAnt(http://my.oschina.net/LittleDY) * @created 2014年9月25日 上午11:18:46 * */ public class BaseFragment extends Fragment implements android.view.View.OnClickListener, BaseFragmentInterface { public static final int STATE_NONE = 0; public static final int STATE_REFRESH = 1; public static final int STATE_LOADMORE = 2; public static final int STATE_NOMORE = 3; public static final int STATE_PRESSNONE = 4;// 正在下拉但还没有到刷新的状态 public static int mState = STATE_NONE; protected LayoutInflater mInflater; public AppContext getApplication() { return (AppContext) getActivity().getApplication(); } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { this.mInflater = inflater; View view = super.onCreateView(inflater, container, savedInstanceState); return view; } @Override public void onResume() { super.onResume(); } @Override public void onPause() { super.onPause(); } @Override public void onDestroy() { super.onDestroy(); } protected int getLayoutId() { return 0; } protected View inflateView(int resId) { return this.mInflater.inflate(resId, null); } public boolean onBackPressed() { return false; } protected void hideWaitDialog() { FragmentActivity activity = getActivity(); if (activity instanceof DialogControl) { ((DialogControl) activity).hideWaitDialog(); } } protected WaitDialog showWaitDialog() { return showWaitDialog(R.string.loading); } protected WaitDialog showWaitDialog(int resid) { FragmentActivity activity = getActivity(); if (activity instanceof DialogControl) { return ((DialogControl) activity).showWaitDialog(resid); } return null; } protected WaitDialog showWaitDialog(String resid) { FragmentActivity activity = getActivity(); if (activity instanceof DialogControl) { return ((DialogControl) activity).showWaitDialog(resid); } return null; } @Override public void initView(View view) { } @Override public void initData() { } @Override public void onClick(View v) { } }
BaseDetailFragment.java
package net.oschina.app.base; import java.io.ByteArrayInputStream; import java.io.InputStream; import java.io.Serializable; import java.lang.ref.WeakReference; import net.oschina.app.AppContext; import net.oschina.app.R; import net.oschina.app.api.remote.OSChinaApi; import net.oschina.app.bean.Comment; import net.oschina.app.bean.Constants; import net.oschina.app.bean.Entity; import net.oschina.app.bean.Report; import net.oschina.app.bean.Result; import net.oschina.app.bean.ResultBean; import net.oschina.app.cache.CacheManager; import net.oschina.app.ui.DetailActivity; import net.oschina.app.ui.ReportDialog; import net.oschina.app.ui.ShareDialog; import net.oschina.app.ui.ShareDialog.OnSharePlatformClick; import net.oschina.app.ui.empty.EmptyLayout; import net.oschina.app.util.HTMLUtil; import net.oschina.app.util.TDevice; import net.oschina.app.util.UIHelper; import net.oschina.app.util.XmlUtils; import org.apache.http.Header; import android.annotation.SuppressLint; import android.content.Context; import android.content.DialogInterface; import android.graphics.drawable.Drawable; import android.os.AsyncTask; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v4.app.FragmentActivity; import android.support.v7.internal.widget.ListPopupWindow; import android.text.TextUtils; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.webkit.WebView; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.BaseAdapter; import android.widget.ImageView; import android.widget.TextView; import com.loopj.android.http.AsyncHttpResponseHandler; import com.loopj.android.http.TextHttpResponseHandler; import com.umeng.socialize.bean.SHARE_MEDIA; import com.umeng.socialize.controller.UMServiceFactory; import com.umeng.socialize.controller.UMSocialService; import com.umeng.socialize.controller.listener.SocializeListeners.UMAuthListener; import com.umeng.socialize.exception.SocializeException; import com.umeng.socialize.media.UMImage; import com.umeng.socialize.sso.SinaSsoHandler; import com.umeng.socialize.sso.UMQQSsoHandler; import com.umeng.socialize.utils.OauthHelper; import com.umeng.socialize.weixin.controller.UMWXHandler; import com.umeng.socialize.weixin.media.CircleShareContent; import com.umeng.socialize.weixin.media.WeiXinShareContent; public abstract class BaseDetailFragment extends BaseFragment implements OnItemClickListener { public static final String INTENT_ACTION_COMMENT_CHANGED = "INTENT_ACTION_COMMENT_CHAGED"; final UMSocialService mController = UMServiceFactory .getUMSocialService("com.umeng.share"); private ListPopupWindow mMenuWindow; private MenuAdapter mMenuAdapter; protected EmptyLayout mEmptyLayout; public int mCommentCount = 0; protected WebView mWebView; protected AsyncHttpResponseHandler mCommentHandler = new AsyncHttpResponseHandler() { @Override public void onSuccess(int arg0, Header[] arg1, byte[] arg2) { try { ResultBean rsb = XmlUtils.toBean(ResultBean.class, new ByteArrayInputStream(arg2)); Result res = rsb.getResult(); if (res.OK()) { hideWaitDialog(); AppContext.showToastShort(R.string.comment_publish_success); commentPubSuccess(rsb.getComment()); } else { hideWaitDialog(); AppContext.showToastShort(res.getErrorMessage()); } } catch (Exception e) { e.printStackTrace(); onFailure(arg0, arg1, arg2, e); } ((DetailActivity) getActivity()).emojiFragment.clean(); } @Override public void onFailure(int arg0, Header[] arg1, byte[] arg2, Throwable arg3) { hideWaitDialog(); AppContext.showToastShort(R.string.comment_publish_faile); } @Override public void onFinish() { ((DetailActivity) getActivity()).emojiFragment.hideAllKeyBoard(); }; }; protected void recycleWebView() { if (mWebView != null) { mWebView.setVisibility(View.GONE); mWebView.removeAllViews(); mWebView.destroy(); mWebView = null; } } protected void onCommentChanged(int opt, int id, int catalog, boolean isBlog, Comment comment) {} private AsyncTask<String, Void, Entity> mCacheTask; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mMenuAdapter = new MenuAdapter(); setHasOptionsMenu(true); mController.getConfig().closeToast(); } protected boolean hasReportMenu() { return false; } @Override public void onDestroyView() { recycleWebView(); super.onDestroyView(); } @Override public void onDestroy() { cancelReadCache(); recycleWebView(); super.onDestroy(); } @Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); requestData(false); } protected String getCacheKey() { return null; } protected Entity parseData(InputStream is) throws Exception { return null; } protected Entity readData(Serializable seri) { return null; } protected void sendRequestData() {} protected void requestData(boolean refresh) { String key = getCacheKey(); if (TDevice.hasInternet() && (!CacheManager.isExistDataCache(getActivity(), key) || refresh)) { sendRequestData(); } else { readCacheData(key); } } // 刷新数据 protected void sendRefresh() { sendRequestData(); } private void readCacheData(String cacheKey) { cancelReadCache(); mCacheTask = new CacheTask(getActivity()).execute(cacheKey); } private void cancelReadCache() { if (mCacheTask != null) { mCacheTask.cancel(true); mCacheTask = null; } } private class CacheTask extends AsyncTask<String, Void, Entity> { private final WeakReference<Context> mContext; private CacheTask(Context context) { mContext = new WeakReference<Context>(context); } @Override protected Entity doInBackground(String... params) { if (mContext.get() != null) { Serializable seri = CacheManager.readObject(mContext.get(), params[0]); if (seri == null) { return null; } else { return readData(seri); } } return null; } @Override protected void onPostExecute(Entity entity) { super.onPostExecute(entity); if (entity != null) { executeOnLoadDataSuccess(entity); } else { executeOnLoadDataError(null); } executeOnLoadFinish(); } } private class SaveCacheTask extends AsyncTask<Void, Void, Void> { private final WeakReference<Context> mContext; private final Serializable seri; private final String key; private SaveCacheTask(Context context, Serializable seri, String key) { mContext = new WeakReference<Context>(context); this.seri = seri; this.key = key; } @Override protected Void doInBackground(Void... params) { CacheManager.saveObject(mContext.get(), seri, key); return null; } } protected AsyncHttpResponseHandler mHandler = new AsyncHttpResponseHandler() { @Override public void onSuccess(int arg0, Header[] arg1, byte[] arg2) { try { Entity entity = parseData(new ByteArrayInputStream(arg2)); if (entity != null) { mEmptyLayout.setErrorType(EmptyLayout.HIDE_LAYOUT); executeOnLoadDataSuccess(entity); saveCache(entity); } else { throw new RuntimeException("load detail error"); } } catch (Exception e) { e.printStackTrace(); onFailure(arg0, arg1, arg2, e); } } @Override public void onFailure(int arg0, Header[] arg1, byte[] arg2, Throwable arg3) { // executeOnLoadDataError(arg3.getMessage()); readCacheData(getCacheKey()); } }; private boolean mIsFavorited; protected void saveCache(Entity entity) { new SaveCacheTask(getActivity(), entity, getCacheKey()).execute(); } protected void executeOnLoadDataSuccess(Entity entity) {} protected void executeOnLoadDataError(String object) { mEmptyLayout.setErrorType(EmptyLayout.NETWORK_ERROR); mEmptyLayout.setOnLayoutClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mState = STATE_REFRESH; mEmptyLayout.setErrorType(EmptyLayout.NETWORK_LOADING); requestData(true); } }); } protected void executeOnLoadFinish() {} protected void onFavoriteChanged(boolean flag) { ((DetailActivity) getActivity()).toolFragment.setFavorite(flag); } protected int getFavoriteTargetId() { return -1; } protected int getFavoriteTargetType() { return -1; } protected String getShareUrl() { return ""; } protected String getShareTitle() { return getString(R.string.share_title); } protected String getShareContent() { return ""; } /*** * 获取去除html标签的body * * @param body * @return */ protected String getFilterHtmlBody(String body) { if (body == null) return ""; return HTMLUtil.delHTMLTag(body.trim()); } protected UMImage getShareImg() { UMImage img = new UMImage(getActivity(), R.drawable.ic_share); return img; } protected void commentPubSuccess(Comment comment) {} @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { if (position == 0) { handleFavoriteOrNot(); handleShare(); } else if (position == 1) { onReportMenuClick(); } else if (position == 2) { } if (mMenuWindow != null) { mMenuWindow.dismiss(); mMenuWindow = null; } } private final AsyncHttpResponseHandler mReportHandler = new TextHttpResponseHandler() { @Override public void onSuccess(int arg0, Header[] arg1, String arg2) { if (TextUtils.isEmpty(arg2)) { AppContext.showToastShort(R.string.tip_report_success); } else { AppContext.showToastShort(new String(arg2)); } } @Override public void onFailure(int arg0, Header[] arg1, String arg2, Throwable arg3) { AppContext.showToastShort(R.string.tip_report_faile); } @Override public void onFinish() { hideWaitDialog(); } }; public void onReportMenuClick() { if (getRepotrId() == 0) { AppContext.showToast("正在加载,请稍等..."); } if (!AppContext.getInstance().isLogin()) { UIHelper.showLoginActivity(getActivity()); return; } int reportId = getRepotrId(); final ReportDialog dialog = new ReportDialog(getActivity(), getRepotrUrl(), reportId); dialog.setCancelable(true); dialog.setTitle(R.string.report); dialog.setCanceledOnTouchOutside(true); dialog.setNegativeButton(R.string.cancle, null); dialog.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface d, int which) { Report report = null; if ((report = dialog.getReport()) != null) { showWaitDialog(R.string.progress_submit); OSChinaApi.report(report, mReportHandler); } d.dismiss(); } }); dialog.show(); } protected String getRepotrUrl() { return ""; } protected int getRepotrId() { return 0; } /** * 收藏 */ public void handleFavoriteOrNot() { if (!TDevice.hasInternet()) { AppContext.showToastShort(R.string.tip_no_internet); return; } if (!AppContext.getInstance().isLogin()) { UIHelper.showLoginActivity(getActivity()); return; } if (getFavoriteTargetId() == -1 || getFavoriteTargetType() == -1) { return; } int uid = AppContext.getInstance().getLoginUid(); if (mIsFavorited) { OSChinaApi.delFavorite(uid, getFavoriteTargetId(), getFavoriteTargetType(), mDelFavoriteHandler); } else { OSChinaApi.addFavorite(uid, getFavoriteTargetId(), getFavoriteTargetType(), mAddFavoriteHandler); } } /** * 分享 */ public void handleShare() { if (TextUtils.isEmpty(getShareContent()) || TextUtils.isEmpty(getShareUrl())) { AppContext.showToast("内容加载失败..."); return; } final ShareDialog dialog = new ShareDialog(getActivity()); dialog.setCancelable(true); dialog.setCanceledOnTouchOutside(true); dialog.setTitle(R.string.share_to); dialog.setOnPlatformClickListener(new OnSharePlatformClick() { @Override public void onPlatformClick(int id) { switch (id) { case R.id.ly_share_weichat_circle: shareToWeiChatCircle(); break; case R.id.ly_share_weichat: shareToWeiChat(); break; case R.id.ly_share_sina_weibo: shareToSinaWeibo(); break; case R.id.ly_share_qq: shareToQQ(SHARE_MEDIA.QQ); break; case R.id.ly_share_copy_link: TDevice.copyTextToBoard(getShareUrl()); break; case R.id.ly_share_more_option: TDevice.showSystemShareOption(getActivity(), getShareTitle(), getShareUrl()); break; default: break; } dialog.dismiss(); } }); dialog.show(); } @SuppressWarnings("deprecation") private void shareToWeiChatCircle() { // 支持微信朋友圈 UMWXHandler wxCircleHandler = new UMWXHandler(getActivity(), Constants.WEICHAT_APPID); wxCircleHandler.setToCircle(true); wxCircleHandler.addToSocialSDK(); // 设置微信朋友圈分享内容 CircleShareContent circleMedia = new CircleShareContent(); circleMedia.setShareContent(getShareContent()); // 设置朋友圈title circleMedia.setTitle(getShareTitle()); circleMedia.setShareImage(getShareImg()); circleMedia.setTargetUrl(getShareUrl()); mController.setShareMedia(circleMedia); mController.postShare(getActivity(), SHARE_MEDIA.WEIXIN_CIRCLE, null); } @SuppressWarnings("deprecation") private void shareToWeiChat() { // 添加微信平台 UMWXHandler wxHandler = new UMWXHandler(getActivity(), Constants.WEICHAT_APPID); wxHandler.addToSocialSDK(); // 设置微信好友分享内容 WeiXinShareContent weixinContent = new WeiXinShareContent(); // 设置分享文字 weixinContent.setShareContent(getShareContent()); // 设置title weixinContent.setTitle(getShareTitle()); // 设置分享内容跳转URL weixinContent.setTargetUrl(getShareUrl()); // 设置分享图片 weixinContent.setShareImage(getShareImg()); mController.setShareMedia(weixinContent); mController.postShare(getActivity(), SHARE_MEDIA.WEIXIN, null); } private void shareToSinaWeibo() { // 设置新浪微博SSO handler mController.getConfig().setSsoHandler(new SinaSsoHandler()); if (OauthHelper.isAuthenticated(getActivity(), SHARE_MEDIA.SINA)) { shareContent(SHARE_MEDIA.SINA); } else { mController.doOauthVerify(getActivity(), SHARE_MEDIA.SINA, new UMAuthListener() { @Override public void onStart(SHARE_MEDIA arg0) {} @Override public void onError(SocializeException arg0, SHARE_MEDIA arg1) {} @Override public void onComplete(Bundle arg0, SHARE_MEDIA arg1) { shareContent(SHARE_MEDIA.SINA); } @Override public void onCancel(SHARE_MEDIA arg0) {} }); } } private void shareContent(SHARE_MEDIA media) { mController.setShareContent(getShareContent() + getShareUrl()); mController.directShare(getActivity(), media, null); } protected void shareToQQ(SHARE_MEDIA media) { UMQQSsoHandler qqSsoHandler = new UMQQSsoHandler(getActivity(), Constants.QQ_APPID, Constants.QQ_APPKEY); qqSsoHandler.setTargetUrl(getShareUrl()); qqSsoHandler.setTitle(getShareTitle()); qqSsoHandler.addToSocialSDK(); mController.setShareContent(getShareContent()); mController.setShareImage(getShareImg()); mController.postShare(getActivity(), media, null); } protected void notifyFavorite(boolean favorite) { mIsFavorited = favorite; FragmentActivity aty = getActivity(); if (aty != null) { aty.supportInvalidateOptionsMenu(); } if (mMenuAdapter != null) { mMenuAdapter.setFavorite(favorite); } onFavoriteChanged(favorite); } public boolean isFavorited() { return mIsFavorited; } @SuppressLint("ViewHolder") private static class MenuAdapter extends BaseAdapter { public void setFavorite(boolean favorite) { notifyDataSetChanged(); } @Override public int getCount() { return 2; } @Override public Object getItem(int position) { return null; } @Override public long getItemId(int position) { return 0; } @SuppressLint("InflateParams") @Override public View getView(int position, View convertView, ViewGroup parent) { convertView = LayoutInflater.from(parent.getContext()).inflate( R.layout.list_cell_popup_menu, null); TextView name = (TextView) convertView.findViewById(R.id.tv_name); int iconResId = 0; // if (position == 0) { // name.setText(isFavorite ? R.string.detail_menu_unfavorite // : R.string.detail_menu_favorite); // iconResId = isFavorite ? // R.drawable.actionbar_menu_icn_unfavoirite // : R.drawable.actionbar_menu_icn_favoirite; // } else if (position == 0) { name.setText(parent.getResources().getString( R.string.detail_menu_for_share)); iconResId = R.drawable.abc_ic_menu_moreoverflow_normal_holo_dark; } else if (position == 1) { name.setText(parent.getResources().getString( R.string.detail_menu_for_report)); iconResId = R.drawable.abc_ic_menu_moreoverflow_normal_holo_dark; } Drawable drawable = AppContext.resources().getDrawable(iconResId); drawable.setBounds(0, 0, drawable.getMinimumWidth(), drawable.getMinimumHeight()); name.setCompoundDrawables(drawable, null, null, null); return convertView; } } private final AsyncHttpResponseHandler mAddFavoriteHandler = new AsyncHttpResponseHandler() { @Override public void onSuccess(int arg0, Header[] arg1, byte[] arg2) { try { Result res = XmlUtils.toBean(ResultBean.class, new ByteArrayInputStream(arg2)).getResult(); if (res.OK()) { AppContext.showToastShort(R.string.add_favorite_success); mMenuAdapter.setFavorite(true); mMenuAdapter.notifyDataSetChanged(); mIsFavorited = true; getActivity().supportInvalidateOptionsMenu(); onFavoriteChanged(true); ImageView view = (ImageView) getActivity().findViewById( R.id.action_favor); view.setImageResource(R.drawable.ic_action_favor_on_normal); } else { AppContext.showToastShort(res.getErrorMessage()); } } catch (Exception e) { e.printStackTrace(); onFailure(arg0, arg1, arg2, e); } } @Override public void onFailure(int arg0, Header[] arg1, byte[] arg2, Throwable arg3) { AppContext.showToastShort(R.string.add_favorite_faile); } }; private final AsyncHttpResponseHandler mDelFavoriteHandler = new AsyncHttpResponseHandler() { @Override public void onSuccess(int arg0, Header[] arg1, byte[] arg2) { try { Result res = XmlUtils.toBean(ResultBean.class, new ByteArrayInputStream(arg2)).getResult(); if (res.OK()) { AppContext.showToastShort(R.string.del_favorite_success); mMenuAdapter.setFavorite(false); mMenuAdapter.notifyDataSetChanged(); mIsFavorited = false; getActivity().supportInvalidateOptionsMenu(); onFavoriteChanged(false); ImageView view = (ImageView) getActivity().findViewById( R.id.action_favor); view.setImageResource(R.drawable.ic_action_favor); } else { AppContext.showToastShort(res.getErrorMessage()); } } catch (Exception e) { e.printStackTrace(); onFailure(arg0, arg1, arg2, e); } } @Override public void onFailure(int arg0, Header[] arg1, byte[] arg2, Throwable arg3) { AppContext.showToastShort(R.string.del_favorite_faile); } }; public abstract int getCommentCount(); @Override public void onClick(View v) {} @Override public void initView(View view) {} public void onclickWriteComment() {} @Override public void initData() {} }
BaseListFragment.java
package net.oschina.app.base; import java.io.ByteArrayInputStream; import java.io.InputStream; import java.io.Serializable; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List; import net.oschina.app.AppContext; import net.oschina.app.R; import net.oschina.app.bean.Entity; import net.oschina.app.bean.ListEntity; import net.oschina.app.bean.Result; import net.oschina.app.bean.ResultBean; import net.oschina.app.cache.CacheManager; import net.oschina.app.ui.empty.EmptyLayout; import net.oschina.app.util.StringUtils; import net.oschina.app.util.TDevice; import net.oschina.app.util.XmlUtils; import org.apache.http.Header; import android.annotation.SuppressLint; import android.content.Context; import android.os.AsyncTask; import android.os.Bundle; import android.support.v4.widget.SwipeRefreshLayout; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.AbsListView; import android.widget.AbsListView.OnScrollListener; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.ListView; import android.widget.TextView; import butterknife.ButterKnife; import butterknife.InjectView; import com.loopj.android.http.AsyncHttpResponseHandler; @SuppressLint("NewApi") public abstract class BaseListFragment<T extends Entity> extends BaseFragment implements SwipeRefreshLayout.OnRefreshListener, OnItemClickListener, OnScrollListener { public static final String BUNDLE_KEY_CATALOG = "BUNDLE_KEY_CATALOG"; @InjectView(R.id.swiperefreshlayout) protected SwipeRefreshLayout mSwipeRefreshLayout; @InjectView(R.id.listview) protected ListView mListView; protected ListBaseAdapter<T> mAdapter; @InjectView(R.id.error_layout) protected EmptyLayout mErrorLayout; protected int mStoreEmptyState = -1; protected int mCurrentPage = 0; protected int mCatalog = 1; // 错误信息 protected Result mResult; private AsyncTask<String, Void, ListEntity<T>> mCacheTask; private ParserTask mParserTask; @Override protected int getLayoutId() { return R.layout.fragment_pull_refresh_listview; } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(getLayoutId(), container, false); return view; } @Override public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); ButterKnife.inject(this, view); initView(view); } @Override public void onCreate(android.os.Bundle savedInstanceState) { super.onCreate(savedInstanceState); Bundle args = getArguments(); if (args != null) { mCatalog = args.getInt(BUNDLE_KEY_CATALOG, 0); } } @Override public void initView(View view) { mSwipeRefreshLayout.setOnRefreshListener(this); mSwipeRefreshLayout.setColorSchemeResources( R.color.swiperefresh_color1, R.color.swiperefresh_color2, R.color.swiperefresh_color3, R.color.swiperefresh_color4); mErrorLayout.setOnLayoutClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mCurrentPage = 0; mState = STATE_REFRESH; mErrorLayout.setErrorType(EmptyLayout.NETWORK_LOADING); requestData(true); } }); mListView.setOnItemClickListener(this); mListView.setOnScrollListener(this); if (mAdapter != null) { mListView.setAdapter(mAdapter); mErrorLayout.setErrorType(EmptyLayout.HIDE_LAYOUT); } else { mAdapter = getListAdapter(); mListView.setAdapter(mAdapter); if (requestDataIfViewCreated()) { mErrorLayout.setErrorType(EmptyLayout.NETWORK_LOADING); mState = STATE_NONE; requestData(false); } else { mErrorLayout.setErrorType(EmptyLayout.HIDE_LAYOUT); } } if (mStoreEmptyState != -1) { mErrorLayout.setErrorType(mStoreEmptyState); } } @Override public void onDestroyView() { mStoreEmptyState = mErrorLayout.getErrorState(); super.onDestroyView(); } @Override public void onDestroy() { cancelReadCacheTask(); cancelParserTask(); super.onDestroy(); } protected abstract ListBaseAdapter<T> getListAdapter(); // 下拉刷新数据 @Override public void onRefresh() { if (mState == STATE_REFRESH) { return; } // 设置顶部正在刷新 mListView.setSelection(0); setSwipeRefreshLoadingState(); mCurrentPage = 0; mState = STATE_REFRESH; requestData(true); } protected boolean requestDataIfViewCreated() { return true; } protected String getCacheKeyPrefix() { return null; } protected ListEntity<T> parseList(InputStream is) throws Exception { return null; } protected ListEntity<T> readList(Serializable seri) { return null; } @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) {} private String getCacheKey() { return new StringBuilder(getCacheKeyPrefix()).append("_") .append(mCurrentPage).toString(); } // 是否需要自动刷新 protected boolean needAutoRefresh() { return true; } /*** * 获取列表数据 * * * @author 火蚁 2015-2-9 下午3:16:12 * * @return void * @param refresh */ protected void requestData(boolean refresh) { String key = getCacheKey(); if (isReadCacheData(refresh)) { readCacheData(key); } else { // 取新的数据 sendRequestData(); } } /*** * 判断是否需要读取缓存的数据 * * @author 火蚁 2015-2-10 下午2:41:02 * * @return boolean * @param refresh * @return */ protected boolean isReadCacheData(boolean refresh) { String key = getCacheKey(); if (!TDevice.hasInternet()) { return true; } // 第一页若不是主动刷新,缓存存在,优先取缓存的 if (CacheManager.isExistDataCache(getActivity(), key) && !refresh && mCurrentPage == 0) { return true; } // 其他页数的,缓存存在以及还没有失效,优先取缓存的 if (CacheManager.isExistDataCache(getActivity(), key) && !CacheManager.isCacheDataFailure(getActivity(), key) && mCurrentPage != 0) { return true; } return false; } // 是否到时间去刷新数据了 private boolean onTimeRefresh() { String lastRefreshTime = AppContext.getLastRefreshTime(getCacheKey()); String currTime = StringUtils.getCurTimeStr(); long diff = StringUtils.calDateDifferent(lastRefreshTime, currTime); return needAutoRefresh() && diff > getAutoRefreshTime(); } /*** * 自动刷新的时间 * * 默认:自动刷新的时间为半天时间 * * @author 火蚁 2015-2-9 下午5:55:11 * * @return long * @return */ protected long getAutoRefreshTime() { return 12 * 60 * 60; } @Override public void onResume() { super.onResume(); if (onTimeRefresh()) { onRefresh(); } } protected void sendRequestData() {} private void readCacheData(String cacheKey) { cancelReadCacheTask(); mCacheTask = new CacheTask(getActivity()).execute(cacheKey); } private void cancelReadCacheTask() { if (mCacheTask != null) { mCacheTask.cancel(true); mCacheTask = null; } } private class CacheTask extends AsyncTask<String, Void, ListEntity<T>> { private final WeakReference<Context> mContext; private CacheTask(Context context) { mContext = new WeakReference<Context>(context); } @Override protected ListEntity<T> doInBackground(String... params) { Serializable seri = CacheManager.readObject(mContext.get(), params[0]); if (seri == null) { return null; } else { return readList(seri); } } @Override protected void onPostExecute(ListEntity<T> list) { super.onPostExecute(list); if (list != null) { executeOnLoadDataSuccess(list.getList()); } else { executeOnLoadDataError(null); } executeOnLoadFinish(); } } private class SaveCacheTask extends AsyncTask<Void, Void, Void> { private final WeakReference<Context> mContext; private final Serializable seri; private final String key; private SaveCacheTask(Context context, Serializable seri, String key) { mContext = new WeakReference<Context>(context); this.seri = seri; this.key = key; } @Override protected Void doInBackground(Void... params) { CacheManager.saveObject(mContext.get(), seri, key); return null; } } protected AsyncHttpResponseHandler mHandler = new AsyncHttpResponseHandler() { @Override public void onSuccess(int statusCode, Header[] headers, byte[] responseBytes) { if (mCurrentPage == 0 && needAutoRefresh()) { AppContext.putToLastRefreshTime(getCacheKey(), StringUtils.getCurTimeStr()); } if (isAdded()) { if (mState == STATE_REFRESH) { onRefreshNetworkSuccess(); } executeParserTask(responseBytes); } } @Override public void onFailure(int arg0, Header[] arg1, byte[] arg2, Throwable arg3) { if (isAdded()) { readCacheData(getCacheKey()); } } }; protected void executeOnLoadDataSuccess(List<T> data) { if (data == null) { data = new ArrayList<T>(); } if (mResult != null && !mResult.OK()) { AppContext.showToast(mResult.getErrorMessage()); // 注销登陆,密码已经修改,cookie,失效了 AppContext.getInstance().Logout(); } mErrorLayout.setErrorType(EmptyLayout.HIDE_LAYOUT); if (mCurrentPage == 0) { mAdapter.clear(); } for (int i = 0; i < data.size(); i++) { if (compareTo(mAdapter.getData(), data.get(i))) { data.remove(i); i--; } } int adapterState = ListBaseAdapter.STATE_EMPTY_ITEM; if ((mAdapter.getCount() + data.size()) == 0) { adapterState = ListBaseAdapter.STATE_EMPTY_ITEM; } else if (data.size() == 0 || (data.size() < getPageSize() && mCurrentPage == 0)) { adapterState = ListBaseAdapter.STATE_NO_MORE; mAdapter.notifyDataSetChanged(); } else { adapterState = ListBaseAdapter.STATE_LOAD_MORE; } mAdapter.setState(adapterState); mAdapter.addData(data); // 判断等于是因为最后有一项是listview的状态 if (mAdapter.getCount() == 1) { if (needShowEmptyNoData()) { mErrorLayout.setErrorType(EmptyLayout.NODATA); } else { mAdapter.setState(ListBaseAdapter.STATE_EMPTY_ITEM); mAdapter.notifyDataSetChanged(); } } } /** * 是否需要隐藏listview,显示无数据状态 * * @author 火蚁 2015-1-27 下午6:18:59 * */ protected boolean needShowEmptyNoData() { return true; } protected boolean compareTo(List<? extends Entity> data, Entity enity) { int s = data.size(); if (enity != null) { for (int i = 0; i < s; i++) { if (enity.getId() == data.get(i).getId()) { return true; } } } return false; } protected int getPageSize() { return AppContext.PAGE_SIZE; } protected void onRefreshNetworkSuccess() {} protected void executeOnLoadDataError(String error) { if (mCurrentPage == 0 && !CacheManager.isExistDataCache(getActivity(), getCacheKey())) { mErrorLayout.setErrorType(EmptyLayout.NETWORK_ERROR); } else { mErrorLayout.setErrorType(EmptyLayout.HIDE_LAYOUT); mAdapter.setState(ListBaseAdapter.STATE_NETWORK_ERROR); mAdapter.notifyDataSetChanged(); } } // 完成刷新 protected void executeOnLoadFinish() { setSwipeRefreshLoadedState(); mState = STATE_NONE; } /** 设置顶部正在加载的状态 */ private void setSwipeRefreshLoadingState() { if (mSwipeRefreshLayout != null) { mSwipeRefreshLayout.setRefreshing(true); // 防止多次重复刷新 mSwipeRefreshLayout.setEnabled(false); } } /** 设置顶部加载完毕的状态 */ private void setSwipeRefreshLoadedState() { if (mSwipeRefreshLayout != null) { mSwipeRefreshLayout.setRefreshing(false); mSwipeRefreshLayout.setEnabled(true); } } private void executeParserTask(byte[] data) { cancelParserTask(); mParserTask = new ParserTask(data); mParserTask.execute(); } private void cancelParserTask() { if (mParserTask != null) { mParserTask.cancel(true); mParserTask = null; } } class ParserTask extends AsyncTask<Void, Void, String> { private final byte[] reponseData; private boolean parserError; private List<T> list; public ParserTask(byte[] data) { this.reponseData = data; } @Override protected String doInBackground(Void... params) { try { ListEntity<T> data = parseList(new ByteArrayInputStream( reponseData)); new SaveCacheTask(getActivity(), data, getCacheKey()).execute(); list = data.getList(); if (list == null) { ResultBean resultBean = XmlUtils.toBean(ResultBean.class, reponseData); if (resultBean != null) { mResult = resultBean.getResult(); } } } catch (Exception e) { e.printStackTrace(); parserError = true; } return null; } @Override protected void onPostExecute(String result) { super.onPostExecute(result); if (parserError) { readCacheData(getCacheKey()); } else { executeOnLoadDataSuccess(list); executeOnLoadFinish(); } } } @Override public void onScrollStateChanged(AbsListView view, int scrollState) { if (mAdapter == null || mAdapter.getCount() == 0) { return; } // 数据已经全部加载,或数据为空时,或正在加载,不处理滚动事件 if (mState == STATE_LOADMORE || mState == STATE_REFRESH) { return; } // 判断是否滚动到底部 boolean scrollEnd = false; try { if (view.getPositionForView(mAdapter.getFooterView()) == view .getLastVisiblePosition()) scrollEnd = true; } catch (Exception e) { scrollEnd = false; } if (mState == STATE_NONE && scrollEnd) { if (mAdapter.getState() == ListBaseAdapter.STATE_LOAD_MORE || mAdapter.getState() == ListBaseAdapter.STATE_NETWORK_ERROR) { mCurrentPage++; mState = STATE_LOADMORE; requestData(false); mAdapter.setFooterViewLoading(); } } } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { // 数据已经全部加载,或数据为空时,或正在加载,不处理滚动事件 // if (mState == STATE_NOMORE || mState == STATE_LOADMORE // || mState == STATE_REFRESH) { // return; // } // if (mAdapter != null // && mAdapter.getDataSize() > 0 // && mListView.getLastVisiblePosition() == (mListView.getCount() - 1)) // { // if (mState == STATE_NONE // && mAdapter.getState() == ListBaseAdapter.STATE_LOAD_MORE) { // mState = STATE_LOADMORE; // mCurrentPage++; // requestData(true); // } // } } /** * 保存已读的文章列表 * * @param view * @param prefFileName * @param key */ protected void saveToReadedList(final View view, final String prefFileName, final String key) { // 放入已读列表 AppContext.putReadedPostList(prefFileName, key, "true"); TextView tvTitle = (TextView) view.findViewById(R.id.tv_title); if (tvTitle != null) { tvTitle.setTextColor(0xff9a9a9a); } } }
BaseViewPagerFragment.java
package net.oschina.app.base; import net.oschina.app.R; import net.oschina.app.adapter.ViewPageFragmentAdapter; import net.oschina.app.ui.empty.EmptyLayout; import net.oschina.app.widget.PagerSlidingTabStrip; import android.os.Bundle; import android.support.v4.view.ViewPager; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; /** * 带有导航条的基类 * * @author FireAnt(http://my.oschina.net/LittleDY) * @created 2014年11月6日 下午4:59:50 * */ public abstract class BaseViewPagerFragment extends BaseFragment { protected PagerSlidingTabStrip mTabStrip; protected ViewPager mViewPager; protected ViewPageFragmentAdapter mTabsAdapter; protected EmptyLayout mErrorLayout; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.base_viewpage_fragment, null); } @Override public void onViewCreated(View view, Bundle savedInstanceState) { mTabStrip = (PagerSlidingTabStrip) view .findViewById(R.id.pager_tabstrip); mViewPager = (ViewPager) view.findViewById(R.id.pager); mErrorLayout = (EmptyLayout) view.findViewById(R.id.error_layout); mTabsAdapter = new ViewPageFragmentAdapter(getChildFragmentManager(), mTabStrip, mViewPager); setScreenPageLimit(); onSetupTabAdapter(mTabsAdapter); // if (savedInstanceState != null) { // int pos = savedInstanceState.getInt("position"); // mViewPager.setCurrentItem(pos, true); // } } protected void setScreenPageLimit() { } // @Override // public void onSaveInstanceState(Bundle outState) { // //No call for super(). Bug on API Level > 11. // if (outState != null && mViewPager != null) { // outState.putInt("position", mViewPager.getCurrentItem()); // } // //super.onSaveInstanceState(outState); // } protected abstract void onSetupTabAdapter(ViewPageFragmentAdapter adapter); }
BeseHaveHeaderListFragment.java
package net.oschina.app.base; import java.io.ByteArrayInputStream; import java.io.Serializable; import java.lang.ref.WeakReference; import net.oschina.app.bean.Entity; import net.oschina.app.cache.CacheManager; import net.oschina.app.ui.empty.EmptyLayout; import org.apache.http.Header; import android.app.Activity; import android.content.Context; import android.os.AsyncTask; import android.os.Bundle; import android.view.View; import butterknife.ButterKnife; import com.loopj.android.http.AsyncHttpResponseHandler; /** * 需要加入header的BaseListFragment * * @desc 应用场景:如动弹详情、团队任务详情这些, 即是头部显示详情,然后下面显示评论列表的 * * BeseHaveHeaderListFragment.java * * @author 火蚁(http://my.oschina.net/u/253900) * * @data 2015-1-27 下午3:02:42 */ public abstract class BeseHaveHeaderListFragment<T1 extends Entity, T2 extends Serializable> extends BaseListFragment<T1> { protected T2 detailBean;// list 头部的详情实体类 protected Activity aty; protected final AsyncHttpResponseHandler mDetailHandler = new AsyncHttpResponseHandler() { @Override public void onSuccess(int arg0, Header[] arg1, byte[] arg2) { try { if (arg2 != null) { T2 detail = getDetailBean(new ByteArrayInputStream(arg2)); if (detail != null) { requstListData(); executeOnLoadDetailSuccess(detail); new SaveCacheTask(getActivity(), detail, getDetailCacheKey()).execute(); } else { onFailure(arg0, arg1, arg2, null); } } else { throw new RuntimeException("load detail error"); } } catch (Exception e) { e.printStackTrace(); onFailure(arg0, arg1, arg2, e); } } @Override public void onFailure(int arg0, Header[] arg1, byte[] arg2, Throwable arg3) { readDetailCacheData(getDetailCacheKey()); } }; @Override public void onViewCreated(View view, Bundle savedInstanceState) { // 通过注解绑定控件 ButterKnife.inject(this, view); mListView.addHeaderView(initHeaderView()); aty = getActivity(); super.initView(view); requestDetailData(isRefresh()); } protected boolean isRefresh() { return false; } protected abstract void requestDetailData(boolean isRefresh); protected abstract View initHeaderView(); protected abstract String getDetailCacheKey(); protected abstract void executeOnLoadDetailSuccess(T2 detailBean); protected abstract T2 getDetailBean(ByteArrayInputStream is); @Override protected boolean requestDataIfViewCreated() { return false; } private void requstListData() { mState = STATE_REFRESH; mAdapter.setState(ListBaseAdapter.STATE_LOAD_MORE); sendRequestData(); } /*** * 带有header view的listfragment不需要显示是否数据为空 */ @Override protected boolean needShowEmptyNoData() { return false; } protected void readDetailCacheData(String cacheKey) { new ReadCacheTask(getActivity()).execute(cacheKey); } private class SaveCacheTask extends AsyncTask<Void, Void, Void> { private final WeakReference<Context> mContext; private final Serializable seri; private final String key; private SaveCacheTask(Context context, Serializable seri, String key) { mContext = new WeakReference<Context>(context); this.seri = seri; this.key = key; } @Override protected Void doInBackground(Void... params) { CacheManager.saveObject(mContext.get(), seri, key); return null; } } private class ReadCacheTask extends AsyncTask<String, Void, T2> { private final WeakReference<Context> mContext; private ReadCacheTask(Context context) { mContext = new WeakReference<Context>(context); } @Override protected T2 doInBackground(String... params) { if (mContext.get() != null) { Serializable seri = CacheManager.readObject(mContext.get(), params[0]); if (seri == null) { return null; } else { return (T2) seri; } } return null; } @Override protected void onPostExecute(T2 t) { super.onPostExecute(t); if (t != null) { requstListData(); executeOnLoadDetailSuccess(t); } } } @Override protected void executeOnLoadDataError(String error) { mErrorLayout.setErrorType(EmptyLayout.HIDE_LAYOUT); mAdapter.setState(ListBaseAdapter.STATE_NETWORK_ERROR); mAdapter.notifyDataSetChanged(); } @SuppressWarnings("unchecked") protected <T extends View> T findHeaderView(View headerView, int viewId) { return (T) headerView.findViewById(viewId); } }
ListBaseAdapter.java
package net.oschina.app.base; import java.util.ArrayList; import java.util.List; import net.oschina.app.R; import net.oschina.app.bean.Entity; import net.oschina.app.emoji.InputHelper; import net.oschina.app.util.StringUtils; import net.oschina.app.util.TDevice; import net.oschina.app.widget.MyLinkMovementMethod; import net.oschina.app.widget.MyURLSpan; import net.oschina.app.widget.TweetTextView; import android.annotation.SuppressLint; import android.content.Context; import android.text.Html; import android.text.Spanned; import android.text.TextUtils; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.LinearLayout; import android.widget.ProgressBar; import android.widget.TextView; public class ListBaseAdapter<T extends Entity> extends BaseAdapter { public static final int STATE_EMPTY_ITEM = 0; public static final int STATE_LOAD_MORE = 1; public static final int STATE_NO_MORE = 2; public static final int STATE_NO_DATA = 3; public static final int STATE_LESS_ONE_PAGE = 4; public static final int STATE_NETWORK_ERROR = 5; public static final int STATE_OTHER = 6; protected int state = STATE_LESS_ONE_PAGE; protected int _loadmoreText; protected int _loadFinishText; protected int _noDateText; protected int mScreenWidth; private LayoutInflater mInflater; protected LayoutInflater getLayoutInflater(Context context) { if (mInflater == null) { mInflater = (LayoutInflater) context .getSystemService(Context.LAYOUT_INFLATER_SERVICE); } return mInflater; } public void setScreenWidth(int width) { mScreenWidth = width; } public void setState(int state) { this.state = state; } public int getState() { return this.state; } protected ArrayList<T> mDatas = new ArrayList<T>(); public ListBaseAdapter() { _loadmoreText = R.string.loading; _loadFinishText = R.string.loading_no_more; _noDateText = R.string.error_view_no_data; } @Override public int getCount() { switch (getState()) { case STATE_EMPTY_ITEM: return getDataSize() + 1; case STATE_NETWORK_ERROR: case STATE_LOAD_MORE: return getDataSize() + 1; case STATE_NO_DATA: return 1; case STATE_NO_MORE: return getDataSize() + 1; case STATE_LESS_ONE_PAGE: return getDataSize(); default: break; } return getDataSize(); } public int getDataSize() { return mDatas.size(); } @Override public T getItem(int arg0) { if (mDatas.size() > arg0) { return mDatas.get(arg0); } return null; } @Override public long getItemId(int arg0) { return arg0; } public void setData(ArrayList<T> data) { mDatas = data; notifyDataSetChanged(); } public ArrayList<T> getData() { return mDatas == null ? (mDatas = new ArrayList<T>()) : mDatas; } public void addData(List<T> data) { if (mDatas != null && data != null && !data.isEmpty()) { mDatas.addAll(data); } notifyDataSetChanged(); } public void addItem(T obj) { if (mDatas != null) { mDatas.add(obj); } notifyDataSetChanged(); } public void addItem(int pos, T obj) { if (mDatas != null) { mDatas.add(pos, obj); } notifyDataSetChanged(); } public void removeItem(Object obj) { mDatas.remove(obj); notifyDataSetChanged(); } public void clear() { mDatas.clear(); notifyDataSetChanged(); } public void setLoadmoreText(int loadmoreText) { _loadmoreText = loadmoreText; } public void setLoadFinishText(int loadFinishText) { _loadFinishText = loadFinishText; } public void setNoDataText(int noDataText) { _noDateText = noDataText; } protected boolean loadMoreHasBg() { return true; } @SuppressWarnings("deprecation") @SuppressLint("InflateParams") @Override public View getView(int position, View convertView, ViewGroup parent) { if (position == getCount() - 1) {// 最后一条 // if (position < _data.size()) { // position = getCount() - 2; // footview // } if (getState() == STATE_LOAD_MORE || getState() == STATE_NO_MORE || state == STATE_EMPTY_ITEM || getState() == STATE_NETWORK_ERROR) { this.mFooterView = (LinearLayout) LayoutInflater.from( parent.getContext()).inflate(R.layout.list_cell_footer, null); if (!loadMoreHasBg()) { mFooterView.setBackgroundDrawable(null); } ProgressBar progress = (ProgressBar) mFooterView .findViewById(R.id.progressbar); TextView text = (TextView) mFooterView.findViewById(R.id.text); switch (getState()) { case STATE_LOAD_MORE: setFooterViewLoading(); break; case STATE_NO_MORE: mFooterView.setVisibility(View.VISIBLE); progress.setVisibility(View.GONE); text.setVisibility(View.VISIBLE); text.setText(_loadFinishText); break; case STATE_EMPTY_ITEM: progress.setVisibility(View.GONE); mFooterView.setVisibility(View.VISIBLE); text.setText(_noDateText); break; case STATE_NETWORK_ERROR: mFooterView.setVisibility(View.VISIBLE); progress.setVisibility(View.GONE); text.setVisibility(View.VISIBLE); if (TDevice.hasInternet()) { text.setText("加载出错了"); } else { text.setText("没有可用的网络"); } break; default: progress.setVisibility(View.GONE); mFooterView.setVisibility(View.GONE); text.setVisibility(View.GONE); break; } return mFooterView; } } if (position < 0) { position = 0; // 若列表没有数据,是没有footview/headview的 } return getRealView(position, convertView, parent); } protected View getRealView(int position, View convertView, ViewGroup parent) { return null; } private LinearLayout mFooterView; public View getFooterView() { return this.mFooterView; } public void setFooterViewLoading(String loadMsg) { ProgressBar progress = (ProgressBar) mFooterView .findViewById(R.id.progressbar); TextView text = (TextView) mFooterView.findViewById(R.id.text); mFooterView.setVisibility(View.VISIBLE); progress.setVisibility(View.VISIBLE); text.setVisibility(View.VISIBLE); if (StringUtils.isEmpty(loadMsg)) { text.setText(_loadmoreText); } else { text.setText(loadMsg); } } public void setFooterViewLoading() { setFooterViewLoading(""); } public void setFooterViewText(String msg) { ProgressBar progress = (ProgressBar) mFooterView .findViewById(R.id.progressbar); TextView text = (TextView) mFooterView.findViewById(R.id.text); mFooterView.setVisibility(View.VISIBLE); progress.setVisibility(View.GONE); text.setVisibility(View.VISIBLE); text.setText(msg); } protected void setContent(TweetTextView contentView, String content) { contentView.setMovementMethod(MyLinkMovementMethod.a()); contentView.setFocusable(false); contentView.setDispatchToParent(true); contentView.setLongClickable(false); Spanned span = Html.fromHtml(TweetTextView.modifyPath(content)); span = InputHelper.displayEmoji(contentView.getResources(), span.toString()); contentView.setText(span); MyURLSpan.parseLinkText(contentView, span); } protected void setText(TextView textView, String text, boolean needGone) { if (text == null || TextUtils.isEmpty(text)) { if (needGone) { textView.setVisibility(View.GONE); } } else { textView.setText(text); } } protected void setText(TextView textView, String text) { setText(textView, text, false); } }
AppConfig.java
package net.oschina.app; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.util.Properties; import android.content.Context; import android.content.SharedPreferences; import android.os.Environment; import android.preference.PreferenceManager; /** * 应用程序配置类:用于保存用户相关信息及设置 * * @author FireAnt(http://my.oschina.net/LittleDY) * @created 2014年9月25日 下午5:29:00 * */ public class AppConfig { private final static String APP_CONFIG = "config"; public final static String CONF_COOKIE = "cookie"; public final static String CONF_APP_UNIQUEID = "APP_UNIQUEID"; public static final String KEY_LOAD_IMAGE = "KEY_LOAD_IMAGE"; public static final String KEY_NOTIFICATION_ACCEPT = "KEY_NOTIFICATION_ACCEPT"; public static final String KEY_NOTIFICATION_SOUND = "KEY_NOTIFICATION_SOUND"; public static final String KEY_NOTIFICATION_VIBRATION = "KEY_NOTIFICATION_VIBRATION"; public static final String KEY_NOTIFICATION_DISABLE_WHEN_EXIT = "KEY_NOTIFICATION_DISABLE_WHEN_EXIT"; public static final String KEY_CHECK_UPDATE = "KEY_CHECK_UPDATE"; public static final String KEY_DOUBLE_CLICK_EXIT = "KEY_DOUBLE_CLICK_EXIT"; public static final String LAST_QUESTION_CATEGORY_IDX = "LAST_QUESTION_CATEGORY_IDX"; public static final String KEY_DAILY_ENGLISH = "KEY_DAILY_ENGLISH"; public static final String KEY_GET_LAST_DAILY_ENG = "KEY_GET_LAST_DAILY_ENG"; public static final String KEY_TWEET_DRAFT = "KEY_TWEET_DRAFT"; public static final String KEY_NOTE_DRAFT = "KEY_NOTE_DRAFT"; public static final String KEY_QUESTION_TITLE_DRAFT = "KEY_QUESTION_TITLE_DRAFT"; public static final String KEY_QUESTION_CONTENT_DRAFT = "KEY_QUESTION_CONTENT_DRAFT"; public static final String KEY_QUESTION_TYPE_DRAFT = "KEY_QUESTION_TYPE_DRAFT"; public static final String KEY_QUESTION_LMK_DRAFT = "KEY_QUESTION_LMK_DRAFT"; public static final String KEY_FRITST_START = "KEY_FRIST_START"; public static final String APP_QQ_KEY = "100942993"; // 默认存放图片的路径 public final static String DEFAULT_SAVE_IMAGE_PATH = Environment .getExternalStorageDirectory() + File.separator + "OSChina" + File.separator + "osc_img" + File.separator; // 默认存放文件下载的路径 public final static String DEFAULT_SAVE_FILE_PATH = Environment .getExternalStorageDirectory() + File.separator + "OSChina" + File.separator + "download" + File.separator; private Context mContext; private static AppConfig appConfig; public static AppConfig getAppConfig(Context context) { if (appConfig == null) { appConfig = new AppConfig(); appConfig.mContext = context; } return appConfig; } /** * 获取Preference设置 */ public static SharedPreferences getSharedPreferences(Context context) { return PreferenceManager.getDefaultSharedPreferences(context); } public String get(String key) { Properties props = get(); return (props != null) ? props.getProperty(key) : null; } public Properties get() { FileInputStream fis = null; Properties props = new Properties(); try { // 读取files目录下的config // fis = activity.openFileInput(APP_CONFIG); // 读取app_config目录下的config File dirConf = mContext.getDir(APP_CONFIG, Context.MODE_PRIVATE); fis = new FileInputStream(dirConf.getPath() + File.separator + APP_CONFIG); props.load(fis); } catch (Exception e) { } finally { try { fis.close(); } catch (Exception e) { } } return props; } private void setProps(Properties p) { FileOutputStream fos = null; try { // 把config建在files目录下 // fos = activity.openFileOutput(APP_CONFIG, Context.MODE_PRIVATE); // 把config建在(自定义)app_config的目录下 File dirConf = mContext.getDir(APP_CONFIG, Context.MODE_PRIVATE); File conf = new File(dirConf, APP_CONFIG); fos = new FileOutputStream(conf); p.store(fos, null); fos.flush(); } catch (Exception e) { e.printStackTrace(); } finally { try { fos.close(); } catch (Exception e) { } } } public void set(Properties ps) { Properties props = get(); props.putAll(ps); setProps(props); } public void set(String key, String value) { Properties props = get(); props.setProperty(key, value); setProps(props); } public void remove(String... key) { Properties props = get(); for (String k : key) props.remove(k); setProps(props); } }
AppContext .java
package net.oschina.app; import static net.oschina.app.AppConfig.KEY_FRITST_START; import static net.oschina.app.AppConfig.KEY_LOAD_IMAGE; import static net.oschina.app.AppConfig.KEY_TWEET_DRAFT; import java.util.Properties; import java.util.UUID; import net.oschina.app.api.ApiHttpClient; import net.oschina.app.base.BaseApplication; import net.oschina.app.bean.Constants; import net.oschina.app.bean.User; import net.oschina.app.cache.DataCleanManager; import net.oschina.app.util.CyptoUtils; import net.oschina.app.util.MethodsCompat; import net.oschina.app.util.StringUtils; import net.oschina.app.util.TLog; import net.oschina.app.util.UIHelper; import org.kymjs.kjframe.KJBitmap; import org.kymjs.kjframe.bitmap.BitmapConfig; import org.kymjs.kjframe.utils.KJLoger; import android.content.Intent; import android.content.pm.PackageInfo; import android.content.pm.PackageManager.NameNotFoundException; import com.loopj.android.http.AsyncHttpClient; import com.loopj.android.http.PersistentCookieStore; /** * 全局应用程序类:用于保存和调用全局应用配置及访问网络数据 * * @author 火蚁 (http://my.oschina.net/LittleDY) * @version 1.0 * @created 2014-04-22 */ public class AppContext extends BaseApplication { public static final int PAGE_SIZE = 20;// 默认分页大小 private static AppContext instance; private int loginUid; private boolean login; @Override public void onCreate() { super.onCreate(); instance = this; init(); initLogin(); // Thread.setDefaultUncaughtExceptionHandler(AppException // .getAppExceptionHandler(this)); UIHelper.sendBroadcastForNotice(this); } private void init() { // 初始化网络请求 AsyncHttpClient client = new AsyncHttpClient(); PersistentCookieStore myCookieStore = new PersistentCookieStore(this); client.setCookieStore(myCookieStore); ApiHttpClient.setHttpClient(client); ApiHttpClient.setCookie(ApiHttpClient.getCookie(this)); // Log控制器 KJLoger.openDebutLog(true); TLog.DEBUG = BuildConfig.DEBUG; // Bitmap缓存地址 BitmapConfig.CACHEPATH = "OSChina/imagecache"; } private void initLogin() { User user = getLoginUser(); if (null != user && user.getId() > 0) { login = true; loginUid = user.getId(); } else { this.cleanLoginInfo(); } } /** * 获得当前app运行的AppContext * * @return */ public static AppContext getInstance() { return instance; } public boolean containsProperty(String key) { Properties props = getProperties(); return props.containsKey(key); } public void setProperties(Properties ps) { AppConfig.getAppConfig(this).set(ps); } public Properties getProperties() { return AppConfig.getAppConfig(this).get(); } public void setProperty(String key, String value) { AppConfig.getAppConfig(this).set(key, value); } /** * 获取cookie时传AppConfig.CONF_COOKIE * * @param key * @return */ public String getProperty(String key) { String res = AppConfig.getAppConfig(this).get(key); return res; } public void removeProperty(String... key) { AppConfig.getAppConfig(this).remove(key); } /** * 获取App唯一标识 * * @return */ public String getAppId() { String uniqueID = getProperty(AppConfig.CONF_APP_UNIQUEID); if (StringUtils.isEmpty(uniqueID)) { uniqueID = UUID.randomUUID().toString(); setProperty(AppConfig.CONF_APP_UNIQUEID, uniqueID); } return uniqueID; } /** * 获取App安装包信息 * * @return */ public PackageInfo getPackageInfo() { PackageInfo info = null; try { info = getPackageManager().getPackageInfo(getPackageName(), 0); } catch (NameNotFoundException e) { e.printStackTrace(System.err); } if (info == null) info = new PackageInfo(); return info; } /** * 保存登录信息 * * @param username * @param pwd */ @SuppressWarnings("serial") public void saveUserInfo(final User user) { this.loginUid = user.getId(); this.login = true; setProperties(new Properties() { { setProperty("user.uid", String.valueOf(user.getId())); setProperty("user.name", user.getName()); setProperty("user.face", user.getPortrait());// 用户头像-文件名 setProperty("user.account", user.getAccount()); setProperty("user.pwd", CyptoUtils.encode("oschinaApp", user.getPwd())); setProperty("user.location", user.getLocation()); setProperty("user.followers", String.valueOf(user.getFollowers())); setProperty("user.fans", String.valueOf(user.getFans())); setProperty("user.score", String.valueOf(user.getScore())); setProperty("user.favoritecount", String.valueOf(user.getFavoritecount())); setProperty("user.gender", String.valueOf(user.getGender())); setProperty("user.isRememberMe", String.valueOf(user.isRememberMe()));// 是否记住我的信息 } }); } /** * 更新用户信息 * * @param user */ @SuppressWarnings("serial") public void updateUserInfo(final User user) { setProperties(new Properties() { { setProperty("user.name", user.getName()); setProperty("user.face", user.getPortrait());// 用户头像-文件名 setProperty("user.followers", String.valueOf(user.getFollowers())); setProperty("user.fans", String.valueOf(user.getFans())); setProperty("user.score", String.valueOf(user.getScore())); setProperty("user.favoritecount", String.valueOf(user.getFavoritecount())); setProperty("user.gender", String.valueOf(user.getGender())); } }); } /** * 获得登录用户的信息 * * @return */ public User getLoginUser() { User user = new User(); user.setId(StringUtils.toInt(getProperty("user.uid"), 0)); user.setName(getProperty("user.name")); user.setPortrait(getProperty("user.face")); user.setAccount(getProperty("user.account")); user.setLocation(getProperty("user.location")); user.setFollowers(StringUtils.toInt(getProperty("user.followers"), 0)); user.setFans(StringUtils.toInt(getProperty("user.fans"), 0)); user.setScore(StringUtils.toInt(getProperty("user.score"), 0)); user.setFavoritecount(StringUtils.toInt( getProperty("user.favoritecount"), 0)); user.setRememberMe(StringUtils.toBool(getProperty("user.isRememberMe"))); user.setGender(getProperty("user.gender")); return user; } /** * 清除登录信息 */ public void cleanLoginInfo() { this.loginUid = 0; this.login = false; removeProperty("user.uid", "user.name", "user.face", "user.location", "user.followers", "user.fans", "user.score", "user.isRememberMe", "user.gender", "user.favoritecount"); } public int getLoginUid() { return loginUid; } public boolean isLogin() { return login; } /** * 用户注销 */ public void Logout() { cleanLoginInfo(); ApiHttpClient.cleanCookie(); this.cleanCookie(); this.login = false; this.loginUid = 0; Intent intent = new Intent(Constants.INTENT_ACTION_LOGOUT); sendBroadcast(intent); } /** * 清除保存的缓存 */ public void cleanCookie() { removeProperty(AppConfig.CONF_COOKIE); } /** * 清除app缓存 */ public void clearAppCache() { DataCleanManager.cleanDatabases(this); // 清除数据缓存 DataCleanManager.cleanInternalCache(this); // 2.2版本才有将应用缓存转移到sd卡的功能 if (isMethodsCompat(android.os.Build.VERSION_CODES.FROYO)) { DataCleanManager.cleanCustomCache(MethodsCompat .getExternalCacheDir(this)); } // 清除编辑器保存的临时内容 Properties props = getProperties(); for (Object key : props.keySet()) { String _key = key.toString(); if (_key.startsWith("temp")) removeProperty(_key); } new KJBitmap().cleanCache(); } public static void setLoadImage(boolean flag) { set(KEY_LOAD_IMAGE, flag); } /** * 判断当前版本是否兼容目标版本的方法 * * @param VersionCode * @return */ public static boolean isMethodsCompat(int VersionCode) { int currentVersion = android.os.Build.VERSION.SDK_INT; return currentVersion >= VersionCode; } public static String getTweetDraft() { return getPreferences().getString( KEY_TWEET_DRAFT + getInstance().getLoginUid(), ""); } public static void setTweetDraft(String draft) { set(KEY_TWEET_DRAFT + getInstance().getLoginUid(), draft); } public static String getNoteDraft() { return getPreferences().getString( AppConfig.KEY_NOTE_DRAFT + getInstance().getLoginUid(), ""); } public static void setNoteDraft(String draft) { set(AppConfig.KEY_NOTE_DRAFT + getInstance().getLoginUid(), draft); } public static boolean isFristStart() { return getPreferences().getBoolean(KEY_FRITST_START, true); } public static void setFristStart(boolean frist) { set(KEY_FRITST_START, frist); } }
AppException.java
package net.oschina.app; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; import java.lang.Thread.UncaughtExceptionHandler; import java.net.ConnectException; import java.net.SocketException; import java.net.UnknownHostException; import net.oschina.app.util.UIHelper; import org.apache.http.HttpException; import org.kymjs.kjframe.utils.FileUtils; import org.kymjs.kjframe.utils.SystemTool; import android.content.Context; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.os.Build; import android.os.Looper; /** * 应用程序异常:用于捕获异常和提示错误信息 * * @author FireAnt(http://my.oschina.net/LittleDY) * @author kymjs (kymjs123@gmali.com) * @created 2014年9月25日 下午5:34:05 * */ @SuppressWarnings("serial") public class AppException extends Exception implements UncaughtExceptionHandler { /** 定义异常类型 */ public final static byte TYPE_NETWORK = 0x01; public final static byte TYPE_SOCKET = 0x02; public final static byte TYPE_HTTP_CODE = 0x03; public final static byte TYPE_HTTP_ERROR = 0x04; public final static byte TYPE_XML = 0x05; public final static byte TYPE_IO = 0x06; public final static byte TYPE_RUN = 0x07; public final static byte TYPE_JSON = 0x08; public final static byte TYPE_FILENOTFOUND = 0x09; private byte type;// 异常的类型 // 异常的状态码,这里一般是网络请求的状态码 private int code; /** 系统默认的UncaughtException处理类 */ private AppContext mContext; private AppException(Context context) { this.mContext = (AppContext) context; } private AppException(byte type, int code, Exception excp) { super(excp); this.type = type; this.code = code; } public int getCode() { return this.code; } public int getType() { return this.type; } public static AppException http(int code) { return new AppException(TYPE_HTTP_CODE, code, null); } public static AppException http(Exception e) { return new AppException(TYPE_HTTP_ERROR, 0, e); } public static AppException socket(Exception e) { return new AppException(TYPE_SOCKET, 0, e); } public static AppException file(Exception e) { return new AppException(TYPE_FILENOTFOUND, 0, e); } // io异常 public static AppException io(Exception e) { return io(e, 0); } // io异常 public static AppException io(Exception e, int code) { if (e instanceof UnknownHostException || e instanceof ConnectException) { return new AppException(TYPE_NETWORK, code, e); } else if (e instanceof IOException) { return new AppException(TYPE_IO, code, e); } return run(e); } public static AppException xml(Exception e) { return new AppException(TYPE_XML, 0, e); } public static AppException json(Exception e) { return new AppException(TYPE_JSON, 0, e); } // 网络请求异常 public static AppException network(Exception e) { if (e instanceof UnknownHostException || e instanceof ConnectException) { return new AppException(TYPE_NETWORK, 0, e); } else if (e instanceof HttpException) { return http(e); } else if (e instanceof SocketException) { return socket(e); } return http(e); } public static AppException run(Exception e) { return new AppException(TYPE_RUN, 0, e); } /** * 获取APP异常崩溃处理对象 * * @param context * @return */ public static AppException getAppExceptionHandler(Context context) { return new AppException(context.getApplicationContext()); } @Override public void uncaughtException(Thread thread, Throwable ex) { if (!handleException(ex)) { System.exit(0); } } /** * 自定义异常处理:收集错误信息&发送错误报告 * * @param ex * @return true:处理了该异常信息;否则返回false */ private boolean handleException(final Throwable ex) { if (ex == null || mContext == null) { return false; } boolean success = true; try { success = saveToSDCard(ex); } catch (Exception e) { } finally { if (!success) { return false; } else { final Context context = AppManager.getAppManager() .currentActivity(); // 显示异常信息&发送报告 new Thread() { @Override public void run() { Looper.prepare(); // 拿到未捕获的异常, UIHelper.sendAppCrashReport(context); Looper.loop(); } }.start(); } } return true; } private boolean saveToSDCard(Throwable ex) throws Exception { boolean append = false; File file = FileUtils.getSaveFile("OSChina", "OSCLog.log"); if (System.currentTimeMillis() - file.lastModified() > 5000) { append = true; } PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter( file, append))); // 导出发生异常的时间 pw.println(SystemTool.getDataTime("yyyy-MM-dd-HH-mm-ss")); // 导出手机信息 dumpPhoneInfo(pw); pw.println(); // 导出异常的调用栈信息 ex.printStackTrace(pw); pw.println(); pw.close(); return append; } private void dumpPhoneInfo(PrintWriter pw) throws NameNotFoundException { // 应用的版本名称和版本号 PackageManager pm = mContext.getPackageManager(); PackageInfo pi = pm.getPackageInfo(mContext.getPackageName(), PackageManager.GET_ACTIVITIES); pw.print("App Version: "); pw.print(pi.versionName); pw.print('_'); pw.println(pi.versionCode); pw.println(); // android版本号 pw.print("OS Version: "); pw.print(Build.VERSION.RELEASE); pw.print("_"); pw.println(Build.VERSION.SDK_INT); pw.println(); // 手机制造商 pw.print("Vendor: "); pw.println(Build.MANUFACTURER); pw.println(); // 手机型号 pw.print("Model: "); pw.println(Build.MODEL); pw.println(); // cpu架构 pw.print("CPU ABI: "); pw.println(Build.CPU_ABI); pw.println(); } }
AppManager.java
package net.oschina.app; import java.util.Stack; import android.app.Activity; import android.content.Context; /** * activity堆栈式管理 * * @author FireAnt(http://my.oschina.net/LittleDY) * @created 2014年10月30日 下午6:22:05 * */ public class AppManager { private static Stack<Activity> activityStack; private static AppManager instance; private AppManager() {} /** * 单一实例 */ public static AppManager getAppManager() { if (instance == null) { instance = new AppManager(); } return instance; } /** * 添加Activity到堆栈 */ public void addActivity(Activity activity) { if (activityStack == null) { activityStack = new Stack<Activity>(); } activityStack.add(activity); } /** * 获取当前Activity(堆栈中最后一个压入的) */ public Activity currentActivity() { Activity activity = activityStack.lastElement(); return activity; } /** * 结束当前Activity(堆栈中最后一个压入的) */ public void finishActivity() { Activity activity = activityStack.lastElement(); finishActivity(activity); } /** * 结束指定的Activity */ public void finishActivity(Activity activity) { if (activity != null && !activity.isFinishing()) { activityStack.remove(activity); activity.finish(); activity = null; } } /** * 结束指定类名的Activity */ public void finishActivity(Class<?> cls) { for (Activity activity : activityStack) { if (activity.getClass().equals(cls)) { finishActivity(activity); break; } } } /** * 结束所有Activity */ public void finishAllActivity() { for (int i = 0, size = activityStack.size(); i < size; i++) { if (null != activityStack.get(i)) { finishActivity(activityStack.get(i)); break; } } activityStack.clear(); } /** * 获取指定的Activity * * @author kymjs */ public static Activity getActivity(Class<?> cls) { if (activityStack != null) for (Activity activity : activityStack) { if (activity.getClass().equals(cls)) { return activity; } } return null; } /** * 退出应用程序 */ public void AppExit(Context context) { try { finishAllActivity(); // 杀死该应用进程 android.os.Process.killProcess(android.os.Process.myPid()); System.exit(0); } catch (Exception e) { } } }
AppStart.java
package net.oschina.app; import java.io.File; import net.oschina.app.ui.MainActivity; import net.oschina.app.util.TDevice; import org.kymjs.kjframe.http.KJAsyncTask; import org.kymjs.kjframe.utils.FileUtils; import org.kymjs.kjframe.utils.PreferenceHelper; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.view.animation.AlphaAnimation; import android.view.animation.Animation; import android.view.animation.Animation.AnimationListener; /** * 应用启动界面 * * @author FireAnt(http://my.oschina.net/LittleDY) * @created 2014年12月22日 上午11:51:56 * */ public class AppStart extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 防止第三方跳转时出现双实例 Activity aty = AppManager.getActivity(MainActivity.class); if (aty != null && !aty.isFinishing()) { finish(); } // SystemTool.gc(this); //针对性能好的手机使用,加快应用相应速度 final View view = View.inflate(this, R.layout.app_start, null); setContentView(view); // 渐变展示启动屏 AlphaAnimation aa = new AlphaAnimation(0.5f, 1.0f); aa.setDuration(800); view.startAnimation(aa); aa.setAnimationListener(new AnimationListener() { @Override public void onAnimationEnd(Animation arg0) { redirectTo(); } @Override public void onAnimationRepeat(Animation animation) {} @Override public void onAnimationStart(Animation animation) {} }); } @Override protected void onResume() { super.onResume(); int cacheVersion = PreferenceHelper.readInt(this, "first_install", "first_install", -1); int currentVersion = TDevice.getVersionCode(); if (cacheVersion < currentVersion) { PreferenceHelper.write(this, "first_install", "first_install", currentVersion); cleanImageCache(); } } private void cleanImageCache() { final File folder = FileUtils.getSaveFolder("OSChina/imagecache"); KJAsyncTask.execute(new Runnable() { @Override public void run() { for (File file : folder.listFiles()) { file.delete(); } } }); } /** * 跳转到... */ private void redirectTo() { Intent uploadLog = new Intent(this, LogUploadService.class); startService(uploadLog); Intent intent = new Intent(this, MainActivity.class); startActivity(intent); finish(); } }
LogUploadService.java
package net.oschina.app; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import net.oschina.app.api.remote.OSChinaApi; import net.oschina.app.util.StringUtils; import org.apache.http.Header; import org.kymjs.kjframe.utils.FileUtils; import android.app.Service; import android.content.Intent; import android.os.IBinder; import com.loopj.android.http.AsyncHttpResponseHandler; public class LogUploadService extends Service { @Override public IBinder onBind(Intent intent) { return null; } @Override public int onStartCommand(Intent intent, int flags, int startId) { final File log = FileUtils.getSaveFile("OSChina", "OSCLog.log"); String data = null; try { FileInputStream inputStream = new FileInputStream(log); data = StringUtils.toConvertString(inputStream); } catch (FileNotFoundException e) { e.printStackTrace(); } if (!StringUtils.isEmpty(data)) { OSChinaApi.uploadLog(data, new AsyncHttpResponseHandler() { @Override public void onSuccess(int arg0, Header[] arg1, byte[] arg2) { log.delete(); LogUploadService.this.stopSelf(); } @Override public void onFailure(int arg0, Header[] arg1, byte[] arg2, Throwable arg3) { LogUploadService.this.stopSelf(); } }); } else { LogUploadService.this.stopSelf(); } return super.onStartCommand(intent, flags, startId); } }
ActiveAdapter.java
package net.oschina.app.adapter; import net.oschina.app.R; import net.oschina.app.base.ListBaseAdapter; import net.oschina.app.bean.Active; import net.oschina.app.bean.Active.ObjectReply; import net.oschina.app.bean.Tweet; import net.oschina.app.emoji.InputHelper; import net.oschina.app.ui.ImagePreviewActivity; import net.oschina.app.util.ImageUtils; import net.oschina.app.util.StringUtils; import net.oschina.app.util.UIHelper; import net.oschina.app.widget.AvatarView; import net.oschina.app.widget.MyLinkMovementMethod; import net.oschina.app.widget.MyURLSpan; import net.oschina.app.widget.TweetTextView; import org.kymjs.kjframe.KJBitmap; import org.kymjs.kjframe.bitmap.BitmapCallBack; import org.kymjs.kjframe.bitmap.BitmapHelper; import org.kymjs.kjframe.utils.DensityUtils; import android.annotation.SuppressLint; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.text.Html; import android.text.Spannable; import android.text.SpannableString; import android.text.Spanned; import android.text.TextUtils; import android.text.style.ImageSpan; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; import butterknife.ButterKnife; import butterknife.InjectView; public class ActiveAdapter extends ListBaseAdapter { private final static String AT_HOST_PRE = "http://my.oschina.net"; private final static String MAIN_HOST = "http://www.oschina.net"; public ActiveAdapter() {} private Bitmap recordBitmap; private final KJBitmap kjb = new KJBitmap(); private int rectSize; private void initRecordImg(Context cxt) { recordBitmap = BitmapFactory.decodeResource(cxt.getResources(), R.drawable.audio3); recordBitmap = ImageUtils.zoomBitmap(recordBitmap, DensityUtils.dip2px(cxt, 20f), DensityUtils.dip2px(cxt, 20f)); } private void initImageSize(Context cxt) { if (cxt != null && rectSize == 0) { rectSize = (int) cxt.getResources().getDimension(R.dimen.space_100); } else { rectSize = 300; } } @Override @SuppressLint("InflateParams") protected View getRealView(int position, View convertView, final ViewGroup parent) { ViewHolder vh = null; initImageSize(parent.getContext()); if (convertView == null || convertView.getTag() == null) { convertView = getLayoutInflater(parent.getContext()).inflate( R.layout.list_cell_active, null); vh = new ViewHolder(convertView); convertView.setTag(vh); } else { vh = (ViewHolder) convertView.getTag(); } final Active item = (Active) mDatas.get(position); vh.name.setText(item.getAuthor()); vh.action.setText(UIHelper.parseActiveAction(item.getObjectType(), item.getObjectCatalog(), item.getObjectTitle())); if (TextUtils.isEmpty(item.getMessage())) { vh.body.setVisibility(View.GONE); } else { vh.body.setMovementMethod(MyLinkMovementMethod.a()); vh.body.setFocusable(false); vh.body.setDispatchToParent(true); vh.body.setLongClickable(false); Spanned span = Html.fromHtml(modifyPath(item.getMessage())); if (!StringUtils.isEmpty(item.getTweetattach())) { if (recordBitmap == null) { initRecordImg(parent.getContext()); } ImageSpan recordImg = new ImageSpan(parent.getContext(), recordBitmap); SpannableString str = new SpannableString("c"); str.setSpan(recordImg, 0, 1, Spannable.SPAN_INCLUSIVE_EXCLUSIVE); vh.body.setText(str); span = InputHelper.displayEmoji(parent.getContext() .getResources(), span); vh.body.append(span); } else { span = InputHelper.displayEmoji(parent.getContext() .getResources(), span); vh.body.setText(span); } MyURLSpan.parseLinkText(vh.body, span); } ObjectReply reply = item.getObjectReply(); if (reply != null) { vh.reply.setMovementMethod(MyLinkMovementMethod.a()); vh.reply.setFocusable(false); vh.reply.setDispatchToParent(true); vh.reply.setLongClickable(false); Spanned span = UIHelper.parseActiveReply(reply.objectName, reply.objectBody); vh.reply.setText(span);// MyURLSpan.parseLinkText(vh.reply, span); vh.lyReply.setVisibility(TextView.VISIBLE); } else { vh.reply.setText(""); vh.lyReply.setVisibility(TextView.GONE); } vh.time.setText(StringUtils.friendly_time(item.getPubDate())); vh.from.setVisibility(View.VISIBLE); switch (item.getAppClient()) { default: vh.from.setText(R.string.from_web); // 不显示 vh.from.setVisibility(View.GONE); break; case Tweet.CLIENT_MOBILE: vh.from.setText(R.string.from_mobile); break; case Tweet.CLIENT_ANDROID: vh.from.setText(R.string.from_android); break; case Tweet.CLIENT_IPHONE: vh.from.setText(R.string.from_iphone); break; case Tweet.CLIENT_WINDOWS_PHONE: vh.from.setText(R.string.from_windows_phone); break; case Tweet.CLIENT_WECHAT: vh.from.setText(R.string.from_wechat); break; } if (item.getCommentCount() > 0) { vh.commentCount.setText(String.valueOf(item.getCommentCount())); vh.commentCount.setVisibility(View.VISIBLE); } else { vh.commentCount.setVisibility(View.GONE); } vh.avatar.setUserInfo(item.getAuthorId(), item.getAuthor()); vh.avatar.setAvatarUrl(item.getPortrait()); if (!TextUtils.isEmpty(item.getTweetimage())) { setTweetImage(parent, vh, item); } else { vh.pic.setVisibility(View.GONE); vh.pic.setImageBitmap(null); } return convertView; } /** * 动态设置图片显示样式 * * @author kymjs */ private void setTweetImage(final ViewGroup parent, final ViewHolder vh, final Active item) { vh.pic.setVisibility(View.VISIBLE); kjb.display(vh.pic, item.getTweetimage(), R.drawable.pic_bg, rectSize, rectSize, new BitmapCallBack() { @Override public void onSuccess(Bitmap bitmap) { super.onSuccess(bitmap); if (bitmap != null) { bitmap = BitmapHelper.scaleWithXY(bitmap, rectSize / bitmap.getHeight()); vh.pic.setImageBitmap(bitmap); } } }); vh.pic.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { ImagePreviewActivity.showImagePrivew(parent.getContext(), 0, new String[] { getOriginalUrl(item.getTweetimage()) }); } }); } private String modifyPath(String message) { message = message.replaceAll("(<a[^>]+href=\")/([\\S]+)\"", "$1" + AT_HOST_PRE + "/$2\""); message = message.replaceAll( "(<a[^>]+href=\")http://m.oschina.net([\\S]+)\"", "$1" + MAIN_HOST + "$2\""); return message; } private String getOriginalUrl(String url) { return url.replaceAll("_thumb", ""); } static class ViewHolder { @InjectView(R.id.tv_name) TextView name; @InjectView(R.id.tv_from) TextView from; @InjectView(R.id.tv_time) TextView time; @InjectView(R.id.tv_action) TextView action; @InjectView(R.id.tv_action_name) TextView actionName; @InjectView(R.id.tv_comment_count) TextView commentCount; // @InjectView(R.id.tv_reply_content) // TextView retweetCount; @InjectView(R.id.tv_body) TweetTextView body; @InjectView(R.id.tv_reply) TweetTextView reply; @InjectView(R.id.iv_pic) ImageView pic; @InjectView(R.id.ly_reply) View lyReply; @InjectView(R.id.iv_avatar) AvatarView avatar; public ViewHolder(View view) { ButterKnife.inject(this, view); } } }
BlogAdapter.java
package net.oschina.app.adapter; import net.oschina.app.AppContext; import net.oschina.app.R; import net.oschina.app.base.ListBaseAdapter; import net.oschina.app.bean.Blog; import net.oschina.app.bean.BlogList; import net.oschina.app.util.StringUtils; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; import butterknife.ButterKnife; import butterknife.InjectView; /** * @author HuangWenwei * * @date 2014年9月29日 */ public class BlogAdapter extends ListBaseAdapter<Blog> { static class ViewHolder { @InjectView(R.id.tv_title) TextView title; @InjectView(R.id.tv_description) TextView description; @InjectView(R.id.tv_source) TextView source; @InjectView(R.id.tv_time) TextView time; @InjectView(R.id.tv_comment_count) TextView comment_count; @InjectView(R.id.iv_tip) ImageView tip; public ViewHolder(View view) { ButterKnife.inject(this, view); } } @Override protected View getRealView(int position, View convertView, ViewGroup parent) { ViewHolder vh = null; if (convertView == null || convertView.getTag() == null) { convertView = getLayoutInflater(parent.getContext()).inflate( R.layout.list_cell_news, null); vh = new ViewHolder(convertView); convertView.setTag(vh); } else { vh = (ViewHolder) convertView.getTag(); } Blog blog = mDatas.get(position); vh.tip.setVisibility(View.VISIBLE); if (blog.getDocumenttype() == Blog.DOC_TYPE_ORIGINAL) { vh.tip.setImageResource(R.drawable.widget_original_icon); } else { vh.tip.setImageResource(R.drawable.widget_repaste_icon); } vh.title.setText(blog.getTitle()); if (AppContext.isOnReadedPostList(BlogList.PREF_READED_BLOG_LIST, blog.getId() + "")) { vh.title.setTextColor(parent.getContext().getResources() .getColor(R.color.main_gray)); } else { vh.title.setTextColor(parent.getContext().getResources() .getColor(R.color.main_black)); } vh.description.setVisibility(View.GONE); String description = blog.getBody(); if (null != description && !StringUtils.isEmpty(description)) { vh.description.setVisibility(View.VISIBLE); vh.description.setText(description.trim()); } vh.source.setText(blog.getAuthor()); vh.time.setText(StringUtils.friendly_time(blog.getPubDate())); vh.comment_count.setText(blog.getCommentCount() + ""); return convertView; } }
RecycleBin.java
package net.oschina.app.adapter; import android.annotation.SuppressLint; import android.os.Build; import android.util.SparseArray; import android.view.View; /** * The RecycleBin facilitates reuse of views across layouts. The RecycleBin has two levels of * storage: ActiveViews and ScrapViews. ActiveViews are those views which were onscreen at the * start of a layout. By construction, they are displaying current information. At the end of * layout, all views in ActiveViews are demoted to ScrapViews. ScrapViews are old views that * could potentially be used by the adapter to avoid allocating views unnecessarily. * <p> * This class was taken from Android's implementation of {@link android.widget.AbsListView} which * is copyrighted 2006 The Android Open Source Project. */ public class RecycleBin { /** * Views that were on screen at the start of layout. This array is populated at the start of * layout, and at the end of layout all view in activeViews are moved to scrapViews. * Views in activeViews represent a contiguous range of Views, with position of the first * view store in mFirstActivePosition. */ private View[] activeViews = new View[0]; private int[] activeViewTypes = new int[0]; /** Unsorted views that can be used by the adapter as a convert view. */ private SparseArray<View>[] scrapViews; private int viewTypeCount; private SparseArray<View> currentScrapViews; public void setViewTypeCount(int viewTypeCount) { if (viewTypeCount < 1) { throw new IllegalArgumentException("Can't have a viewTypeCount < 1"); } //noinspection unchecked SparseArray<View>[] scrapViews = new SparseArray[viewTypeCount]; for (int i = 0; i < viewTypeCount; i++) { scrapViews[i] = new SparseArray<View>(); } this.viewTypeCount = viewTypeCount; currentScrapViews = scrapViews[0]; this.scrapViews = scrapViews; } protected boolean shouldRecycleViewType(int viewType) { return viewType >= 0; } /** @return A view from the ScrapViews collection. These are unordered. */ View getScrapView(int position, int viewType) { if (viewTypeCount == 1) { return retrieveFromScrap(currentScrapViews, position); } else if (viewType >= 0 && viewType < scrapViews.length) { return retrieveFromScrap(scrapViews[viewType], position); } return null; } /** * Put a view into the ScrapViews list. These views are unordered. * * @param scrap The view to add */ @SuppressLint("NewApi") void addScrapView(View scrap, int position, int viewType) { if (viewTypeCount == 1) { currentScrapViews.put(position, scrap); } else { scrapViews[viewType].put(position, scrap); } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { scrap.setAccessibilityDelegate(null); } } /** Move all views remaining in activeViews to scrapViews. */ @SuppressLint("NewApi") void scrapActiveViews() { final View[] activeViews = this.activeViews; final int[] activeViewTypes = this.activeViewTypes; final boolean multipleScraps = viewTypeCount > 1; SparseArray<View> scrapViews = currentScrapViews; final int count = activeViews.length; for (int i = count - 1; i >= 0; i--) { final View victim = activeViews[i]; if (victim != null) { int whichScrap = activeViewTypes[i]; activeViews[i] = null; activeViewTypes[i] = -1; if (!shouldRecycleViewType(whichScrap)) { continue; } if (multipleScraps) { scrapViews = this.scrapViews[whichScrap]; } scrapViews.put(i, victim); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { victim.setAccessibilityDelegate(null); } } } pruneScrapViews(); } /** * Makes sure that the size of scrapViews does not exceed the size of activeViews. * (This can happen if an adapter does not recycle its views). */ private void pruneScrapViews() { final int maxViews = activeViews.length; final int viewTypeCount = this.viewTypeCount; final SparseArray<View>[] scrapViews = this.scrapViews; for (int i = 0; i < viewTypeCount; ++i) { final SparseArray<View> scrapPile = scrapViews[i]; int size = scrapPile.size(); final int extras = size - maxViews; size--; for (int j = 0; j < extras; j++) { scrapPile.remove(scrapPile.keyAt(size--)); } } } static View retrieveFromScrap(SparseArray<View> scrapViews, int position) { int size = scrapViews.size(); if (size > 0) { // See if we still have a view for this position. for (int i = 0; i < size; i++) { int fromPosition = scrapViews.keyAt(i); View view = scrapViews.get(fromPosition); if (fromPosition == position) { scrapViews.remove(fromPosition); return view; } } int index = size - 1; View r = scrapViews.valueAt(index); scrapViews.remove(scrapViews.keyAt(index)); return r; } else { return null; } } }
ViewPageFragmentAdapter.java
package net.oschina.app.adapter; import java.util.ArrayList; import net.oschina.app.R; import net.oschina.app.widget.PagerSlidingTabStrip; import android.annotation.SuppressLint; import android.content.Context; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentStatePagerAdapter; import android.support.v4.view.PagerAdapter; import android.support.v4.view.ViewPager; import android.view.LayoutInflater; import android.view.View; import android.widget.TextView; @SuppressLint("Recycle") public class ViewPageFragmentAdapter extends FragmentStatePagerAdapter { private final Context mContext; protected PagerSlidingTabStrip mPagerStrip; private final ViewPager mViewPager; private final ArrayList<ViewPageInfo> mTabs = new ArrayList<ViewPageInfo>(); public ViewPageFragmentAdapter(FragmentManager fm, PagerSlidingTabStrip pageStrip, ViewPager pager) { super(fm); mContext = pager.getContext(); mPagerStrip = pageStrip; mViewPager = pager; mViewPager.setAdapter(this); mPagerStrip.setViewPager(mViewPager); } public void addTab(String title, String tag, Class<?> clss, Bundle args) { ViewPageInfo viewPageInfo = new ViewPageInfo(title, tag, clss, args); addFragment(viewPageInfo); } public void addAllTab(ArrayList<ViewPageInfo> mTabs) { for (ViewPageInfo viewPageInfo : mTabs) { addFragment(viewPageInfo); } } private void addFragment(ViewPageInfo info) { if (info == null) { return; } // 加入tab title View v = LayoutInflater.from(mContext).inflate( R.layout.base_viewpage_fragment_tab_item, null, false); TextView title = (TextView) v.findViewById(R.id.tab_title); title.setText(info.title); mPagerStrip.addTab(v); mTabs.add(info); notifyDataSetChanged(); } /** * 移除第一次 */ public void remove() { remove(0); } /** * 移除一个tab * * @param index * 备注:如果index小于0,则从第一个开始删 如果大于tab的数量值则从最后一个开始删除 */ public void remove(int index) { if (mTabs.isEmpty()) { return; } if (index < 0) { index = 0; } if (index >= mTabs.size()) { index = mTabs.size() - 1; } mTabs.remove(index); mPagerStrip.removeTab(index, 1); notifyDataSetChanged(); } /** * 移除所有的tab */ public void removeAll() { if (mTabs.isEmpty()) { return; } mPagerStrip.removeAllTab(); mTabs.clear(); notifyDataSetChanged(); } @Override public int getCount() { return mTabs.size(); } @Override public int getItemPosition(Object object) { return PagerAdapter.POSITION_NONE; } @Override public Fragment getItem(int position) { ViewPageInfo info = mTabs.get(position); return Fragment.instantiate(mContext, info.clss.getName(), info.args); } @Override public CharSequence getPageTitle(int position) { return mTabs.get(position).title; } }
ApiClientHelper.java
package net.oschina.app.api; import net.oschina.app.AppContext; public class ApiClientHelper { /** * 获得请求的服务端数据的userAgent * @param appContext * @return */ public static String getUserAgent(AppContext appContext) { StringBuilder ua = new StringBuilder("OSChina.NET"); ua.append('/' + appContext.getPackageInfo().versionName + '_' + appContext.getPackageInfo().versionCode);// app版本信息 ua.append("/Android");// 手机系统平台 ua.append("/" + android.os.Build.VERSION.RELEASE);// 手机系统版本 ua.append("/" + android.os.Build.MODEL); // 手机型号 ua.append("/" + appContext.getAppId());// 客户端唯一标识 return ua.toString(); } }
ApiHttpClient.java
package net.oschina.app.api; import java.util.Locale; import net.oschina.app.AppContext; import net.oschina.app.util.TLog; import org.apache.http.client.params.ClientPNames; import android.content.Context; import android.util.Log; import com.loopj.android.http.AsyncHttpClient; import com.loopj.android.http.AsyncHttpResponseHandler; import com.loopj.android.http.RequestParams; public class ApiHttpClient { public final static String HOST = "www.oschina.net"; private static String API_URL = "http://www.oschina.net/%s"; // public final static String HOST = "192.168.1.46"; // private static String API_URL = "http://192.168.1.46/%s"; public static final String DELETE = "DELETE"; public static final String GET = "GET"; public static final String POST = "POST"; public static final String PUT = "PUT"; public static AsyncHttpClient client; public ApiHttpClient() {} public static AsyncHttpClient getHttpClient() { return client; } public static void cancelAll(Context context) { client.cancelRequests(context, true); } public static void clearUserCookies(Context context) { // (new HttpClientCookieStore(context)).a(); } public static void delete(String partUrl, AsyncHttpResponseHandler handler) { client.delete(getAbsoluteApiUrl(partUrl), handler); log(new StringBuilder("DELETE ").append(partUrl).toString()); } public static void get(String partUrl, AsyncHttpResponseHandler handler) { client.get(getAbsoluteApiUrl(partUrl), handler); log(new StringBuilder("GET ").append(partUrl).toString()); } public static void get(String partUrl, RequestParams params, AsyncHttpResponseHandler handler) { client.get(getAbsoluteApiUrl(partUrl), params, handler); log(new StringBuilder("GET ").append(partUrl).append("&") .append(params).toString()); } public static String getAbsoluteApiUrl(String partUrl) { String url = String.format(API_URL, partUrl); Log.d("BASE_CLIENT", "request:" + url); return url; } public static String getApiUrl() { return API_URL; } public static void getDirect(String url, AsyncHttpResponseHandler handler) { client.get(url, handler); log(new StringBuilder("GET ").append(url).toString()); } public static void log(String log) { Log.d("BaseApi", log); TLog.log("Test", log); } public static void post(String partUrl, AsyncHttpResponseHandler handler) { client.post(getAbsoluteApiUrl(partUrl), handler); log(new StringBuilder("POST ").append(partUrl).toString()); } public static void post(String partUrl, RequestParams params, AsyncHttpResponseHandler handler) { client.post(getAbsoluteApiUrl(partUrl), params, handler); log(new StringBuilder("POST ").append(partUrl).append("&") .append(params).toString()); } public static void postDirect(String url, RequestParams params, AsyncHttpResponseHandler handler) { client.post(url, params, handler); log(new StringBuilder("POST ").append(url).append("&").append(params) .toString()); } public static void put(String partUrl, AsyncHttpResponseHandler handler) { client.put(getAbsoluteApiUrl(partUrl), handler); log(new StringBuilder("PUT ").append(partUrl).toString()); } public static void put(String partUrl, RequestParams params, AsyncHttpResponseHandler handler) { client.put(getAbsoluteApiUrl(partUrl), params, handler); log(new StringBuilder("PUT ").append(partUrl).append("&") .append(params).toString()); } public static void setApiUrl(String apiUrl) { API_URL = apiUrl; } public static void setHttpClient(AsyncHttpClient c) { client = c; client.addHeader("Accept-Language", Locale.getDefault().toString()); client.addHeader("Host", HOST); client.addHeader("Connection", "Keep-Alive"); client.getHttpClient().getParams() .setParameter(ClientPNames.ALLOW_CIRCULAR_REDIRECTS, true); setUserAgent(ApiClientHelper.getUserAgent(AppContext.getInstance())); } public static void setUserAgent(String userAgent) { client.setUserAgent(userAgent); } public static void setCookie(String cookie) { client.addHeader("Cookie", cookie); } private static String appCookie; public static void cleanCookie() { appCookie = ""; } public static String getCookie(AppContext appContext) { if (appCookie == null || appCookie == "") { appCookie = appContext.getProperty("cookie"); } return appCookie; } }
ApiResponse.java
package net.oschina.app.api; import org.json.JSONObject; public class ApiResponse { protected Object _data; protected String _message; protected int _errorCode; protected boolean _isOk; private long _total; private String _serverTime; private boolean isCanceled; public ApiResponse(JSONObject json) { if (json != null) { setData(json.optJSONObject("data") == null ? json .optJSONArray("data") : json.optJSONObject("data")); setMessage(json.optString("result_desc")); setErrorCode(json.optInt("result_code")); setOk(getErrorCode() == 0); setServerTime(json.optString("timestamp")); } } public Object getData() { return _data; } public void setData(Object _data) { this._data = _data; } public boolean isOk() { return _isOk; } public void setOk(boolean _isOk) { this._isOk = _isOk; } public String getMessage() { return _message; } public void setMessage(String _message) { this._message = _message; } public int getErrorCode() { return _errorCode; } public void setErrorCode(int _errorCode) { this._errorCode = _errorCode; } @Override public String toString() { return "data:" + getData() + " message:" + getMessage() + " errocode:" + _errorCode; } public void update(ApiResponse response) { _message = response.getMessage(); } public void setTotal(long total) { _total = total; } public long getTotal() { return _total; } public String getServerTime() { return _serverTime; } public void setServerTime(String _serverTime) { this._serverTime = _serverTime; } public boolean isCanceled() { return isCanceled; } public void setCanceled(boolean isCanceled) { this.isCanceled = isCanceled; } }
OperationResponseHandler.java
package net.oschina.app.api; import java.io.ByteArrayInputStream; import org.apache.http.Header; import android.os.Looper; import com.loopj.android.http.AsyncHttpResponseHandler; public class OperationResponseHandler extends AsyncHttpResponseHandler { private Object[] args; public OperationResponseHandler(Looper looper, Object... args) { super(looper); this.args = args; } public OperationResponseHandler(Object... args) { this.args = args; } @Override public void onFailure(int arg0, Header[] arg1, byte[] arg2, Throwable arg3) { onFailure(arg0, arg3.getMessage(), args); } public void onFailure(int code, String errorMessage, Object[] args) { } @Override public void onSuccess(int arg0, Header[] arg1, byte[] arg2) { try { onSuccess(arg0, new ByteArrayInputStream(arg2), args); } catch (Exception e) { e.printStackTrace(); onFailure(arg0, e.getMessage(), args); } } public void onSuccess(int code, ByteArrayInputStream is, Object[] args) throws Exception { } }
OSChinaApi.java
package net.oschina.app.api.remote; import java.io.File; import java.io.FileNotFoundException; import java.net.URLEncoder; import net.oschina.app.AppContext; import net.oschina.app.AppException; import net.oschina.app.api.ApiHttpClient; import net.oschina.app.bean.EventApplyData; import net.oschina.app.bean.NewsList; import net.oschina.app.bean.Report; import net.oschina.app.bean.Tweet; import net.oschina.app.team.bean.Team; import net.oschina.app.util.StringUtils; import net.oschina.app.util.TLog; import org.kymjs.kjframe.utils.KJLoger; import android.text.TextUtils; import com.loopj.android.http.AsyncHttpResponseHandler; import com.loopj.android.http.RequestParams; public class OSChinaApi { /** * 登陆 * * @param username * @param password * @param handler */ public static void login(String username, String password, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("username", username); params.put("pwd", password); params.put("keep_login", 1); String loginurl = "action/api/login_validate"; ApiHttpClient.post(loginurl, params, handler); } /** * 获取新闻列表 * * @param catalog * 类别 (1,2,3) * @param page * 第几页 * @param handler */ public static void getNewsList(int catalog, int page, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("catalog", catalog); params.put("pageIndex", page); params.put("pageSize", AppContext.PAGE_SIZE); if (catalog == NewsList.CATALOG_WEEK) { params.put("show", "week"); } else if (catalog == NewsList.CATALOG_MONTH) { params.put("show", "month"); } ApiHttpClient.get("action/api/news_list", params, handler); } public static void getBlogList(String type, int pageIndex, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("type", type); params.put("pageIndex", pageIndex); params.put("pageSize", AppContext.PAGE_SIZE); ApiHttpClient.get("action/api/blog_list", params, handler); } public static void getPostList(int catalog, int page, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("catalog", catalog); params.put("pageIndex", page); params.put("pageSize", AppContext.PAGE_SIZE); ApiHttpClient.get("action/api/post_list", params, handler); } public static void getPostListByTag(String tag, int page, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("tag", tag); params.put("pageIndex", page); params.put("pageSize", AppContext.PAGE_SIZE); ApiHttpClient.get("action/api/post_list", params, handler); } public static void getTweetList(int uid, int page, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("uid", uid); params.put("pageIndex", page); params.put("pageSize", AppContext.PAGE_SIZE); ApiHttpClient.get("action/api/tweet_list", params, handler); } public static void getTweetTopicList(int page, String topic, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("pageIndex", page); params.put("title", topic); params.put("pageSize", AppContext.PAGE_SIZE); ApiHttpClient.get("action/api/tweet_topic_list", params, handler); } public static void getTweetLikeList(AsyncHttpResponseHandler handler) { ApiHttpClient.get("action/api/my_tweet_like_list", handler); } public static void pubLikeTweet(int tweetId, int authorId, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("tweetid", tweetId); params.put("uid", AppContext.getInstance().getLoginUid()); params.put("ownerOfTweet", authorId); ApiHttpClient.post("action/api/tweet_like", params, handler); } public static void pubUnLikeTweet(int tweetId, int authorId, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("tweetid", tweetId); params.put("uid", AppContext.getInstance().getLoginUid()); params.put("ownerOfTweet", authorId); ApiHttpClient.post("action/api/tweet_unlike", params, handler); } public static void getTweetLikeList(int tweetId, int page, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("tweetid", tweetId); params.put("pageIndex", page); params.put("pageSize", AppContext.PAGE_SIZE); ApiHttpClient.get("action/api/tweet_like_list", params, handler); } public static void getActiveList(int uid, int catalog, int page, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("uid", uid); params.put("catalog", catalog); params.put("pageIndex", page); params.put("pageSize", AppContext.PAGE_SIZE); ApiHttpClient.get("action/api/active_list", params, handler); } public static void getFriendList(int uid, int relation, int page, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("uid", uid); params.put("relation", relation); params.put("pageIndex", page); params.put("pageSize", AppContext.PAGE_SIZE); ApiHttpClient.get("action/api/friends_list", params, handler); } /** * 获取用户收藏 * * @param uid * 指定用户UID * @param type * 收藏类型: 0:全部收藏 1:软件 2:话题 3:博客 4:新闻 5:代码 * @param page * @param handler */ public static void getFavoriteList(int uid, int type, int page, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("uid", uid); params.put("type", type); params.put("pageIndex", page); params.put("pageSize", AppContext.PAGE_SIZE); ApiHttpClient.get("action/api/favorite_list", params, handler); } /** * 分类列表 * * @param tag * 第一级:0 * @param handler */ public static void getSoftwareCatalogList(int tag, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams("tag", tag); ApiHttpClient.get("action/api/softwarecatalog_list", params, handler); } public static void getSoftwareTagList(int searchTag, int page, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("searchTag", searchTag); params.put("pageIndex", page); params.put("pageSize", AppContext.PAGE_SIZE); ApiHttpClient.get("action/api/softwaretag_list", params, handler); } /** * @param searchTag * 软件分类 推荐:recommend 最新:time 热门:view 国产:list_cn * @param page * @param handler */ public static void getSoftwareList(String searchTag, int page, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("searchTag", searchTag); params.put("pageIndex", page); params.put("pageSize", AppContext.PAGE_SIZE); ApiHttpClient.get("action/api/software_list", params, handler); } /** * 获取评论列表 * * @param id * @param catalog * 1新闻 2帖子 3动弹 4动态 * @param page * @param handler */ public static void getCommentList(int id, int catalog, int page, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("catalog", catalog); params.put("id", id); params.put("pageIndex", page); params.put("pageSize", AppContext.PAGE_SIZE); ApiHttpClient.get("action/api/comment_list", params, handler); } public static void getBlogCommentList(int id, int page, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("id", id); params.put("pageIndex", page); params.put("pageSize", AppContext.PAGE_SIZE); ApiHttpClient.get("action/api/blogcomment_list", params, handler); } public static void getUserInformation(int uid, int hisuid, String hisname, int pageIndex, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("uid", uid); params.put("hisuid", hisuid); params.put("hisname", hisname); params.put("pageIndex", pageIndex); params.put("pageSize", AppContext.PAGE_SIZE); ApiHttpClient.get("action/api/user_information", params, handler); } @SuppressWarnings("deprecation") public static void getUserBlogList(int authoruid, final String authorname, final int uid, final int pageIndex, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("authoruid", authoruid); params.put("authorname", URLEncoder.encode(authorname)); params.put("uid", uid); params.put("pageIndex", pageIndex); params.put("pageSize", AppContext.PAGE_SIZE); ApiHttpClient.get("action/api/userblog_list", params, handler); } public static void updateRelation(int uid, int hisuid, int newrelation, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("uid", uid); params.put("hisuid", hisuid); params.put("newrelation", newrelation); ApiHttpClient.post("action/api/user_updaterelation", params, handler); } public static void getMyInformation(int uid, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("uid", uid); ApiHttpClient.get("action/api/my_information", params, handler); } /** * 获取新闻明细 * * @param newsId * @param handler */ public static void getNewsDetail(int id, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams("id", id); ApiHttpClient.get("action/api/news_detail", params, handler); } public static void getBlogDetail(int id, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams("id", id); ApiHttpClient.get("action/api/blog_detail", params, handler); } /** * 获取软件详情 * * @param ident * @param handler */ public static void getSoftwareDetail(String ident, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams("ident", ident.replace(" ", "")); ApiHttpClient.get("action/api/software_detail", params, handler); } public static void getPostDetail(int id, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams("id", id); ApiHttpClient.get("action/api/post_detail", params, handler); } public static void getTweetDetail(int id, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams("id", id); ApiHttpClient.get("action/api/tweet_detail", params, handler); } /** * 用户针对某个新闻,帖子,动弹,消息发表评论的接口,参数使用POST方式提交 * * @param catalog * 1新闻 2 帖子 3 动弹 4消息中心 * @param id * 被评论的某条新闻,帖子,动弹或者某条消息的id * @param uid * 当天登陆用户的UID * @param content * 发表的评论内容 * @param isPostToMyZone * 是否转发到我的空间,0不转发 1转发到我的空间(注意该功能之对某条动弹进行评论是有效,其他情况下服务器借口可以忽略该参数) * @param handler */ public static void publicComment(int catalog, int id, int uid, String content, int isPostToMyZone, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("catalog", catalog); params.put("id", id); params.put("uid", uid); params.put("content", content); params.put("isPostToMyZone", isPostToMyZone); ApiHttpClient.post("action/api/comment_pub", params, handler); } public static void replyComment(int id, int catalog, int replyid, int authorid, int uid, String content, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("catalog", catalog); params.put("id", id); params.put("uid", uid); params.put("content", content); params.put("replyid", replyid); params.put("authorid", authorid); ApiHttpClient.post("action/api/comment_reply", params, handler); } public static void publicBlogComment(int blog, int uid, String content, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("blog", blog); params.put("uid", uid); params.put("content", content); ApiHttpClient.post("action/api/blogcomment_pub", params, handler); } public static void replyBlogComment(int blog, int uid, String content, int reply_id, int objuid, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("blog", blog); params.put("uid", uid); params.put("content", content); params.put("reply_id", reply_id); params.put("objuid", objuid); ApiHttpClient.post("action/api/blogcomment_pub", params, handler); } public static void pubTweet(Tweet tweet, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("uid", tweet.getAuthorid()); params.put("msg", tweet.getBody()); // Map<String, File> files = new HashMap<String, File>(); if (!TextUtils.isEmpty(tweet.getImageFilePath())) { try { params.put("img", new File(tweet.getImageFilePath())); } catch (FileNotFoundException e) { e.printStackTrace(); } } if (!TextUtils.isEmpty(tweet.getAudioPath())) { try { params.put("amr", new File(tweet.getAudioPath())); } catch (FileNotFoundException e) { e.printStackTrace(); } } ApiHttpClient.post("action/api/tweet_pub", params, handler); } public static void pubSoftWareTweet(Tweet tweet, int softid, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("uid", tweet.getAuthorid()); params.put("msg", tweet.getBody()); params.put("project", softid); ApiHttpClient.post("action/api/software_tweet_pub", params, handler); } public static void deleteTweet(int uid, int tweetid, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("uid", uid); params.put("tweetid", tweetid); ApiHttpClient.post("action/api/tweet_delete", params, handler); } public static void deleteComment(int id, int catalog, int replyid, int authorid, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("id", id); params.put("catalog", catalog); params.put("replyid", replyid); params.put("authorid", authorid); ApiHttpClient.post("action/api/comment_delete", params, handler); } public static void deleteBlog(int uid, int authoruid, int id, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("uid", uid); params.put("authoruid", authoruid); params.put("id", id); ApiHttpClient.post("action/api/userblog_delete", params, handler); } public static void deleteBlogComment(int uid, int blogid, int replyid, int authorid, int owneruid, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("uid", uid); params.put("blogid", blogid); params.put("replyid", replyid); params.put("authorid", authorid); params.put("owneruid", owneruid); ApiHttpClient.post("action/api/blogcomment_delete", params, handler); } /** * 用户添加收藏 * * @param uid * 用户UID * @param objid * 比如是新闻ID 或者问答ID 或者动弹ID * @param type * 1:软件 2:话题 3:博客 4:新闻 5:代码 */ public static void addFavorite(int uid, int objid, int type, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("uid", uid); params.put("objid", objid); params.put("type", type); ApiHttpClient.post("action/api/favorite_add", params, handler); } public static void delFavorite(int uid, int objid, int type, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("uid", uid); params.put("objid", objid); params.put("type", type); ApiHttpClient.post("action/api/favorite_delete", params, handler); } public static void getSearchList(String catalog, String content, int pageIndex, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("catalog", catalog); params.put("content", content); params.put("pageIndex", pageIndex); params.put("pageSize", AppContext.PAGE_SIZE); ApiHttpClient.get("action/api/search_list", params, handler); } public static void publicMessage(int uid, int receiver, String content, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("uid", uid); params.put("receiver", receiver); params.put("content", content); ApiHttpClient.post("action/api/message_pub", params, handler); } public static void deleteMessage(int uid, int friendid, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("uid", uid); params.put("friendid", friendid); ApiHttpClient.post("action/api/message_delete", params, handler); } public static void forwardMessage(int uid, String receiverName, String content, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("uid", uid); params.put("receiverName", receiverName); params.put("content", content); ApiHttpClient.post("action/api/message_pub", params, handler); } public static void getMessageList(int uid, int pageIndex, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("uid", uid); params.put("pageIndex", pageIndex); params.put("pageSize", AppContext.PAGE_SIZE); ApiHttpClient.get("action/api/message_list", params, handler); } public static void updatePortrait(int uid, File portrait, AsyncHttpResponseHandler handler) throws FileNotFoundException { RequestParams params = new RequestParams(); params.put("uid", uid); params.put("portrait", portrait); ApiHttpClient.post("action/api/portrait_update", params, handler); } public static void getNotices(AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("uid", AppContext.getInstance().getLoginUid()); ApiHttpClient.get("action/api/user_notice", params, handler); } /** * 清空通知消息 * * @param uid * @param type * 1:@我的信息 2:未读消息 3:评论个数 4:新粉丝个数 * @return * @throws AppException */ public static void clearNotice(int uid, int type, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("uid", uid); params.put("type", type); ApiHttpClient.post("action/api/notice_clear", params, handler); } public static void singnIn(String url, AsyncHttpResponseHandler handler) { ApiHttpClient.getDirect(url, handler); } /** * 获取软件的动态列表 * * @param softid * @param handler */ public static void getSoftTweetList(int softid, int page, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("project", softid); params.put("pageIndex", page); params.put("pageSize", AppContext.PAGE_SIZE); ApiHttpClient.get("action/api/software_tweet_list", params, handler); } public static void checkUpdate(AsyncHttpResponseHandler handler) { ApiHttpClient.get("MobileAppVersion.xml", handler); } /** * 查找用户 * * @param username * @param handler */ public static void findUser(String username, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("name", username); ApiHttpClient.get("action/api/find_user", params, handler); } /** * 获取活动列表 * * @param pageIndex * @param uid * <= 0 近期活动 实际的用户ID 则获取用户参与的活动列表,需要已登陆的用户 * @param handler */ public static void getEventList(int pageIndex, int uid, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("pageIndex", pageIndex); params.put("uid", uid); params.put("pageSize", AppContext.PAGE_SIZE); ApiHttpClient.get("action/api/event_list", params, handler); } /** * 获取某活动已出席的人员列表 * * @param eventId * @param pageIndex * @param handler */ public static void getEventApplies(int eventId, int pageIndex, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("pageIndex", pageIndex); params.put("event_id", eventId); params.put("pageSize", AppContext.PAGE_SIZE); ApiHttpClient.get("action/api/event_attend_user", params, handler); } /** * 举报 * * @param report * @param handler */ public static void report(Report report, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("obj_id", report.getReportId()); params.put("url", report.getLinkAddress()); params.put("obj_type", report.getReason()); if (report.getOtherReason() != null && !StringUtils.isEmpty(report.getOtherReason())) { params.put("memo", report.getOtherReason()); } else { params.put("memo", "其他原因"); } TLog.log("Test", report.getReportId() + "" + report.getLinkAddress() + report.getReason() + report.getOtherReason()); ApiHttpClient.post("action/communityManage/report", params, handler); } /** * 摇一摇,随机数据 * * @param handler */ public static void shake(AsyncHttpResponseHandler handler) { shake(-1, handler); } /** * 摇一摇指定请求类型 */ public static void shake(int type, AsyncHttpResponseHandler handler) { String inter = "action/api/rock_rock"; if (type > 0) { inter = (inter + "/?type=" + type); } ApiHttpClient.get(inter, handler); } /** * 活动报名 * * @param data * @param handler */ public static void eventApply(EventApplyData data, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("event", data.getEvent()); params.put("user", data.getUser()); params.put("name", data.getName()); params.put("gender", data.getGender()); params.put("mobile", data.getPhone()); params.put("company", data.getCompany()); params.put("job", data.getJob()); ApiHttpClient.post("action/api/event_apply", params, handler); } private static void uploadLog(String data, String report, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("app", "1"); params.put("report", report); params.put("msg", data); ApiHttpClient.post("action/api/user_report_to_admin", params, handler); } /** * BUG上报 * * @param data * @param handler */ public static void uploadLog(String data, AsyncHttpResponseHandler handler) { uploadLog(data, "1", handler); } /** * 反馈意见 * * @param data * @param handler */ public static void feedback(String data, AsyncHttpResponseHandler handler) { uploadLog(data, "2", handler); } /** * team动态 * * @param team * @param page * @param handler */ public static void teamDynamic(Team team, int page, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); // int uid = AppContext.getInstance().getLoginUid(); // params.put("uid", uid); params.put("teamid", team.getId()); params.put("pageIndex", page); params.put("pageSize", 20); params.put("type", "all"); ApiHttpClient.get("action/api/team_active_list", params, handler); } /** * 获取team列表 * * @param handler */ public static void teamList(AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("uid", AppContext.getInstance().getLoginUid()); ApiHttpClient.get("action/api/team_list", params, handler); } /** * 获取team成员列表 * * @param handler */ public static void getTeamMemberList(int teamid, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("teamid", teamid); ApiHttpClient.get("action/api/team_member_list", params, handler); } /** * 获取team成员个人信息 * * @param handler */ public static void getTeamUserInfo(String teamid, String uid, int pageIndex, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("teamid", teamid); params.put("uid", uid); params.put("pageIndex", pageIndex); params.put("pageSize", 20); ApiHttpClient.get("action/api/team_user_information", params, handler); } /** * 获取我的任务中进行中、未完成、已完成等状态的数量 */ public static void getMyIssueState(String teamid, String uid, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("teamid", teamid); params.put("uid", uid); ApiHttpClient.get("action/api/team_user_issue_information", params, handler); } /** * 获取指定用户的动态 */ public static void getUserDynamic(int teamid, String uid, int pageIndex, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("teamid", teamid); params.put("pageIndex", pageIndex); params.put("pageSize", 20); params.put("type", "git"); params.put("uid", uid); ApiHttpClient.get("action/api/team_active_list", params, handler); } /** * 动态详情 * * @param activeid * @param teamid * @param uid * @param handler */ public static void getDynamicDetail(int activeid, int teamid, int uid, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("teamid", teamid); params.put("uid", uid); params.put("activeid", activeid); ApiHttpClient.get("action/api/team_active_detail", params, handler); } /** * 获取指定用户的任务 */ public static void getMyIssue(String teamid, String uid, int pageIndex, String type, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("teamid", teamid); params.put("uid", uid); params.put("pageIndex", pageIndex); params.put("pageSize", 20); params.put("state", type); params.put("projectid", "-1"); ApiHttpClient.get("action/api/team_issue_list", params, handler); } /** * 获取指定周周报 * * @param teamid * @param year * @param week * @param handler */ public static void getDiaryFromWhichWeek(int teamid, int year, int week, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("teamid", teamid); params.put("year", year); params.put("week", week); ApiHttpClient.get("action/api/team_diary_list", params, handler); } /** * 删除一个便签 * * @param id * 便签id * @param uid * 用户id */ public static void deleteNoteBook(int id, int uid, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("uid", uid); params.put("id", id); // 便签id ApiHttpClient .get("action/api/team_stickynote_recycle", params, handler); } public static void getNoteBook(int uid, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("uid", uid); ApiHttpClient.get("action/api/team_sticky_list", params, handler); } /** * 获取指定周报的详细信息 * * @param teamid * @param diaryid * @param handler */ public static void getDiaryDetail(int teamid, int diaryid, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("teamid", teamid); params.put("diaryid", diaryid); ApiHttpClient.get("action/api/team_diary_detail", params, handler); } /** * diary评论列表 * * @param teamid * @param diaryid * @param handler */ public static void getDiaryComment(int teamid, int diaryid, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("teamid", teamid); params.put("id", diaryid); params.put("type", "diary"); params.put("pageIndex", 0); params.put("pageSize", "20"); KJLoger.debug(teamid + "==getDiaryComment接口=" + diaryid); ApiHttpClient .get("action/api/team_reply_list_by_type", params, handler); } /** * 周报评论(以后可改为全局评论) * * @param uid * @param teamid * @param diaryId * @param content * @param handler */ public static void sendComment(int uid, int teamid, int diaryId, String content, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("uid", uid); params.put("teamid", teamid); params.put("type", "118"); params.put("tweetid", diaryId); params.put("content", content); ApiHttpClient.post("action/api/team_tweet_reply", params, handler); } /*** * 客户端扫描二维码登陆 * * @author 火蚁 2015-3-13 上午11:45:47 * * @return void * @param url * @param handler */ public static void scanQrCodeLogin(String url, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); String uuid = url.substring(url.lastIndexOf("=") + 1); params.put("uuid", uuid); ApiHttpClient.getDirect(url, handler); } }
OSChinaTeamApi.java
package net.oschina.app.api.remote; import java.io.File; import java.io.FileNotFoundException; import net.oschina.app.AppContext; import net.oschina.app.api.ApiHttpClient; import net.oschina.app.team.bean.TeamIssue; import net.oschina.app.team.bean.TeamProject; import android.text.TextUtils; import com.loopj.android.http.AsyncHttpResponseHandler; import com.loopj.android.http.RequestParams; /** * osc team api集合类 * * @author FireAnt(http://my.oschina.net/LittleDY) * @version 创建时间:2015年1月14日 下午3:32:18 * */ public class OSChinaTeamApi { /** * 获取团队项目列表 * * @param teamId * @param handler */ public static void getTeamProjectList(int teamId, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("teamid", teamId); ApiHttpClient.get("action/api/team_project_list", params, handler); } /** * 获取team动态列表 * * @param teamId * @param activeId * @param pageIndex * @param handler */ public static void getTeamCommentList(int teamId, int activeId, int pageIndex, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("teamid", teamId); params.put("id", activeId); params.put("pageIndex", pageIndex); params.put("pageSize", 20); ApiHttpClient.get("action/api/team_reply_list_by_activeid", params, handler); } /*** * 获取团队绑定项目的成员列表(包括管理员以及开发者) * * @author 火蚁 2015-2-5 下午6:45:41 * * @return void * @param teamId * @param teamProject * @param handler */ public static void getTeamProjectMemberList(int teamId, TeamProject teamProject, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("teamid", teamId); params.put("uid", AppContext.getInstance().getLoginUid()); params.put("projectid", teamProject.getGit().getId()); String source = teamProject.getSource(); if (source != null && !TextUtils.isEmpty(source)) { params.put("source", teamProject.getSource()); } ApiHttpClient.get("action/api/team_project_member_list", params, handler); } /*** * 获取项目的动态列表 * * @author 火蚁 2015-3-2 下午5:18:54 * * @return void * @param teamId * @param project * @param type * "all"(default),"issue","code","other" * @param page * @param handler */ public static void getTeamProjectActiveList(int teamId, TeamProject project, String type, int page, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("teamid", teamId); params.put("projectid", project.getGit().getId()); if (!TextUtils.isEmpty(project.getSource())) { params.put("source", project.getSource()); } params.put("type", type); params.put("pageIndex", page); ApiHttpClient.get("action/api/team_project_active_list", params, handler); } /** * 获取某项目的任务列表 * * @param uId * 用户id * @param teamId * 团队id * @param projectId * 项目id(当<=0或不设置时,查询非项目的任务列表) * @param source * "Git@OSC","GitHub"(只有设置了projectid值,这里才需要设置该值) */ public static void getTeamCatalogIssueList(int uId, int teamId, int projectId, String source, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("uid", uId); params.put("teamid", teamId); params.put("projectid", projectId); params.put("source", source); ApiHttpClient.get("action/api/team_project_catalog_list", params, handler); } /** * 获取指定任务列表的任务列表 * * @param teamId * @param projectId * 项目id(-1获取非项目任务列表, 0获取所有任务列表) * @param catalogId * 任务列表的的目录id * @param source * "Team@OSC"(default),"Git@OSC","GitHub",如果指定了projectid的值, * 这个值就是必须的 * @param uid * 如果指定该值,则获取该id用户相关的任务 * @param state * "all"(default),"opened","closed","outdate" * @param scope * "tome"(default,指派给我的任务),"meto"(我指派的任务) * @param pageIndex * @param pageSize * @param handler */ public static void getTeamIssueList(int teamId, int projectId, int catalogId, String source, int uid, String state, String scope, int pageIndex, int pageSize, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("teamid", teamId); params.put("projectid", projectId); params.put("catalogid", catalogId); params.put("source", source); params.put("uid", uid); params.put("state", state); params.put("scope", scope); params.put("pageIndex", pageIndex); params.put("pageSize", pageSize); ApiHttpClient.get("action/api/team_issue_list", params, handler); } /*** * 改变一个任务的状态 * * @author 火蚁 2015-3-6 上午11:44:01 * * @return void * @param teamId * @param issue * @param target * 修改的属性("state" : 状态, "assignee" 指派人, "deadline" : 截止日期) * @param handler */ public static void changeIssueState(int teamId, TeamIssue issue, String target, AsyncHttpResponseHandler handler) { if (issue == null) return; RequestParams params = new RequestParams(); params.put("uid", AppContext.getInstance().getLoginUid()); params.put("teamid", teamId); params.put("target", target); params.put("issueid", issue.getId()); if (target.equals("state")) { params.put("state", issue.getState()); } else if (target.equals("assignee")) { params.put("assignee", issue.getToUser().getId()); } else if (target.equals("deadline")) { params.put("deadline", issue.getDeadlineTime()); } ApiHttpClient.post("action/api/team_issue_update", params, handler); } public static void pubTeamNewIssue(RequestParams params, AsyncHttpResponseHandler handler) { ApiHttpClient.post("action/api/team_issue_pub", params, handler); } /*** * 获取团队的讨论区列表 * * @param type * @param teamId * @param uid * @param pageIndex * @param handler */ public static void getTeamDiscussList(String type, int teamId, int uid, int pageIndex, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("type", type); params.put("teamid", teamId); params.put("uid", uid); params.put("pageIndex", pageIndex); params.put("pageSize", AppContext.PAGE_SIZE); ApiHttpClient.get("action/api/team_discuss_list", params, handler); } /*** * 获取讨论贴详情 * * @author 火蚁 2015-2-2 下午6:19:54 * * @return void * @param teamId * @param discussId * @param handler */ public static void getTeamDiscussDetail(int teamId, int discussId, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("teamid", teamId); params.put("discussid", discussId); ApiHttpClient.get("action/api/team_discuss_detail", params, handler); } /*** * 发表讨论贴评论 * * @author 火蚁 2015-2-3 下午2:42:54 * * @return void * @param uid * @param teamId * @param dicussId * @param content * @param handler */ public static void pubTeamDiscussReply(int uid, int teamId, int discussId, String content, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("uid", uid); params.put("teamid", teamId); params.put("discussid", discussId); params.put("content", content); ApiHttpClient.post("action/api/team_discuss_reply", params, handler); } /*** * 发表一条综合评论 动态、分享内容、周报 * * @author 火蚁 2015-3-6 下午3:31:07 * * @return void * @param teamId * @param type * 普通动态-110,分享内容-114, 周报-118 * @param tweetId * @param content * @param handler */ public static void pubTeamTweetReply(int teamId, int type, long tweetId, String content, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("uid", AppContext.getInstance().getLoginUid()); params.put("type", type); params.put("teamid", teamId); params.put("tweetid", tweetId); params.put("content", content); ApiHttpClient.post("action/api/team_tweet_reply", params, handler); } /*** * 获取团队任务详情 * * @author 火蚁 2015-1-27 下午7:47:17 * */ public static void getTeamIssueDetail(int teamId, int issueId, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("teamid", teamId); params.put("issueid", issueId); ApiHttpClient.get("action/api/team_issue_detail", params, handler); } /*** * 获取团队的周报列表 * * @param uid * @param teamId * @param year * @param week * @param pageIndex * @param handler */ public static void getTeamDiaryList(int uid, int teamId, int year, int week, int pageIndex, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("uid", uid); params.put("teamid", teamId); params.put("year", year); params.put("week", week); params.put("pageIndex", pageIndex); params.put("pageSize", AppContext.PAGE_SIZE); ApiHttpClient.get("action/api/team_diary_list", params, handler); } /*** * 任务、周报、讨论的回复列表 * * @author 火蚁 2015-2-2 上午11:39:04 * * @return void * @param teamId * @param id * @param type * 评论列表的类型(周报diary,讨论discuss,任务issue) * @param pageIndex * @param handler */ public static void getTeamReplyList(int teamId, int id, String type, int pageIndex, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("teamid", teamId); params.put("id", id); params.put("type", type); params.put("pageIndex", pageIndex); ApiHttpClient .get("action/api/team_reply_list_by_type", params, handler); } /*** * 发表一个新的团队动态 * * @author 火蚁 2015-3-9 下午2:46:13 * * @return void * @param teamId * @param content * @param img * @param handler */ public static void pubTeamNewActive(int teamId, String content, File img, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("teamid", teamId); params.put("uid", AppContext.getInstance().getLoginUid()); params.put("msg", content); params.put("appid", 3); if (img != null) { try { params.put("img", img); } catch (FileNotFoundException e) { e.printStackTrace(); } } ApiHttpClient.post("action/api/team_tweet_pub", params, handler); } /*** * 更新子任务属性 * * @author 火蚁 2015-3-10 下午4:53:49 * * @return void * @param teamId * @param target * @param childIssue * @param handler */ public static void updateChildIssue(int teamId, String target, TeamIssue childIssue, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("uid", AppContext.getInstance().getLoginUid()); params.put("teamid", teamId); params.put("childissueid", childIssue.getId()); params.put("target", target); if (target.equals("state")) { params.put("state", childIssue.getState()); } else { params.put("title", childIssue.getTitle()); } ApiHttpClient.post("action/api/team_issue_update_child_issue", params, handler); } /*** * 发表任务评论 * * @author 火蚁 2015-3-13 下午6:22:41 * * @return void * @param teamId * @param issueId * @param content * @param handler */ public static void pubTeamIssueReply(int teamId, int issueId, String content, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("uid", AppContext.getInstance().getLoginUid()); params.put("teamid", teamId); params.put("content", content); params.put("issueid", issueId); ApiHttpClient.post("action/api/team_issue_reply", params, handler); } }
Base.java
package net.oschina.app.bean; import java.io.Serializable; import com.thoughtworks.xstream.annotations.XStreamAlias; /** * 实体基类:实现序列化 * @author liux (http://my.oschina.net/liux) * @version 1.0 * @created 2012-3-21 */ @SuppressWarnings("serial") public abstract class Base implements Serializable { @XStreamAlias("notice") protected Notice notice; public Notice getNotice() { return notice; } public void setNotice(Notice notice) { this.notice = notice; } }
ListEntity.java
package net.oschina.app.bean; import java.io.Serializable; import java.util.List; public interface ListEntity<T extends Entity> extends Serializable { public List<T> getList(); }
Entity.java
package net.oschina.app.bean; import com.thoughtworks.xstream.annotations.XStreamAlias; /** * 实体类 * * @author liux (http://my.oschina.net/liux) * @version 1.0 * @created 2012-3-21 */ @SuppressWarnings("serial") public abstract class Entity extends Base { @XStreamAlias("id") protected int id; protected String cacheKey; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getCacheKey() { return cacheKey; } public void setCacheKey(String cacheKey) { this.cacheKey = cacheKey; } }
Active.java
package net.oschina.app.bean; import java.io.Serializable; import com.thoughtworks.xstream.annotations.XStreamAlias; /** * 动态实体类 * * @author FireAnt(http://my.oschina.net/LittleDY) * @created 2014年10月22日 下午3:22:09 * */ @SuppressWarnings("serial") @XStreamAlias("active") public class Active extends Entity { public final static int CATALOG_OTHER = 0;// 其他 public final static int CATALOG_NEWS = 1;// 新闻 public final static int CATALOG_POST = 2;// 帖子 public final static int CATALOG_TWEET = 3;// 动弹 public final static int CATALOG_BLOG = 4;// 博客 public final static int CLIENT_MOBILE = 2; public final static int CLIENT_ANDROID = 3; public final static int CLIENT_IPHONE = 4; public final static int CLIENT_WINDOWS_PHONE = 5; @XStreamAlias("portrait") private String portrait; @XStreamAlias("message") private String message; @XStreamAlias("author") private String author; @XStreamAlias("authorid") private int authorId; @XStreamAlias("activetype") private int activeType; @XStreamAlias("objectID") private int objectId; @XStreamAlias("catalog") private int catalog; @XStreamAlias("objecttype") private int objectType; @XStreamAlias("objectcatalog") private int objectCatalog; @XStreamAlias("objecttitle") private String objectTitle; @XStreamAlias("objectreply") private ObjectReply objectReply; @XStreamAlias("commentCount") private int commentCount; @XStreamAlias("pubDate") private String pubDate; @XStreamAlias("tweetimage") private String tweetimage; @XStreamAlias("tweetattach") private String tweetattach; @XStreamAlias("appclient") private int appClient; @XStreamAlias("url") private String url; public String getPortrait() { return portrait; } public void setPortrait(String portrait) { this.portrait = portrait; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } public String getAuthor() { return author; } public void setAuthor(String author) { this.author = author; } public int getAuthorId() { return authorId; } public void setAuthorId(int authorId) { this.authorId = authorId; } public int getActiveType() { return activeType; } public void setActiveType(int activeType) { this.activeType = activeType; } public int getObjectId() { return objectId; } public void setObjectId(int objectId) { this.objectId = objectId; } public int getCatalog() { return catalog; } public void setCatalog(int catalog) { this.catalog = catalog; } public int getObjectType() { return objectType; } public void setObjectType(int objectType) { this.objectType = objectType; } public int getObjectCatalog() { return objectCatalog; } public void setObjectCatalog(int objectCatalog) { this.objectCatalog = objectCatalog; } public String getObjectTitle() { return objectTitle; } public void setObjectTitle(String objectTitle) { this.objectTitle = objectTitle; } public ObjectReply getObjectReply() { return objectReply; } public void setObjectReply(ObjectReply objectReply) { this.objectReply = objectReply; } public int getCommentCount() { return commentCount; } public void setCommentCount(int commentCount) { this.commentCount = commentCount; } public String getPubDate() { return pubDate; } public void setPubDate(String pubDate) { this.pubDate = pubDate; } public String getTweetattach() { return tweetattach; } public void setTweetattach(String tweetattach) { this.tweetattach = tweetattach; } public String getTweetimage() { return tweetimage; } public void setTweetimage(String tweetimage) { this.tweetimage = tweetimage; } public int getAppClient() { return appClient; } public void setAppClient(int appClient) { this.appClient = appClient; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } @XStreamAlias("objectreply") public static class ObjectReply implements Serializable { @XStreamAlias("objectname") public String objectName; @XStreamAlias("objectbody") public String objectBody; public String getObjectName() { return objectName; } public void setObjectName(String objectName) { this.objectName = objectName; } public String getObjectBody() { return objectBody; } public void setObjectBody(String objectBody) { this.objectBody = objectBody; } } }
ActiveList.java
package net.oschina.app.bean; import java.util.ArrayList; import java.util.List; import com.thoughtworks.xstream.annotations.XStreamAlias; /** * 动态实体列表 * * @author FireAnt(http://my.oschina.net/LittleDY) * @created 2014年10月22日 下午3:34:21 * */ @SuppressWarnings("serial") @XStreamAlias("oschina") public class ActiveList extends Entity implements ListEntity<Active> { public final static int CATALOG_LASTEST = 1;// 最新 public final static int CATALOG_ATME = 2;// @我 public final static int CATALOG_COMMENT = 3;// 评论 public final static int CATALOG_MYSELF = 4;// 我自己 @XStreamAlias("pagesize") private int pageSize; @XStreamAlias("activeCount") private int activeCount; @XStreamAlias("activies") private List<Active> activelist = new ArrayList<Active>(); @XStreamAlias("result") private Result result; public int getPageSize() { return pageSize; } public int getActiveCount() { return activeCount; } public List<Active> getActivelist() { return activelist; } @Override public List<Active> getList() { return activelist; } public Result getResult() { return result; } public void setResult(Result result) { this.result = result; } }
Constants.java
package net.oschina.app.bean; /** * 常量类 * * @author FireAnt(http://my.oschina.net/LittleDY) * @version 创建时间:2014年10月27日 下午12:14:42 * */ public class Constants { public static final String INTENT_ACTION_USER_CHANGE = "net.oschina.action.USER_CHANGE"; public static final String INTENT_ACTION_COMMENT_CHANGED = "net.oschina.action.COMMENT_CHANGED"; public static final String INTENT_ACTION_NOTICE = "net.oschina.action.APPWIDGET_UPDATE"; public static final String INTENT_ACTION_LOGOUT = "net.oschina.action.LOGOUT"; public static final String WEICHAT_APPID = "wx41be5fe48092e94c"; public static final String WEICHAT_SECRET = "0101b0595ffe2042c214420fac358abc"; public static final String QQ_APPID = "100942993"; public static final String QQ_APPKEY = "8edd3cc7ca8dcc15082d6fe75969601b"; }
AlarmReceiver.java
package net.oschina.app.broadcast; import net.oschina.app.service.NoticeUtils; import net.oschina.app.util.TLog; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; public class AlarmReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { TLog.log("onReceive ->net.oschina.app收到定时获取消息"); NoticeUtils.requestNotice(context); } }
CacheManager.java
package net.oschina.app.cache; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InvalidClassException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import net.oschina.app.util.TDevice; import android.content.Context; public class CacheManager { // wifi缓存时间为5分钟 private static long wifi_cache_time = 5 * 60 * 1000; // 其他网络环境为1小时 private static long other_cache_time = 60 * 60 * 1000; /** * 保存对象 * * @param ser * @param file * @throws IOException */ public static boolean saveObject(Context context, Serializable ser, String file) { FileOutputStream fos = null; ObjectOutputStream oos = null; try { fos = context.openFileOutput(file, Context.MODE_PRIVATE); oos = new ObjectOutputStream(fos); oos.writeObject(ser); oos.flush(); return true; } catch (Exception e) { e.printStackTrace(); return false; } finally { try { oos.close(); } catch (Exception e) { } try { fos.close(); } catch (Exception e) { } } } /** * 读取对象 * * @param file * @return * @throws IOException */ public static Serializable readObject(Context context, String file) { if (!isExistDataCache(context, file)) return null; FileInputStream fis = null; ObjectInputStream ois = null; try { fis = context.openFileInput(file); ois = new ObjectInputStream(fis); return (Serializable) ois.readObject(); } catch (FileNotFoundException e) { } catch (Exception e) { e.printStackTrace(); // 反序列化失败 - 删除缓存文件 if (e instanceof InvalidClassException) { File data = context.getFileStreamPath(file); data.delete(); } } finally { try { ois.close(); } catch (Exception e) { } try { fis.close(); } catch (Exception e) { } } return null; } /** * 判断缓存是否存在 * * @param cachefile * @return */ public static boolean isExistDataCache(Context context, String cachefile) { if (context == null) return false; boolean exist = false; File data = context.getFileStreamPath(cachefile); if (data.exists()) exist = true; return exist; } /** * 判断缓存是否已经失效 */ public static boolean isCacheDataFailure(Context context, String cachefile) { File data = context.getFileStreamPath(cachefile); if (!data.exists()) { return false; } long existTime = System.currentTimeMillis() - data.lastModified(); boolean failure = false; if (TDevice.getNetworkType() == TDevice.NETTYPE_WIFI) { failure = existTime > wifi_cache_time ? true : false; } else { failure = existTime > other_cache_time ? true : false; } return failure; } }
DataCleanManager.java
package net.oschina.app.cache; import java.io.File; import android.content.Context; import android.os.Environment; /** * 数据删除工具类 * @author FireAnt(http://my.oschina.net/LittleDY) * @version 创建时间:2014年10月27日 上午10:18:22 * */ public class DataCleanManager { /** * 清除本应用内部缓存 * (/data/data/com.xxx.xxx/cache) * @param context */ public static void cleanInternalCache(Context context) { deleteFilesByDirectory(context.getCacheDir()); deleteFilesByDirectory(context.getFilesDir()); } /** * 清楚本应用所有数据库 * (/data/data/com.xxx.xxx/databases) * @param context */ public static void cleanDatabases(Context context) { deleteFilesByDirectory(new File("/data/data/" + context.getPackageName() + "/databases")); } /** * 清除本应用SharedPreference * (/data/data/com.xxx.xxx/shared_prefs) * @param context */ public static void cleanSharedPreference(Context context) { deleteFilesByDirectory(new File("/data/data/" + context.getPackageName() + "/shared_prefs")); } /** * 按名字清除本应用数据库 * @param context * @param dbName */ public static void cleanDatabaseByName(Context context, String dbName) { context.deleteDatabase(dbName); } /** * 清除/data/data/com.xxx.xxx/files下的内容 * @param context */ public static void cleanFiles(Context context) { deleteFilesByDirectory(context.getFilesDir()); } /** * 清除外部cache下的内容(/mnt/sdcard/android/data/com.xxx.xxx/cache) * @param context */ public static void cleanExternalCache(Context context) { if (Environment.getExternalStorageState().equals( Environment.MEDIA_MOUNTED)) { deleteFilesByDirectory(context.getExternalCacheDir()); } } /** * 清除自定义路径下的文件,使用需小心,请不要误删。而且只支持目录下的文件删除 * @param filePath */ public static void cleanCustomCache(String filePath) { deleteFilesByDirectory(new File(filePath)); } /** * 清除自定义路径下的文件,使用需小心,请不要误删。而且只支持目录下的文件删除 * @param filePath */ public static void cleanCustomCache(File file) { deleteFilesByDirectory(file); } /** * 清除本应用所有的数据 * @param context * @param filepath */ public static void cleanApplicationData(Context context, String... filepath) { cleanInternalCache(context); cleanExternalCache(context); cleanDatabases(context); cleanSharedPreference(context); cleanFiles(context); for (String filePath : filepath) { cleanCustomCache(filePath); } } /** * 删除方法 这里只会删除某个文件夹下的文件,如果传入的directory是个文件,将不做处理 * @param directory */ private static void deleteFilesByDirectory(File directory) { if (directory != null && directory.exists() && directory.isDirectory()) { for (File child : directory.listFiles()) { if (child.isDirectory()) { deleteFilesByDirectory(child); } child.delete(); } } } }
DiskLruCache.java
/* * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package net.oschina.app.cache; import java.io.BufferedInputStream; import java.io.BufferedWriter; import java.io.Closeable; import java.io.EOFException; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.FileWriter; import java.io.FilterOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.Reader; import java.io.StringWriter; import java.io.Writer; import java.lang.reflect.Array; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.Map; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; /** ****************************************************************************** * Taken from the JB source code, can be found in: * libcore/luni/src/main/java/libcore/io/DiskLruCache.java * or direct link: * https://android.googlesource.com/platform/libcore/+/android-4.1.1_r1/luni/src/main/java/libcore/io/DiskLruCache.java ****************************************************************************** * * A cache that uses a bounded amount of space on a filesystem. Each cache * entry has a string key and a fixed number of values. Values are byte * sequences, accessible as streams or files. Each value must be between {@code * 0} and {@code Integer.MAX_VALUE} bytes in length. * * <p>The cache stores its data in a directory on the filesystem. This * directory must be exclusive to the cache; the cache may delete or overwrite * files from its directory. It is an error for multiple processes to use the * same cache directory at the same time. * * <p>This cache limits the number of bytes that it will store on the * filesystem. When the number of stored bytes exceeds the limit, the cache will * remove entries in the background until the limit is satisfied. The limit is * not strict: the cache may temporarily exceed it while waiting for files to be * deleted. The limit does not include filesystem overhead or the cache * journal so space-sensitive applications should set a conservative limit. * * <p>Clients call {@link #edit} to create or update the values of an entry. An * entry may have only one editor at one time; if a value is not available to be * edited then {@link #edit} will return null. * <ul> * <li>When an entry is being <strong>created</strong> it is necessary to * supply a full set of values; the empty value should be used as a * placeholder if necessary. * <li>When an entry is being <strong>edited</strong>, it is not necessary * to supply data for every value; values default to their previous * value. * </ul> * Every {@link #edit} call must be matched by a call to {@link Editor#commit} * or {@link Editor#abort}. Committing is atomic: a read observes the full set * of values as they were before or after the commit, but never a mix of values. * * <p>Clients call {@link #get} to read a snapshot of an entry. The read will * observe the value at the time that {@link #get} was called. Updates and * removals after the call do not impact ongoing reads. * * <p>This class is tolerant of some I/O errors. If files are missing from the * filesystem, the corresponding entries will be dropped from the cache. If * an error occurs while writing a cache value, the edit will fail silently. * Callers should handle other problems by catching {@code IOException} and * responding appropriately. */ public final class DiskLruCache implements Closeable { static final String JOURNAL_FILE = "journal"; static final String JOURNAL_FILE_TMP = "journal.tmp"; static final String MAGIC = "libcore.io.DiskLruCache"; static final String VERSION_1 = "1"; static final long ANY_SEQUENCE_NUMBER = -1; private static final String CLEAN = "CLEAN"; private static final String DIRTY = "DIRTY"; private static final String REMOVE = "REMOVE"; private static final String READ = "READ"; private static final Charset UTF_8 = Charset.forName("UTF-8"); private static final int IO_BUFFER_SIZE = 8 * 1024; /* * This cache uses a journal file named "journal". A typical journal file * looks like this: * libcore.io.DiskLruCache * 1 * 100 * 2 * * CLEAN 3400330d1dfc7f3f7f4b8d4d803dfcf6 832 21054 * DIRTY 335c4c6028171cfddfbaae1a9c313c52 * CLEAN 335c4c6028171cfddfbaae1a9c313c52 3934 2342 * REMOVE 335c4c6028171cfddfbaae1a9c313c52 * DIRTY 1ab96a171faeeee38496d8b330771a7a * CLEAN 1ab96a171faeeee38496d8b330771a7a 1600 234 * READ 335c4c6028171cfddfbaae1a9c313c52 * READ 3400330d1dfc7f3f7f4b8d4d803dfcf6 * * The first five lines of the journal form its header. They are the * constant string "libcore.io.DiskLruCache", the disk cache's version, * the application's version, the value count, and a blank line. * * Each of the subsequent lines in the file is a record of the state of a * cache entry. Each line contains space-separated values: a state, a key, * and optional state-specific values. * o DIRTY lines track that an entry is actively being created or updated. * Every successful DIRTY action should be followed by a CLEAN or REMOVE * action. DIRTY lines without a matching CLEAN or REMOVE indicate that * temporary files may need to be deleted. * o CLEAN lines track a cache entry that has been successfully published * and may be read. A publish line is followed by the lengths of each of * its values. * o READ lines track accesses for LRU. * o REMOVE lines track entries that have been deleted. * * The journal file is appended to as cache operations occur. The journal may * occasionally be compacted by dropping redundant lines. A temporary file named * "journal.tmp" will be used during compaction; that file should be deleted if * it exists when the cache is opened. */ private final File directory; private final File journalFile; private final File journalFileTmp; private final int appVersion; private final long maxSize; private final int valueCount; private long size = 0; private Writer journalWriter; private final LinkedHashMap<String, Entry> lruEntries = new LinkedHashMap<String, Entry>(0, 0.75f, true); private int redundantOpCount; /** * To differentiate between old and current snapshots, each entry is given * a sequence number each time an edit is committed. A snapshot is stale if * its sequence number is not equal to its entry's sequence number. */ private long nextSequenceNumber = 0; /* From java.util.Arrays */ @SuppressWarnings("unchecked") private static <T> T[] copyOfRange(T[] original, int start, int end) { final int originalLength = original.length; // For exception priority compatibility. if (start > end) { throw new IllegalArgumentException(); } if (start < 0 || start > originalLength) { throw new ArrayIndexOutOfBoundsException(); } final int resultLength = end - start; final int copyLength = Math.min(resultLength, originalLength - start); final T[] result = (T[]) Array .newInstance(original.getClass().getComponentType(), resultLength); System.arraycopy(original, start, result, 0, copyLength); return result; } /** * Returns the remainder of 'reader' as a string, closing it when done. */ public static String readFully(Reader reader) throws IOException { try { StringWriter writer = new StringWriter(); char[] buffer = new char[1024]; int count; while ((count = reader.read(buffer)) != -1) { writer.write(buffer, 0, count); } return writer.toString(); } finally { reader.close(); } } /** * Returns the ASCII characters up to but not including the next "\r\n", or * "\n". * * @throws java.io.EOFException if the stream is exhausted before the next newline * character. */ public static String readAsciiLine(InputStream in) throws IOException { // TODO: support UTF-8 here instead StringBuilder result = new StringBuilder(80); while (true) { int c = in.read(); if (c == -1) { throw new EOFException(); } else if (c == '\n') { break; } result.append((char) c); } int length = result.length(); if (length > 0 && result.charAt(length - 1) == '\r') { result.setLength(length - 1); } return result.toString(); } /** * Closes 'closeable', ignoring any checked exceptions. Does nothing if 'closeable' is null. */ public static void closeQuietly(Closeable closeable) { if (closeable != null) { try { closeable.close(); } catch (RuntimeException rethrown) { throw rethrown; } catch (Exception ignored) { } } } /** * Recursively delete everything in {@code dir}. */ // TODO: this should specify paths as Strings rather than as Files public static void deleteContents(File dir) throws IOException { File[] files = dir.listFiles(); if (files == null) { throw new IllegalArgumentException("not a directory: " + dir); } for (File file : files) { if (file.isDirectory()) { deleteContents(file); } if (!file.delete()) { throw new IOException("failed to delete file: " + file); } } } /** This cache uses a single background thread to evict entries. */ private final ExecutorService executorService = new ThreadPoolExecutor(0, 1, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>()); private final Callable<Void> cleanupCallable = new Callable<Void>() { @Override public Void call() throws Exception { synchronized (DiskLruCache.this) { if (journalWriter == null) { return null; // closed } trimToSize(); if (journalRebuildRequired()) { rebuildJournal(); redundantOpCount = 0; } } return null; } }; private DiskLruCache(File directory, int appVersion, int valueCount, long maxSize) { this.directory = directory; this.appVersion = appVersion; this.journalFile = new File(directory, JOURNAL_FILE); this.journalFileTmp = new File(directory, JOURNAL_FILE_TMP); this.valueCount = valueCount; this.maxSize = maxSize; } /** * Opens the cache in {@code directory}, creating a cache if none exists * there. * * @param directory a writable directory * @param appVersion * @param valueCount the number of values per cache entry. Must be positive. * @param maxSize the maximum number of bytes this cache should use to store * @throws java.io.IOException if reading or writing the cache directory fails */ public static DiskLruCache open(File directory, int appVersion, int valueCount, long maxSize) throws IOException { if (maxSize <= 0) { throw new IllegalArgumentException("maxSize <= 0"); } if (valueCount <= 0) { throw new IllegalArgumentException("valueCount <= 0"); } // prefer to pick up where we left off DiskLruCache cache = new DiskLruCache(directory, appVersion, valueCount, maxSize); if (cache.journalFile.exists()) { try { cache.readJournal(); cache.processJournal(); cache.journalWriter = new BufferedWriter(new FileWriter(cache.journalFile, true), IO_BUFFER_SIZE); return cache; } catch (IOException journalIsCorrupt) { // System.logW("DiskLruCache " + directory + " is corrupt: " // + journalIsCorrupt.getMessage() + ", removing"); cache.delete(); } } // create a new empty cache directory.mkdirs(); cache = new DiskLruCache(directory, appVersion, valueCount, maxSize); cache.rebuildJournal(); return cache; } private void readJournal() throws IOException { InputStream in = new BufferedInputStream(new FileInputStream(journalFile), IO_BUFFER_SIZE); try { String magic = readAsciiLine(in); String version = readAsciiLine(in); String appVersionString = readAsciiLine(in); String valueCountString = readAsciiLine(in); String blank = readAsciiLine(in); if (!MAGIC.equals(magic) || !VERSION_1.equals(version) || !Integer.toString(appVersion).equals(appVersionString) || !Integer.toString(valueCount).equals(valueCountString) || !"".equals(blank)) { throw new IOException("unexpected journal header: [" + magic + ", " + version + ", " + valueCountString + ", " + blank + "]"); } while (true) { try { readJournalLine(readAsciiLine(in)); } catch (EOFException endOfJournal) { break; } } } finally { closeQuietly(in); } } private void readJournalLine(String line) throws IOException { String[] parts = line.split(" "); if (parts.length < 2) { throw new IOException("unexpected journal line: " + line); } String key = parts[1]; if (parts[0].equals(REMOVE) && parts.length == 2) { lruEntries.remove(key); return; } Entry entry = lruEntries.get(key); if (entry == null) { entry = new Entry(key); lruEntries.put(key, entry); } if (parts[0].equals(CLEAN) && parts.length == 2 + valueCount) { entry.readable = true; entry.currentEditor = null; entry.setLengths(copyOfRange(parts, 2, parts.length)); } else if (parts[0].equals(DIRTY) && parts.length == 2) { entry.currentEditor = new Editor(entry); } else if (parts[0].equals(READ) && parts.length == 2) { // this work was already done by calling lruEntries.get() } else { throw new IOException("unexpected journal line: " + line); } } /** * Computes the initial size and collects garbage as a part of opening the * cache. Dirty entries are assumed to be inconsistent and will be deleted. */ private void processJournal() throws IOException { deleteIfExists(journalFileTmp); for (Iterator<Entry> i = lruEntries.values().iterator(); i.hasNext(); ) { Entry entry = i.next(); if (entry.currentEditor == null) { for (int t = 0; t < valueCount; t++) { size += entry.lengths[t]; } } else { entry.currentEditor = null; for (int t = 0; t < valueCount; t++) { deleteIfExists(entry.getCleanFile(t)); deleteIfExists(entry.getDirtyFile(t)); } i.remove(); } } } /** * Creates a new journal that omits redundant information. This replaces the * current journal if it exists. */ private synchronized void rebuildJournal() throws IOException { if (journalWriter != null) { journalWriter.close(); } Writer writer = new BufferedWriter(new FileWriter(journalFileTmp), IO_BUFFER_SIZE); writer.write(MAGIC); writer.write("\n"); writer.write(VERSION_1); writer.write("\n"); writer.write(Integer.toString(appVersion)); writer.write("\n"); writer.write(Integer.toString(valueCount)); writer.write("\n"); writer.write("\n"); for (Entry entry : lruEntries.values()) { if (entry.currentEditor != null) { writer.write(DIRTY + ' ' + entry.key + '\n'); } else { writer.write(CLEAN + ' ' + entry.key + entry.getLengths() + '\n'); } } writer.close(); journalFileTmp.renameTo(journalFile); journalWriter = new BufferedWriter(new FileWriter(journalFile, true), IO_BUFFER_SIZE); } private static void deleteIfExists(File file) throws IOException { // try { // Libcore.os.remove(file.getPath()); // } catch (ErrnoException errnoException) { // if (errnoException.errno != OsConstants.ENOENT) { // throw errnoException.rethrowAsIOException(); // } // } if (file.exists() && !file.delete()) { throw new IOException(); } } /** * Returns a snapshot of the entry named {@code key}, or null if it doesn't * exist is not currently readable. If a value is returned, it is moved to * the head of the LRU queue. */ public synchronized Snapshot get(String key) throws IOException { checkNotClosed(); validateKey(key); Entry entry = lruEntries.get(key); if (entry == null) { return null; } if (!entry.readable) { return null; } /* * Open all streams eagerly to guarantee that we see a single published * snapshot. If we opened streams lazily then the streams could come * from different edits. */ InputStream[] ins = new InputStream[valueCount]; try { for (int i = 0; i < valueCount; i++) { ins[i] = new FileInputStream(entry.getCleanFile(i)); } } catch (FileNotFoundException e) { // a file must have been deleted manually! return null; } redundantOpCount++; journalWriter.append(READ + ' ' + key + '\n'); if (journalRebuildRequired()) { executorService.submit(cleanupCallable); } return new Snapshot(key, entry.sequenceNumber, ins); } /** * Returns an editor for the entry named {@code key}, or null if another * edit is in progress. */ public Editor edit(String key) throws IOException { return edit(key, ANY_SEQUENCE_NUMBER); } private synchronized Editor edit(String key, long expectedSequenceNumber) throws IOException { checkNotClosed(); validateKey(key); Entry entry = lruEntries.get(key); if (expectedSequenceNumber != ANY_SEQUENCE_NUMBER && (entry == null || entry.sequenceNumber != expectedSequenceNumber)) { return null; // snapshot is stale } if (entry == null) { entry = new Entry(key); lruEntries.put(key, entry); } else if (entry.currentEditor != null) { return null; // another edit is in progress } Editor editor = new Editor(entry); entry.currentEditor = editor; // flush the journal before creating files to prevent file leaks journalWriter.write(DIRTY + ' ' + key + '\n'); journalWriter.flush(); return editor; } /** * Returns the directory where this cache stores its data. */ public File getDirectory() { return directory; } /** * Returns the maximum number of bytes that this cache should use to store * its data. */ public long maxSize() { return maxSize; } /** * Returns the number of bytes currently being used to store the values in * this cache. This may be greater than the max size if a background * deletion is pending. */ public synchronized long size() { return size; } private synchronized void completeEdit(Editor editor, boolean success) throws IOException { Entry entry = editor.entry; if (entry.currentEditor != editor) { throw new IllegalStateException(); } // if this edit is creating the entry for the first time, every index must have a value if (success && !entry.readable) { for (int i = 0; i < valueCount; i++) { if (!entry.getDirtyFile(i).exists()) { editor.abort(); throw new IllegalStateException("edit didn't create file " + i); } } } for (int i = 0; i < valueCount; i++) { File dirty = entry.getDirtyFile(i); if (success) { if (dirty.exists()) { File clean = entry.getCleanFile(i); dirty.renameTo(clean); long oldLength = entry.lengths[i]; long newLength = clean.length(); entry.lengths[i] = newLength; size = size - oldLength + newLength; } } else { deleteIfExists(dirty); } } redundantOpCount++; entry.currentEditor = null; if (entry.readable | success) { entry.readable = true; journalWriter.write(CLEAN + ' ' + entry.key + entry.getLengths() + '\n'); if (success) { entry.sequenceNumber = nextSequenceNumber++; } } else { lruEntries.remove(entry.key); journalWriter.write(REMOVE + ' ' + entry.key + '\n'); } if (size > maxSize || journalRebuildRequired()) { executorService.submit(cleanupCallable); } } /** * We only rebuild the journal when it will halve the size of the journal * and eliminate at least 2000 ops. */ private boolean journalRebuildRequired() { final int REDUNDANT_OP_COMPACT_THRESHOLD = 2000; return redundantOpCount >= REDUNDANT_OP_COMPACT_THRESHOLD && redundantOpCount >= lruEntries.size(); } /** * Drops the entry for {@code key} if it exists and can be removed. Entries * actively being edited cannot be removed. * * @return true if an entry was removed. */ public synchronized boolean remove(String key) throws IOException { checkNotClosed(); validateKey(key); Entry entry = lruEntries.get(key); if (entry == null || entry.currentEditor != null) { return false; } for (int i = 0; i < valueCount; i++) { File file = entry.getCleanFile(i); if (!file.delete()) { throw new IOException("failed to delete " + file); } size -= entry.lengths[i]; entry.lengths[i] = 0; } redundantOpCount++; journalWriter.append(REMOVE + ' ' + key + '\n'); lruEntries.remove(key); if (journalRebuildRequired()) { executorService.submit(cleanupCallable); } return true; } /** * Returns true if this cache has been closed. */ public boolean isClosed() { return journalWriter == null; } private void checkNotClosed() { if (journalWriter == null) { throw new IllegalStateException("cache is closed"); } } /** * Force buffered operations to the filesystem. */ public synchronized void flush() throws IOException { checkNotClosed(); trimToSize(); journalWriter.flush(); } /** * Closes this cache. Stored values will remain on the filesystem. */ public synchronized void close() throws IOException { if (journalWriter == null) { return; // already closed } for (Entry entry : new ArrayList<Entry>(lruEntries.values())) { if (entry.currentEditor != null) { entry.currentEditor.abort(); } } trimToSize(); journalWriter.close(); journalWriter = null; } private void trimToSize() throws IOException { while (size > maxSize) { // Map.Entry<String, Entry> toEvict = lruEntries.eldest(); final Map.Entry<String, Entry> toEvict = lruEntries.entrySet().iterator().next(); remove(toEvict.getKey()); } } /** * Closes the cache and deletes all of its stored values. This will delete * all files in the cache directory including files that weren't created by * the cache. */ public void delete() throws IOException { close(); deleteContents(directory); } private void validateKey(String key) { if (key.contains(" ") || key.contains("\n") || key.contains("\r")) { throw new IllegalArgumentException( "keys must not contain spaces or newlines: \"" + key + "\""); } } private static String inputStreamToString(InputStream in) throws IOException { return readFully(new InputStreamReader(in, UTF_8)); } /** * A snapshot of the values for an entry. */ public final class Snapshot implements Closeable { private final String key; private final long sequenceNumber; private final InputStream[] ins; private Snapshot(String key, long sequenceNumber, InputStream[] ins) { this.key = key; this.sequenceNumber = sequenceNumber; this.ins = ins; } /** * Returns an editor for this snapshot's entry, or null if either the * entry has changed since this snapshot was created or if another edit * is in progress. */ public Editor edit() throws IOException { return DiskLruCache.this.edit(key, sequenceNumber); } /** * Returns the unbuffered stream with the value for {@code index}. */ public InputStream getInputStream(int index) { return ins[index]; } /** * Returns the string value for {@code index}. */ public String getString(int index) throws IOException { return inputStreamToString(getInputStream(index)); } @Override public void close() { for (InputStream in : ins) { closeQuietly(in); } } } /** * Edits the values for an entry. */ public final class Editor { private final Entry entry; private boolean hasErrors; private Editor(Entry entry) { this.entry = entry; } /** * Returns an unbuffered input stream to read the last committed value, * or null if no value has been committed. */ public InputStream newInputStream(int index) throws IOException { synchronized (DiskLruCache.this) { if (entry.currentEditor != this) { throw new IllegalStateException(); } if (!entry.readable) { return null; } return new FileInputStream(entry.getCleanFile(index)); } } /** * Returns the last committed value as a string, or null if no value * has been committed. */ public String getString(int index) throws IOException { InputStream in = newInputStream(index); return in != null ? inputStreamToString(in) : null; } /** * Returns a new unbuffered output stream to write the value at * {@code index}. If the underlying output stream encounters errors * when writing to the filesystem, this edit will be aborted when * {@link #commit} is called. The returned output stream does not throw * IOExceptions. */ public OutputStream newOutputStream(int index) throws IOException { synchronized (DiskLruCache.this) { if (entry.currentEditor != this) { throw new IllegalStateException(); } return new FaultHidingOutputStream(new FileOutputStream(entry.getDirtyFile(index))); } } /** * Sets the value at {@code index} to {@code value}. */ public void set(int index, String value) throws IOException { Writer writer = null; try { writer = new OutputStreamWriter(newOutputStream(index), UTF_8); writer.write(value); } finally { closeQuietly(writer); } } /** * Commits this edit so it is visible to readers. This releases the * edit lock so another edit may be started on the same key. */ public void commit() throws IOException { if (hasErrors) { completeEdit(this, false); remove(entry.key); // the previous entry is stale } else { completeEdit(this, true); } } /** * Aborts this edit. This releases the edit lock so another edit may be * started on the same key. */ public void abort() throws IOException { completeEdit(this, false); } private class FaultHidingOutputStream extends FilterOutputStream { private FaultHidingOutputStream(OutputStream out) { super(out); } @Override public void write(int oneByte) { try { out.write(oneByte); } catch (IOException e) { hasErrors = true; } } @Override public void write(byte[] buffer, int offset, int length) { try { out.write(buffer, offset, length); } catch (IOException e) { hasErrors = true; } } @Override public void close() { try { out.close(); } catch (IOException e) { hasErrors = true; } } @Override public void flush() { try { out.flush(); } catch (IOException e) { hasErrors = true; } } } } private final class Entry { private final String key; /** Lengths of this entry's files. */ private final long[] lengths; /** True if this entry has ever been published */ private boolean readable; /** The ongoing edit or null if this entry is not being edited. */ private Editor currentEditor; /** The sequence number of the most recently committed edit to this entry. */ private long sequenceNumber; private Entry(String key) { this.key = key; this.lengths = new long[valueCount]; } public String getLengths() throws IOException { StringBuilder result = new StringBuilder(); for (long size : lengths) { result.append(' ').append(size); } return result.toString(); } /** * Set lengths using decimal numbers like "10123". */ private void setLengths(String[] strings) throws IOException { if (strings.length != valueCount) { throw invalidLengths(strings); } try { for (int i = 0; i < strings.length; i++) { lengths[i] = Long.parseLong(strings[i]); } } catch (NumberFormatException e) { throw invalidLengths(strings); } } private IOException invalidLengths(String[] strings) throws IOException { throw new IOException("unexpected journal line: " + Arrays.toString(strings)); } public File getCleanFile(int i) { return new File(directory, key + "." + i); } public File getDirtyFile(int i) { return new File(directory, key + "." + i + ".tmp"); } } }
DiskLruCacheUtil.java
package net.oschina.app.cache; import java.io.File; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import net.oschina.app.util.TDevice; import org.kymjs.kjframe.utils.FileUtils; import android.content.Context; import android.os.Environment; /** * 缓存工具类 * * @author FireAnt(http://my.oschina.net/LittleDY) * @version 创建时间:2014年12月26日 下午4:53:13 * */ public class DiskLruCacheUtil { private static int appVersion = TDevice.getVersionCode(); private static int valueCount = 1;// 同一个key可以对应多少个缓存文件 private static int maxSize = 10 * 1024 * 1024;// 一个缓存文件最大可以缓存10M public static final String CACHE_OBJECT = "object";// 对象缓存目录 /** * 保存对象缓存 * * @param context * @param ser * @param key */ public static void saveObject(Context context, Serializable ser, String key) { ObjectOutputStream oos = null; try { DiskLruCache.Editor editor = getDiskLruCacheOutputStream(context, CACHE_OBJECT, key); if (editor != null) { oos = new ObjectOutputStream(editor.newOutputStream(0)); oos.writeObject(ser); oos.flush(); editor.commit(); } } catch (IOException e) { e.printStackTrace(); } finally { FileUtils.closeIO(oos); } } /** * 读取对象缓存 * * @param context * @param key * @return */ public static Serializable readObject(Context context, String key) { ObjectInputStream ois = null; try { DiskLruCache.Editor editor = getDiskLruCacheOutputStream(context, CACHE_OBJECT, key); ois = new ObjectInputStream(editor.newInputStream(0)); return (Serializable) ois.readObject(); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } finally { FileUtils.closeIO(ois); } return null; } /** * 获取DiskLruCache的editor * * @param context * @param key * @return * @throws IOException */ public static DiskLruCache.Editor getDiskLruCacheOutputStream( Context context, String uniqueName, String key) throws IOException { DiskLruCache mDiskLruCache = DiskLruCache.open( getDiskCacheDir(context, uniqueName), appVersion, valueCount, maxSize); DiskLruCache.Editor editor = mDiskLruCache.edit(hashKeyForDisk(key)); return editor; } /** * 获取相应的缓存目录 * * @param context * @param uniqueName * @return */ public static File getDiskCacheDir(Context context, String uniqueName) { String cachePath; if (Environment.MEDIA_MOUNTED.equals(Environment .getExternalStorageState()) || !Environment.isExternalStorageRemovable()) { cachePath = context.getExternalCacheDir().getPath(); } else { cachePath = context.getCacheDir().getPath(); } return new File(cachePath + File.separator + uniqueName); } /** * 传入缓存的key值,以得到相应的MD5值 * * @param key * @return */ public static String hashKeyForDisk(String key) { String cacheKey; try { final MessageDigest mDigest = MessageDigest.getInstance("MD5"); mDigest.update(key.getBytes()); cacheKey = bytesToHexString(mDigest.digest()); } catch (NoSuchAlgorithmException e) { cacheKey = String.valueOf(key.hashCode()); } return cacheKey; } private static String bytesToHexString(byte[] bytes) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < bytes.length; i++) { String hex = Integer.toHexString(0xFF & bytes[i]); if (hex.length() == 1) { sb.append('0'); } sb.append(hex); } return sb.toString(); } }
DatabaseHelper.java
package net.oschina.app.db; import android.content.Context; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; /** * 创建便签的数据库 * * @author kymjs * * update:2014-01-12 updateor: fireant 内容:修改为全应用数据库 * */ public class DatabaseHelper extends SQLiteOpenHelper { public static final String OSC_DATABASE_NAME = "oschina"; public static final String NOTE_TABLE_NAME = "osc_Notebook"; public static final String CREATE_NOTE_TABLE = "create table " + NOTE_TABLE_NAME + " (_id integer primary key autoincrement, iid integer," + " time varchar(10), date varchar(10), content text, color integer)"; public static final String NEWS_LIST = "osc_news_list"; public static final String CREATE_NEWS_LIST_TABLE = "create table " + NOTE_TABLE_NAME + "(" + "_id integer primary key autoincrement, " + "news_id interger, title varchar(10), " + ")"; public DatabaseHelper(Context context) { super(context, OSC_DATABASE_NAME, null, 1); } @Override public void onCreate(SQLiteDatabase db) { db.execSQL(CREATE_NOTE_TABLE); // db.execSQL(CREATE_NEWS_LIST_TABLE); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {} }
NoteDatabase.java
package net.oschina.app.db; import java.util.ArrayList; import java.util.List; import net.oschina.app.bean.NotebookData; import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; public class NoteDatabase { private final DatabaseHelper dbHelper; public NoteDatabase(Context context) { super(); dbHelper = new DatabaseHelper(context); } /** * 增 * * @param data */ public void insert(NotebookData data) { String sql = "insert into " + DatabaseHelper.NOTE_TABLE_NAME; sql += "(_id, iid, time, date, content, color) values(?, ?, ?, ?, ?, ?)"; SQLiteDatabase sqlite = dbHelper.getWritableDatabase(); sqlite.execSQL(sql, new String[] { data.getId() + "", data.getIid() + "", data.getUnixTime() + "", data.getDate(), data.getContent(), data.getColor() + "" }); sqlite.close(); } /** * 删 * * @param id */ public void delete(int id) { SQLiteDatabase sqlite = dbHelper.getWritableDatabase(); String sql = ("delete from " + DatabaseHelper.NOTE_TABLE_NAME + " where _id=?"); sqlite.execSQL(sql, new Integer[] { id }); sqlite.close(); } /** * 改 * * @param data */ public void update(NotebookData data) { SQLiteDatabase sqlite = dbHelper.getWritableDatabase(); String sql = ("update " + DatabaseHelper.NOTE_TABLE_NAME + " set iid=?, time=?, date=?, content=?, color=? where _id=?"); sqlite.execSQL(sql, new String[] { data.getIid() + "", data.getUnixTime() + "", data.getDate(), data.getContent(), data.getColor() + "", data.getId() + "" }); sqlite.close(); } public List<NotebookData> query() { return query(" "); } /** * 查 * * @param where * @return */ public List<NotebookData> query(String where) { SQLiteDatabase sqlite = dbHelper.getReadableDatabase(); ArrayList<NotebookData> data = null; data = new ArrayList<NotebookData>(); Cursor cursor = sqlite.rawQuery("select * from " + DatabaseHelper.NOTE_TABLE_NAME + where, null); for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) { NotebookData notebookData = new NotebookData(); notebookData.setId(cursor.getInt(0)); notebookData.setIid(cursor.getInt(1)); notebookData.setUnixTime(cursor.getString(2)); notebookData.setDate(cursor.getString(3)); notebookData.setContent(cursor.getString(4)); notebookData.setColor(cursor.getInt(5)); data.add(notebookData); } if (!cursor.isClosed()) { cursor.close(); } sqlite.close(); return data; } /** * 重置 * * @param datas */ public void reset(List<NotebookData> datas) { if (datas != null) { SQLiteDatabase sqlite = dbHelper.getWritableDatabase(); // 删除全部 sqlite.execSQL("delete from " + DatabaseHelper.NOTE_TABLE_NAME); // 重新添加 for (NotebookData data : datas) { insert(data); } sqlite.close(); } } /** * 保存一条数据到本地(若已存在则直接覆盖) * * @param data */ public void save(NotebookData data) { List<NotebookData> datas = query(" where _id=" + data.getId()); if (datas != null && !datas.isEmpty()) { update(data); } else { insert(data); } } // // /** // * 合并一条数据到本地(通过更新时间判断仅保留最新) // * // * @param data // * @return 数据是否被合并了 // */ // public boolean merge(NotebookData data) { // Cursor cursor = sqlite.rawQuery( // "select * from " + DatabaseHelper.NOTE_TABLE_NAME // + " where _id=" + data.getId(), null); // NotebookData localData = new NotebookData(); // // 本循环其实只执行一次 // for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) { // localData.setId(cursor.getInt(0)); // localData.setIid(cursor.getInt(1)); // localData.setUnixTime(cursor.getString(2)); // localData.setDate(cursor.getString(3)); // localData.setContent(cursor.getString(4)); // localData.setColor(cursor.getInt(5)); // } // // 是否需要合这条数据 // boolean isMerge = localData.getUnixTime() < data.getUnixTime(); // if (isMerge) { // save(data); // } // return isMerge; // } public void destroy() { dbHelper.close(); } }
ActiveFragment.java
package net.oschina.app.fragment; import java.io.InputStream; import java.io.Serializable; import net.oschina.app.AppContext; import net.oschina.app.R; import net.oschina.app.adapter.ActiveAdapter; import net.oschina.app.api.remote.OSChinaApi; import net.oschina.app.base.BaseListFragment; import net.oschina.app.bean.Active; import net.oschina.app.bean.ActiveList; import net.oschina.app.bean.Constants; import net.oschina.app.bean.Notice; import net.oschina.app.service.NoticeUtils; import net.oschina.app.ui.MainActivity; import net.oschina.app.ui.dialog.CommonDialog; import net.oschina.app.ui.dialog.DialogHelper; import net.oschina.app.ui.empty.EmptyLayout; import net.oschina.app.util.HTMLUtil; import net.oschina.app.util.TDevice; import net.oschina.app.util.UIHelper; import net.oschina.app.util.XmlUtils; import net.oschina.app.viewpagerfragment.NoticeViewPagerFragment; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.Bundle; import android.view.View; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.AdapterView.OnItemLongClickListener; /** * 动态fragment * * @author FireAnt(http://my.oschina.net/LittleDY) * @author kymjs (https://github.com/kymjs) * @created 2014年10月22日 下午3:35:43 * */ public class ActiveFragment extends BaseListFragment<Active> implements OnItemLongClickListener { protected static final String TAG = ActiveFragment.class.getSimpleName(); private static final String CACHE_KEY_PREFIX = "active_list"; private boolean mIsWatingLogin; // 还没登陆 private final BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if (mErrorLayout != null) { mIsWatingLogin = true; mErrorLayout.setErrorType(EmptyLayout.NETWORK_ERROR); mErrorLayout.setErrorMessage(getString(R.string.unlogin_tip)); } } }; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); IntentFilter filter = new IntentFilter(Constants.INTENT_ACTION_LOGOUT); getActivity().registerReceiver(mReceiver, filter); } @Override public void onDestroy() { getActivity().unregisterReceiver(mReceiver); super.onDestroy(); } @Override public void onResume() { if (mIsWatingLogin) { mCurrentPage = 0; mState = STATE_REFRESH; requestData(false); } refreshNotice(); super.onResume(); } /** * 开始刷新请求 */ private void refreshNotice() { Notice notice = MainActivity.mNotice; if (notice == null) { return; } if (notice.getAtmeCount() > 0 && mCatalog == ActiveList.CATALOG_ATME) { onRefresh(); } else if (notice.getReviewCount() > 0 && mCatalog == ActiveList.CATALOG_COMMENT) { onRefresh(); } } @Override protected ActiveAdapter getListAdapter() { return new ActiveAdapter(); } @Override protected String getCacheKeyPrefix() { return new StringBuffer(CACHE_KEY_PREFIX + mCatalog).append( AppContext.getInstance().getLoginUid()).toString(); } @Override protected ActiveList parseList(InputStream is) { ActiveList list = XmlUtils.toBean(ActiveList.class, is); return list; } @Override protected ActiveList readList(Serializable seri) { return ((ActiveList) seri); } @Override public void initView(View view) { if (mCatalog == ActiveList.CATALOG_LASTEST) { setHasOptionsMenu(true); } super.initView(view); mListView.setOnItemLongClickListener(this); mListView.setOnItemClickListener(this); mErrorLayout.setOnLayoutClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (AppContext.getInstance().isLogin()) { mErrorLayout.setErrorType(EmptyLayout.NETWORK_LOADING); requestData(false); } else { UIHelper.showLoginActivity(getActivity()); } } }); if (AppContext.getInstance().isLogin()) { UIHelper.sendBroadcastForNotice(getActivity()); } } @Override protected void requestData(boolean refresh) { if (AppContext.getInstance().isLogin()) { mIsWatingLogin = false; super.requestData(refresh); } else { mIsWatingLogin = true; mErrorLayout.setErrorType(EmptyLayout.NETWORK_ERROR); mErrorLayout.setErrorMessage(getString(R.string.unlogin_tip)); } } @Override protected void sendRequestData() { OSChinaApi.getActiveList(AppContext.getInstance().getLoginUid(), mCatalog, mCurrentPage, mHandler); } @Override protected void onRefreshNetworkSuccess() { if (AppContext.getInstance().isLogin()) { if (0 == NoticeViewPagerFragment.sCurrentPage) { NoticeUtils.clearNotice(Notice.TYPE_ATME); } else if (1 == NoticeViewPagerFragment.sCurrentPage || NoticeViewPagerFragment.sShowCount[1] > 0) { // 如果当前显示的是评论页,则发送评论页已被查看的Http请求 NoticeUtils.clearNotice(Notice.TYPE_COMMENT); } else { NoticeUtils.clearNotice(Notice.TYPE_ATME); } UIHelper.sendBroadcastForNotice(getActivity()); } } @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { Active active = mAdapter.getItem(position); if (active != null) UIHelper.showActiveRedirect(view.getContext(), active); } @Override public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) { final Active active = mAdapter.getItem(position); if (active == null) return false; String[] items = new String[] { getResources().getString(R.string.copy) }; final CommonDialog dialog = DialogHelper .getPinterestDialogCancelable(getActivity()); dialog.setNegativeButton(R.string.cancle, null); dialog.setItemsWithoutChk(items, new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { dialog.dismiss(); TDevice.copyTextToBoard(HTMLUtil.delHTMLTag(active.getMessage())); } }); dialog.show(); return true; } @Override protected long getAutoRefreshTime() { // 最新动态,即是好友圈 if (mCatalog == ActiveList.CATALOG_LASTEST) { return 5 * 60; } return super.getAutoRefreshTime(); } }
EventFragment.java
package net.oschina.app.fragment; import java.io.InputStream; import java.io.Serializable; import net.oschina.app.AppContext; import net.oschina.app.R; import net.oschina.app.adapter.EventAdapter; import net.oschina.app.api.remote.OSChinaApi; import net.oschina.app.base.BaseListFragment; import net.oschina.app.bean.Constants; import net.oschina.app.bean.Event; import net.oschina.app.bean.EventList; import net.oschina.app.ui.empty.EmptyLayout; import net.oschina.app.util.UIHelper; import net.oschina.app.util.XmlUtils; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.Bundle; import android.view.View; import android.widget.AdapterView; /** * 活动列表fragment * * @author FireAnt(http://my.oschina.net/LittleDY) * @version 创建时间:2014年12月8日 下午5:17:32 * */ public class EventFragment extends BaseListFragment<Event> { public static final String BUNDLE_KEY_EVENT_TYPE = "eventlist_type"; protected static final String TAG = EventFragment.class.getSimpleName(); private static final String CACHE_KEY_PREFIX = "eventlist_"; private int event_type; @Override protected EventAdapter getListAdapter() { EventAdapter adapter = new EventAdapter(); adapter.setEventType(event_type); return adapter; } private final BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { requestData(true); } }; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Bundle args = getArguments(); if (args != null) { event_type = args.getInt(BUNDLE_KEY_EVENT_TYPE); } if (event_type == EventList.EVENT_LIST_TYPE_MY_EVENT) { IntentFilter filter = new IntentFilter( Constants.INTENT_ACTION_USER_CHANGE); filter.addAction(Constants.INTENT_ACTION_LOGOUT); getActivity().registerReceiver(mReceiver, filter); } } @Override public void onDestroy() { super.onDestroy(); if (event_type == EventList.EVENT_LIST_TYPE_MY_EVENT) { getActivity().unregisterReceiver(mReceiver); } } @Override public void initView(View view) { super.initView(view); mErrorLayout.setOnLayoutClickListener(new View.OnClickListener() { @Override public void onClick(View v) { clickErrorLayout(); } }); } private void clickErrorLayout() { if (event_type == EventList.EVENT_LIST_TYPE_NEW_EVENT) { mErrorLayout.setErrorType(EmptyLayout.NETWORK_LOADING); requestData(true); } else { if (AppContext.getInstance().isLogin()) { mErrorLayout.setErrorType(EmptyLayout.NETWORK_LOADING); requestData(true); } else { UIHelper.showLoginActivity(getActivity()); } } } @Override protected void requestData(boolean refresh) { if (event_type == EventList.EVENT_LIST_TYPE_NEW_EVENT) { mCatalog = -1; super.requestData(refresh); return; } if (AppContext.getInstance().isLogin()) { mCatalog = AppContext.getInstance().getLoginUid(); super.requestData(refresh); } else { mErrorLayout.setErrorType(EmptyLayout.NETWORK_ERROR); mErrorLayout.setErrorMessage(getString(R.string.unlogin_tip)); } } @Override protected String getCacheKeyPrefix() { return CACHE_KEY_PREFIX + mCatalog; } @Override protected EventList parseList(InputStream is) throws Exception { EventList list = XmlUtils.toBean(EventList.class, is); return list; } @Override protected EventList readList(Serializable seri) { return ((EventList) seri); } @Override protected void sendRequestData() { OSChinaApi.getEventList(mCurrentPage, mCatalog, mHandler); } @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { Event event = mAdapter.getItem(position); if (event != null) UIHelper.showEventDetail(view.getContext(), event.getId()); } }
EventDetailFragment.java
package net.oschina.app.fragment; import java.io.ByteArrayInputStream; import java.io.InputStream; import java.io.Serializable; import java.net.URLEncoder; import net.oschina.app.AppContext; import net.oschina.app.R; import net.oschina.app.api.remote.OSChinaApi; import net.oschina.app.base.BaseDetailFragment; import net.oschina.app.base.BaseListFragment; import net.oschina.app.bean.CommentList; import net.oschina.app.bean.Entity; import net.oschina.app.bean.Event; import net.oschina.app.bean.EventApplyData; import net.oschina.app.bean.FavoriteList; import net.oschina.app.bean.Post; import net.oschina.app.bean.PostDetail; import net.oschina.app.bean.Result; import net.oschina.app.bean.ResultBean; import net.oschina.app.bean.SimpleBackPage; import net.oschina.app.emoji.OnSendClickListener; import net.oschina.app.ui.DetailActivity; import net.oschina.app.ui.EventApplyDialog; import net.oschina.app.ui.empty.EmptyLayout; import net.oschina.app.util.StringUtils; import net.oschina.app.util.TDevice; import net.oschina.app.util.UIHelper; import net.oschina.app.util.XmlUtils; import org.apache.http.Header; import android.content.DialogInterface; import android.os.Bundle; import android.support.annotation.Nullable; import android.text.Editable; import android.text.TextUtils; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.webkit.WebView; import android.widget.Button; import android.widget.TextView; import butterknife.ButterKnife; import butterknife.InjectView; import com.loopj.android.http.AsyncHttpResponseHandler; /** * 活动详情页面 * * @author FireAnt(http://my.oschina.net/LittleDY) * @created 2014年12月12日 下午3:08:49 * */ public class EventDetailFragment extends BaseDetailFragment implements OnSendClickListener { protected static final String TAG = EventDetailFragment.class .getSimpleName(); private static final String POST_CACHE_KEY = "post_"; @InjectView(R.id.tv_event_title) TextView mTvTitle; @InjectView(R.id.tv_event_start_time) TextView mTvStartTime; @InjectView(R.id.tv_event_end_time) TextView mTvEndTime; @InjectView(R.id.tv_event_spot) TextView mTvSpot; @InjectView(R.id.webview) WebView mWebView; @InjectView(R.id.rl_event_location) View mLocation; @InjectView(R.id.bt_event_attend) Button mBtAttend;// 出席人员 @InjectView(R.id.bt_event_apply) Button mBtEventApply;// 活动报名 @InjectView(R.id.tv_event_tip) TextView mEventTip; private int mPostId; private Post mPost; private EventApplyDialog mEventApplyDialog; @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { super.onCreateView(inflater, container, savedInstanceState); View view = inflater.inflate(R.layout.fragment_event_detail, container, false); mPostId = getActivity().getIntent().getIntExtra("post_id", 0); ButterKnife.inject(this, view); initViews(view); return view; } @Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); requestData(true); } @Override protected void onFavoriteChanged(boolean flag) { super.onFavoriteChanged(flag); mPost.setFavorite(flag ? 1 : 0); saveCache(mPost); } private void initViews(View view) { mEmptyLayout = (EmptyLayout) view.findViewById(R.id.error_layout); mLocation.setOnClickListener(this); mBtAttend.setOnClickListener(this); mBtEventApply.setOnClickListener(this); UIHelper.initWebView(mWebView); } @Override public void onClick(View v) { super.onClick(v); int id = v.getId(); switch (id) { case R.id.rl_event_location: UIHelper.showEventLocation(getActivity(), mPost.getEvent() .getCity(), mPost.getEvent().getSpot()); break; case R.id.bt_event_attend: showEventApplies(); break; case R.id.bt_event_apply: showEventApply(); break; default: break; } } private void showEventApplies() { Bundle args = new Bundle(); args.putInt(BaseListFragment.BUNDLE_KEY_CATALOG, mPost.getEvent() .getId()); UIHelper.showSimpleBack(getActivity(), SimpleBackPage.EVENT_APPLY, args); } private final AsyncHttpResponseHandler mApplyHandler = new AsyncHttpResponseHandler() { @Override public void onSuccess(int arg0, Header[] arg1, byte[] arg2) { Result rs = XmlUtils.toBean(ResultBean.class, new ByteArrayInputStream(arg2)).getResult(); if (rs.OK()) { AppContext.showToast("报名成功"); mEventApplyDialog.dismiss(); mPost.getEvent().setApplyStatus(Event.APPLYSTATUS_CHECKING); notifyEventStatus(); } else { AppContext.showToast(rs.getErrorMessage()); } } @Override public void onFailure(int arg0, Header[] arg1, byte[] arg2, Throwable arg3) { AppContext.showToast("报名失败"); } @Override public void onFinish() { hideWaitDialog(); } }; /** * 显示活动报名对话框 */ private void showEventApply() { if (mPost.getEvent().getCategory() == 4) { UIHelper.openSysBrowser(getActivity(), mPost.getEvent().getUrl()); return; } if (!AppContext.getInstance().isLogin()) { UIHelper.showLoginActivity(getActivity()); return; } if (mEventApplyDialog == null) { mEventApplyDialog = new EventApplyDialog(getActivity()); mEventApplyDialog.setCanceledOnTouchOutside(true); mEventApplyDialog.setCancelable(true); mEventApplyDialog.setTitle("活动报名"); mEventApplyDialog.setCanceledOnTouchOutside(true); mEventApplyDialog.setNegativeButton(R.string.cancle, null); mEventApplyDialog.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface d, int which) { EventApplyData data = null; if ((data = mEventApplyDialog.getApplyData()) != null) { data.setEvent(mPostId); data.setUser(AppContext.getInstance() .getLoginUid()); showWaitDialog(R.string.progress_submit); OSChinaApi.eventApply(data, mApplyHandler); } } }); } mEventApplyDialog.show(); } @Override protected String getCacheKey() { return new StringBuilder(POST_CACHE_KEY).append(mPostId).toString(); } @Override protected void sendRequestData() { mEmptyLayout.setErrorType(EmptyLayout.NETWORK_LOADING); OSChinaApi.getPostDetail(mPostId, mHandler); } @Override protected Entity parseData(InputStream is) throws Exception { return XmlUtils.toBean(PostDetail.class, is).getPost(); } @Override protected Entity readData(Serializable seri) { return (Post) seri; } @Override protected void executeOnLoadDataSuccess(Entity entity) { mPost = (Post) entity; fillUI(); fillWebViewBody(); ((DetailActivity) getActivity()).toolFragment.setCommentCount(mPost .getAnswerCount()); } private void fillUI() { mTvTitle.setText(mPost.getTitle()); mTvStartTime.setText(String.format( getString(R.string.event_start_time), mPost.getEvent() .getStartTime())); mTvEndTime.setText(String.format(getString(R.string.event_end_time), mPost.getEvent().getEndTime())); mTvSpot.setText(mPost.getEvent().getCity() + " " + mPost.getEvent().getSpot()); notifyFavorite(mPost.getFavorite() == 1); // 站外活动 if (mPost.getEvent().getCategory() == 4) { mBtEventApply.setVisibility(View.VISIBLE); mBtAttend.setVisibility(View.GONE); mBtEventApply.setText("报名链接"); } else { notifyEventStatus(); } } @Override public int getCommentCount() { return mPost.getAnswerCount(); } // 显示活动 以及报名的状态 private void notifyEventStatus() { int eventStatus = mPost.getEvent().getStatus(); int applyStatus = mPost.getEvent().getApplyStatus(); if (applyStatus == Event.APPLYSTATUS_ATTEND) { mBtAttend.setVisibility(View.VISIBLE); } else { mBtAttend.setVisibility(View.GONE); } if (eventStatus == Event.EVNET_STATUS_APPLYING) { mBtEventApply.setVisibility(View.VISIBLE); mBtEventApply.setEnabled(false); switch (applyStatus) { case Event.APPLYSTATUS_CHECKING: mBtEventApply.setText("待确认"); break; case Event.APPLYSTATUS_CHECKED: mBtEventApply.setText("已确认"); mBtEventApply.setVisibility(View.GONE); mEventTip.setVisibility(View.VISIBLE); break; case Event.APPLYSTATUS_ATTEND: mBtEventApply.setText("已出席"); break; case Event.APPLYSTATUS_CANCLE: mBtEventApply.setText("已取消"); mBtEventApply.setEnabled(true); break; case Event.APPLYSTATUS_REJECT: mBtEventApply.setText("已拒绝"); break; default: mBtEventApply.setText("我要报名"); mBtEventApply.setEnabled(true); break; } } else { mBtEventApply.setVisibility(View.GONE); } } private void fillWebViewBody() { // 显示标签 StringBuffer body = new StringBuffer(); body.append(UIHelper.setHtmlCotentSupportImagePreview(mPost.getBody())); body.append(UIHelper.WEB_STYLE).append(UIHelper.WEB_LOAD_IMAGES) .append(getPostTags(mPost.getTags())) .append("<div style=\"margin-bottom: 80px\" />"); mWebView.loadDataWithBaseURL(null, body.toString(), "text/html", "utf-8", null); } @SuppressWarnings("deprecation") private String getPostTags(Post.Tags taglist) { if (taglist == null) return ""; StringBuffer tags = new StringBuffer(); for (String tag : taglist.getTags()) { tags.append(String .format("<a class='tag' href='http://www.oschina.net/question/tag/%s' > %s </a> ", URLEncoder.encode(tag), tag)); } return String.format("<div style='margin-top:10px;'>%s</div>", tags); } @Override protected int getFavoriteTargetId() { return mPost != null ? mPost.getId() : -1; } @Override protected int getFavoriteTargetType() { return mPost != null ? FavoriteList.TYPE_POST : -1; } @Override protected String getShareTitle() { return mPost != null ? mPost.getTitle() : getString(R.string.share_title_post); } @Override protected String getShareContent() { return mPost != null ? StringUtils.getSubString(0, 55, getFilterHtmlBody(mPost.getBody())) : ""; } @Override protected String getShareUrl() { return mPost != null ? mPost.getUrl().replace("http://www", "http://m") : null; } @Override public void onClickSendButton(Editable str) { if (!TDevice.hasInternet()) { AppContext.showToastShort(R.string.tip_network_error); return; } if (!AppContext.getInstance().isLogin()) { UIHelper.showLoginActivity(getActivity()); return; } if (TextUtils.isEmpty(str)) { AppContext.showToastShort(R.string.tip_comment_content_empty); return; } showWaitDialog(R.string.progress_submit); OSChinaApi.publicComment(CommentList.CATALOG_POST, mPostId, AppContext .getInstance().getLoginUid(), str.toString(), 0, mCommentHandler); } @Override public void onClickFlagButton() {} @Override public void onclickWriteComment() { super.onclickWriteComment(); UIHelper.showComment(getActivity(), mPostId, CommentList.CATALOG_POST); } @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { inflater.inflate(R.menu.refresh_menu, menu); super.onCreateOptionsMenu(menu, inflater); } @Override public boolean onOptionsItemSelected(MenuItem item) { sendRequestData(); return super.onOptionsItemSelected(item); } }
EventAppliesFragment.java
package net.oschina.app.fragment; import java.io.InputStream; import java.io.Serializable; import net.oschina.app.AppContext; import net.oschina.app.adapter.EventApplyAdapter; import net.oschina.app.api.remote.OSChinaApi; import net.oschina.app.base.BaseListFragment; import net.oschina.app.bean.Apply; import net.oschina.app.bean.EventAppliesList; import net.oschina.app.util.UIHelper; import net.oschina.app.util.XmlUtils; import android.annotation.TargetApi; import android.os.Build; import android.view.View; import android.widget.AdapterView; /** * 活动出席人员列表 * * @author FireAnt(http://my.oschina.net/LittleDY) * @created 2014年12月12日 下午7:59:10 * */ @TargetApi(Build.VERSION_CODES.HONEYCOMB) public class EventAppliesFragment extends BaseListFragment<Apply> { protected static final String TAG = EventAppliesFragment.class.getSimpleName(); private static final String CACHE_KEY_PREFIX = "event_apply_user_list"; @Override public void initView(View view) { super.initView(view); } @Override protected EventApplyAdapter getListAdapter() { return new EventApplyAdapter(); } @Override protected String getCacheKeyPrefix() { return CACHE_KEY_PREFIX + "_" + mCatalog; } @Override protected EventAppliesList parseList(InputStream is) throws Exception { EventAppliesList list = XmlUtils.toBean(EventAppliesList.class, is); return list; } @Override protected EventAppliesList readList(Serializable seri) { return ((EventAppliesList) seri); } @Override protected void sendRequestData() { OSChinaApi.getEventApplies(mCatalog, mCurrentPage, mHandler); } @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { Apply item = (Apply) mAdapter.getItem(position); if (item != null) { if (AppContext.getInstance().isLogin()) { UIHelper.showMessageDetail(getActivity(), item.getId(), item.getName()); return; } UIHelper.showUserCenter(getActivity(), item.getId(),item.getName()); } } }
BaseFragmentInterface.java
package net.oschina.app.interf; import android.view.View; /** * 基类fragment实现接口 * @author FireAnt(http://my.oschina.net/LittleDY) * @created 2014年9月25日 上午11:00:25 * */ public interface BaseFragmentInterface { public void initView(View view); public void initData(); }
BaseViewInterface.java
package net.oschina.app.interf; /** * * @author deyi * */ public interface BaseViewInterface { public void initView(); public void initData(); }
ICallbackResult.java
package net.oschina.app.interf; /** * @author FireAnt(http://my.oschina.net/LittleDY) * @version 创建时间:2014年11月18日 上午11:18:28 * */ public interface ICallbackResult { public void OnBackResult(Object s); }
OnTabReselectListener.java
package net.oschina.app.interf; /** * 当tabHost再次被点击时 * @author FireAnt(http://my.oschina.net/LittleDY) * @version 创建时间:2014年11月17日 上午11:00:15 * */ public interface OnTabReselectListener { public void onTabReselect(); }
OnWebViewImageListener.java
package net.oschina.app.interf; /** * 监听webview上的图片 * * @author yeguozhong@yeah.net * */ public interface OnWebViewImageListener { /** * 点击webview上的图片,传入该缩略图的大图Url * @param bigImageUrl */ void showImagePreview(String bigImageUrl); }
DownloadService.java
package net.oschina.app.service; import java.io.File; import java.io.FileOutputStream; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; import net.oschina.app.AppConfig; import net.oschina.app.R; import net.oschina.app.interf.ICallbackResult; import net.oschina.app.ui.MainActivity; import net.oschina.app.util.StringUtils; import net.oschina.app.util.TDevice; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.app.Service; import android.content.Context; import android.content.Intent; import android.os.Binder; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.widget.RemoteViews; /** * download service * * @author FireAnt(http://my.oschina.net/LittleDY) * @created 2014年11月18日 下午3:02:36 * */ public class DownloadService extends Service { public static final String BUNDLE_KEY_DOWNLOAD_URL = "download_url"; public static final String BUNDLE_KEY_TITLE = "title"; private final String tag = "download"; private static final int NOTIFY_ID = 0; private int progress; private NotificationManager mNotificationManager; private boolean canceled; private String downloadUrl; private String mTitle = "正在下载%s"; private String saveFileName = AppConfig.DEFAULT_SAVE_FILE_PATH; private ICallbackResult callback; private DownloadBinder binder; private boolean serviceIsDestroy = false; private Context mContext = this; private Thread downLoadThread; private Notification mNotification; private Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { // TODO Auto-generated method stub super.handleMessage(msg); switch (msg.what) { case 0: // 下载完毕 mNotificationManager.cancel(NOTIFY_ID); installApk(); break; case 2: // 取消通知 mNotificationManager.cancel(NOTIFY_ID); break; case 1: int rate = msg.arg1; if (rate < 100) { RemoteViews contentview = mNotification.contentView; contentview.setTextViewText(R.id.tv_download_state, mTitle + "(" + rate + "%" + ")"); contentview.setProgressBar(R.id.pb_download, 100, rate, false); } else { // 下载完毕后变换通知形式 mNotification.flags = Notification.FLAG_AUTO_CANCEL; mNotification.contentView = null; Intent intent = new Intent(mContext, MainActivity.class); // 告知已完成 intent.putExtra("completed", "yes"); // 更新参数,注意flags要使用FLAG_UPDATE_CURRENT PendingIntent contentIntent = PendingIntent.getActivity( mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); mNotification.setLatestEventInfo(mContext, "下载完成", "文件已下载完毕", contentIntent); serviceIsDestroy = true; stopSelf();// 停掉服务自身 } mNotificationManager.notify(NOTIFY_ID, mNotification); break; } } }; @Override public IBinder onBind(Intent intent) { downloadUrl = intent.getStringExtra(BUNDLE_KEY_DOWNLOAD_URL); saveFileName = saveFileName + getSaveFileName(downloadUrl); mTitle = String.format(mTitle, intent.getStringExtra(BUNDLE_KEY_TITLE)); return binder; } private String getSaveFileName(String downloadUrl) { if (downloadUrl == null || StringUtils.isEmpty(downloadUrl)) { return ""; } return downloadUrl.substring(downloadUrl.lastIndexOf("/")); } @Override public void onCreate() { super.onCreate(); binder = new DownloadBinder(); mNotificationManager = (NotificationManager) getSystemService(android.content.Context.NOTIFICATION_SERVICE); stopForeground(true);// 这个不确定是否有作用 } private void startDownload() { canceled = false; downloadApk(); } /** * 创建通知 */ private void setUpNotification() { int icon = R.drawable.ic_notification; CharSequence tickerText = "准备下载"; long when = System.currentTimeMillis(); mNotification = new Notification(icon, tickerText, when); ; // 放置在"正在运行"栏目中 mNotification.flags = Notification.FLAG_ONGOING_EVENT; RemoteViews contentView = new RemoteViews(getPackageName(), R.layout.download_notification_show); contentView.setTextViewText(R.id.tv_download_state, mTitle); // 指定个性化视图 mNotification.contentView = contentView; Intent intent = new Intent(this, MainActivity.class); PendingIntent contentIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); // 指定内容意图 mNotification.contentIntent = contentIntent; mNotificationManager.notify(NOTIFY_ID, mNotification); } private void downloadApk() { downLoadThread = new Thread(mdownApkRunnable); downLoadThread.start(); } /** * 安装apk */ private void installApk() { File apkfile = new File(saveFileName); if (!apkfile.exists()) { return; } TDevice.installAPK(mContext, apkfile); } private Runnable mdownApkRunnable = new Runnable() { @Override public void run() { File file = new File(AppConfig.DEFAULT_SAVE_FILE_PATH); if (!file.exists()) { file.mkdirs(); } String apkFile = saveFileName; File saveFile = new File(apkFile); try { downloadUpdateFile(downloadUrl, saveFile); } catch (Exception e) { e.printStackTrace(); } } }; public long downloadUpdateFile(String downloadUrl, File saveFile) throws Exception { int downloadCount = 0; int currentSize = 0; long totalSize = 0; int updateTotalSize = 0; HttpURLConnection httpConnection = null; InputStream is = null; FileOutputStream fos = null; try { URL url = new URL(downloadUrl); httpConnection = (HttpURLConnection) url.openConnection(); httpConnection .setRequestProperty("User-Agent", "PacificHttpClient"); if (currentSize > 0) { httpConnection.setRequestProperty("RANGE", "bytes=" + currentSize + "-"); } httpConnection.setConnectTimeout(10000); httpConnection.setReadTimeout(20000); updateTotalSize = httpConnection.getContentLength(); if (httpConnection.getResponseCode() == 404) { throw new Exception("fail!"); } is = httpConnection.getInputStream(); fos = new FileOutputStream(saveFile, false); byte buffer[] = new byte[1024]; int readsize = 0; while ((readsize = is.read(buffer)) > 0) { fos.write(buffer, 0, readsize); totalSize += readsize; // 为了防止频繁的通知导致应用吃紧,百分比增加10才通知一次 if ((downloadCount == 0) || (int) (totalSize * 100 / updateTotalSize) - 10 >= downloadCount) { downloadCount += 10; // 更新进度 Message msg = mHandler.obtainMessage(); msg.what = 1; msg.arg1 = downloadCount; mHandler.sendMessage(msg); if (callback != null) callback.OnBackResult(progress); } } // 下载完成通知安装 mHandler.sendEmptyMessage(0); // 下载完了,cancelled也要设置 canceled = true; } finally { if (httpConnection != null) { httpConnection.disconnect(); } if (is != null) { is.close(); } if (fos != null) { fos.close(); } } return totalSize; } public class DownloadBinder extends Binder { public void start() { if (downLoadThread == null || !downLoadThread.isAlive()) { progress = 0; setUpNotification(); new Thread() { public void run() { // 下载 startDownload(); }; }.start(); } } public void cancel() { canceled = true; } public int getProgress() { return progress; } public boolean isCanceled() { return canceled; } public boolean serviceIsDestroy() { return serviceIsDestroy; } public void cancelNotification() { mHandler.sendEmptyMessage(2); } public void addCallback(ICallbackResult callback) { DownloadService.this.callback = callback; } } }
NoticeService.java
package net.oschina.app.service; import java.io.ByteArrayInputStream; import java.lang.ref.WeakReference; import net.oschina.app.AppConfig; import net.oschina.app.AppContext; import net.oschina.app.R; import net.oschina.app.api.remote.OSChinaApi; import net.oschina.app.bean.Constants; import net.oschina.app.bean.Notice; import net.oschina.app.bean.NoticeDetail; import net.oschina.app.bean.Result; import net.oschina.app.bean.ResultBean; import net.oschina.app.broadcast.AlarmReceiver; import net.oschina.app.ui.MainActivity; import net.oschina.app.util.UIHelper; import net.oschina.app.util.XmlUtils; import org.apache.http.Header; import android.app.AlarmManager; import android.app.Notification; import android.app.PendingIntent; import android.app.Service; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.res.Resources; import android.net.Uri; import android.os.IBinder; import android.os.RemoteException; import android.support.v4.app.NotificationCompat; import android.support.v4.app.NotificationManagerCompat; import com.loopj.android.http.AsyncHttpResponseHandler; public class NoticeService extends Service { public static final String INTENT_ACTION_GET = "net.oschina.app.service.GET_NOTICE"; public static final String INTENT_ACTION_CLEAR = "net.oschina.app.service.CLEAR_NOTICE"; public static final String INTENT_ACTION_BROADCAST = "net.oschina.app.service.BROADCAST"; public static final String INTENT_ACTION_SHUTDOWN = "net.oschina.app.service.SHUTDOWN"; public static final String INTENT_ACTION_REQUEST = "net.oschina.app.service.REQUEST"; public static final String BUNDLE_KEY_TPYE = "bundle_key_type"; private static final long INTERVAL = 1000 * 120; private AlarmManager mAlarmMgr; private Notice mNotice; private final BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (Constants.INTENT_ACTION_NOTICE.equals(action)) { Notice notice = (Notice) intent.getSerializableExtra("notice_bean"); int atmeCount = notice.getAtmeCount();// @我 int msgCount = notice.getMsgCount();// 留言 int reviewCount = notice.getReviewCount();// 评论 int newFansCount = notice.getNewFansCount();// 新粉丝 int newLikeCount = notice.getNewLikeCount();// 点赞数 int activeCount = atmeCount + reviewCount + msgCount + newFansCount + newLikeCount; if (activeCount == 0) { NotificationManagerCompat.from(NoticeService.this).cancel( R.string.you_have_news_messages); } } else if (INTENT_ACTION_BROADCAST.equals(action)) { if (mNotice != null) { UIHelper.sendBroadCast(NoticeService.this, mNotice); } } else if (INTENT_ACTION_SHUTDOWN.equals(action)) { stopSelf(); } else if (INTENT_ACTION_REQUEST.equals(action)) { requestNotice(); } } }; @Override public IBinder onBind(Intent intent) { return mBinder; } @Override public void onCreate() { super.onCreate(); mAlarmMgr = (AlarmManager) getSystemService(ALARM_SERVICE); startRequestAlarm(); requestNotice(); IntentFilter filter = new IntentFilter(INTENT_ACTION_BROADCAST); filter.addAction(Constants.INTENT_ACTION_NOTICE); filter.addAction(INTENT_ACTION_SHUTDOWN); filter.addAction(INTENT_ACTION_REQUEST); registerReceiver(mReceiver, filter); } @Override public int onStartCommand(Intent intent, int flags, int startId) { return super.onStartCommand(intent, flags, startId); } @Override public void onDestroy() { cancelRequestAlarm(); unregisterReceiver(mReceiver); super.onDestroy(); } private void startRequestAlarm() { cancelRequestAlarm(); // 从1秒后开始,每隔2分钟执行getOperationIntent() mAlarmMgr.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + 1000, INTERVAL, getOperationIntent()); } /** * <!-- kymjs --> 即使启动PendingIntent的原进程结束了的话,PendingIntent本身仍然还存在,可在其他进程( * PendingIntent被递交到的其他程序)中继续使用. * 如果我在从系统中提取一个PendingIntent的,而系统中有一个和你描述的PendingIntent对等的PendingInent, * 那么系统会直接返回和该PendingIntent其实是同一token的PendingIntent, * 而不是一个新的token和PendingIntent。然而你在从提取PendingIntent时,通过FLAG_CANCEL_CURRENT参数, * 让这个老PendingIntent的先cancel()掉,这样得到的pendingInten和其token的就是新的了。 */ private void cancelRequestAlarm() { mAlarmMgr.cancel(getOperationIntent()); } /** * OSC采用轮询方式实现消息推送<br> * 每次被调用都去执行一次{@link #AlarmReceiver}onReceive()方法 * * @return */ private PendingIntent getOperationIntent() { Intent intent = new Intent(this, AlarmReceiver.class); PendingIntent operation = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); return operation; } private void clearNotice(int uid, int type) { OSChinaApi.clearNotice(uid, type, mClearNoticeHandler); } private int lastNotifiyCount; private void notification(Notice notice) { int atmeCount = notice.getAtmeCount(); int msgCount = notice.getMsgCount(); int reviewCount = notice.getReviewCount(); int newFansCount = notice.getNewFansCount(); int newLikeCount = notice.getNewLikeCount(); int count = atmeCount + msgCount + reviewCount + newFansCount + newLikeCount; if (count == 0) { lastNotifiyCount = 0; NotificationManagerCompat.from(this).cancel( R.string.you_have_news_messages); return; } if (count == lastNotifiyCount) return; lastNotifiyCount = count; Resources res = getResources(); String contentTitle = res.getString(R.string.you_have_news_messages, count); String contentText; StringBuffer sb = new StringBuffer(); if (atmeCount > 0) { sb.append(getString(R.string.atme_count, atmeCount)).append(" "); } if (msgCount > 0) { sb.append(getString(R.string.msg_count, msgCount)).append(" "); } if (reviewCount > 0) { sb.append(getString(R.string.review_count, reviewCount)) .append(" "); } if (newFansCount > 0) { sb.append(getString(R.string.fans_count, newFansCount)); } if (newLikeCount > 0) { sb.append(getString(R.string.like_count, newLikeCount)); } contentText = sb.toString(); Intent intent = new Intent(this, MainActivity.class); intent.putExtra("NOTICE", true); PendingIntent pi = PendingIntent.getActivity(this, 1000, intent, PendingIntent.FLAG_CANCEL_CURRENT); NotificationCompat.Builder builder = new NotificationCompat.Builder( this).setTicker(contentTitle).setContentTitle(contentTitle) .setContentText(contentText).setAutoCancel(true) .setContentIntent(pi).setSmallIcon(R.drawable.ic_notification); if (AppContext.get(AppConfig.KEY_NOTIFICATION_SOUND, true)) { builder.setSound(Uri.parse("android.resource://" + AppContext.getInstance().getPackageName() + "/" + R.raw.notificationsound)); } if (AppContext.get(AppConfig.KEY_NOTIFICATION_VIBRATION, true)) { long[] vibrate = { 0, 10, 20, 30 }; builder.setVibrate(vibrate); } Notification notification = builder.build(); NotificationManagerCompat.from(this).notify( R.string.you_have_news_messages, notification); } private final AsyncHttpResponseHandler mGetNoticeHandler = new AsyncHttpResponseHandler() { @Override public void onSuccess(int arg0, Header[] arg1, byte[] arg2) { try { Notice notice = XmlUtils.toBean(NoticeDetail.class, arg2).getNotice(); if (notice != null) { UIHelper.sendBroadCast(NoticeService.this, notice); if (AppContext.get(AppConfig.KEY_NOTIFICATION_ACCEPT, true)) { notification(notice); } mNotice = notice; } else { // ResultBean resultBean = XmlUtils.toBean(ResultBean.class, arg2); // if (resultBean != null && resultBean.getResult() != null) { // AppContext appContext = AppContext.getInstance(); // if (appContext != null) { // appContext.Logout(); // } // } } } catch (Exception e) { e.printStackTrace(); onFailure(arg0, arg1, arg2, e); } }; @Override public void onFailure(int arg0, Header[] arg1, byte[] arg2, Throwable arg3) { arg3.printStackTrace(); } }; private final AsyncHttpResponseHandler mClearNoticeHandler = new AsyncHttpResponseHandler() { @Override public void onSuccess(int arg0, Header[] arg1, byte[] arg2) { try { ResultBean rsb = XmlUtils.toBean(ResultBean.class, new ByteArrayInputStream(arg2)); Result res = rsb.getResult(); if (res.OK() && rsb.getNotice() != null) { mNotice = rsb.getNotice(); UIHelper.sendBroadCast(NoticeService.this, rsb.getNotice()); } } catch (Exception e) { e.printStackTrace(); } } @Override public void onFailure(int arg0, Header[] arg1, byte[] arg2, Throwable arg3) {} }; /** * 请求是否有新通知 */ private void requestNotice() { OSChinaApi.getNotices(mGetNoticeHandler); } private static class ServiceStub extends INoticeService.Stub { WeakReference<NoticeService> mService; ServiceStub(NoticeService service) { mService = new WeakReference<NoticeService>(service); } @Override public void clearNotice(int uid, int type) throws RemoteException { mService.get().clearNotice(uid, type); } @Override public void scheduleNotice() throws RemoteException { mService.get().startRequestAlarm(); } @Override public void requestNotice() throws RemoteException { mService.get().requestNotice(); } } private final IBinder mBinder = new ServiceStub(this); }
NoticeUtils.java
package net.oschina.app.service; import java.util.HashMap; import net.oschina.app.AppConfig; import net.oschina.app.AppContext; import net.oschina.app.util.TLog; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.os.RemoteException; import android.util.Log; public class NoticeUtils { public static INoticeService sService = null; private static HashMap<Context, ServiceBinder> sConnectionMap = new HashMap<Context, ServiceBinder>(); public static boolean bindToService(Context context) { return bindToService(context, null); } public static boolean bindToService(Context context, ServiceConnection callback) { context.startService(new Intent(context, NoticeService.class)); ServiceBinder sb = new ServiceBinder(callback); sConnectionMap.put(context, sb); return context.bindService( (new Intent()).setClass(context, NoticeService.class), sb, 0); } public static void unbindFromService(Context context) { ServiceBinder sb = sConnectionMap.remove(context); if (sb == null) { Log.e("MusicUtils", "Trying to unbind for unknown Context"); return; } context.unbindService(sb); if (sConnectionMap.isEmpty()) { // presumably there is nobody interested in the service at this // point, // so don't hang on to the ServiceConnection sService = null; } } public static void clearNotice(int type) { if (sService != null) { try { sService.clearNotice(AppContext.getInstance().getLoginUid(), type); } catch (RemoteException e) { e.printStackTrace(); } } } public static void requestNotice(Context context) { if (sService != null) { try { TLog.log("requestNotice..."); sService.requestNotice(); } catch (RemoteException e) { e.printStackTrace(); } } else { context.sendBroadcast(new Intent( NoticeService.INTENT_ACTION_REQUEST)); TLog.log("requestNotice,service is null"); } } public static void scheduleNotice() { if (sService != null) { try { sService.scheduleNotice(); } catch (RemoteException e) { e.printStackTrace(); } } } private static class ServiceBinder implements ServiceConnection { ServiceConnection mCallback; ServiceBinder(ServiceConnection callback) { mCallback = callback; } @Override public void onServiceConnected(ComponentName className, android.os.IBinder service) { sService = INoticeService.Stub.asInterface(service); if (mCallback != null) { mCallback.onServiceConnected(className, service); } } @Override public void onServiceDisconnected(ComponentName className) { if (mCallback != null) { mCallback.onServiceDisconnected(className); } sService = null; } } public static void tryToShutDown(Context context) { if (AppContext.get(AppConfig.KEY_NOTIFICATION_DISABLE_WHEN_EXIT, true)) { context.sendBroadcast(new Intent( NoticeService.INTENT_ACTION_SHUTDOWN)); } } public static void startNotifyService(Context context) { Intent service = new Intent(context, NoticeService.class); context.startService(service); } }
PublicCommentTask.java
package net.oschina.app.service; import android.os.Parcel; import android.os.Parcelable; public class PublicCommentTask implements Parcelable { private int catalog; private int id; private int uid; private String content; private int isPostToMyZone; public PublicCommentTask() { } public PublicCommentTask(Parcel source) { catalog = source.readInt(); id = source.readInt(); uid = source.readInt(); content = source.readString(); isPostToMyZone = source.readInt(); } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(catalog); dest.writeInt(id); dest.writeInt(uid); dest.writeString(content); dest.writeInt(isPostToMyZone); } public int getCatalog() { return catalog; } public void setCatalog(int catalog) { this.catalog = catalog; } public int getId() { return id; } public void setId(int id) { this.id = id; } public int getUid() { return uid; } public void setUid(int uid) { this.uid = uid; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } public int getIsPostToMyZone() { return isPostToMyZone; } public void setIsPostToMyZone(int isPostToMyZone) { this.isPostToMyZone = isPostToMyZone; } @Override public int describeContents() { return 0; } public static final Parcelable.Creator<PublicCommentTask> CREATOR = new Creator<PublicCommentTask>() { @Override public PublicCommentTask[] newArray(int size) { return new PublicCommentTask[size]; } @Override public PublicCommentTask createFromParcel(Parcel source) { return new PublicCommentTask(source); } }; }
ServerTaskService.java
package net.oschina.app.service; import java.io.ByteArrayInputStream; import java.io.File; import java.util.ArrayList; import java.util.List; import net.oschina.app.AppContext; import net.oschina.app.R; import net.oschina.app.api.OperationResponseHandler; import net.oschina.app.api.remote.OSChinaApi; import net.oschina.app.base.ListBaseAdapter; import net.oschina.app.bean.Comment; import net.oschina.app.bean.Result; import net.oschina.app.bean.ResultBean; import net.oschina.app.bean.Tweet; import net.oschina.app.util.XmlUtils; import android.app.IntentService; import android.app.Notification; import android.app.PendingIntent; import android.content.Intent; import android.os.Handler; import android.os.Looper; import android.support.v4.app.NotificationCompat; import android.support.v4.app.NotificationManagerCompat; public class ServerTaskService extends IntentService { private static final String SERVICE_NAME = "ServerTaskService"; public static final String ACTION_PUB_BLOG_COMMENT = "net.oschina.app.ACTION_PUB_BLOG_COMMENT"; public static final String ACTION_PUB_COMMENT = "net.oschina.app.ACTION_PUB_COMMENT"; public static final String ACTION_PUB_POST = "net.oschina.app.ACTION_PUB_POST"; public static final String ACTION_PUB_TWEET = "net.oschina.app.ACTION_PUB_TWEET"; public static final String ACTION_PUB_SOFTWARE_TWEET = "net.oschina.app.ACTION_PUB_SOFTWARE_TWEET"; public static final String KEY_ADAPTER = "adapter"; public static final String BUNDLE_PUB_COMMENT_TASK = "BUNDLE_PUB_COMMENT_TASK"; public static final String BUNDLE_PUB_POST_TASK = "BUNDLE_PUB_POST_TASK"; public static final String BUNDLE_PUB_TWEET_TASK = "BUNDLE_PUB_TWEET_TASK"; public static final String BUNDLE_PUB_SOFTWARE_TWEET_TASK = "BUNDLE_PUB_SOFTWARE_TWEET_TASK"; public static final String KEY_SOFTID = "soft_id"; private static final String KEY_COMMENT = "comment_"; private static final String KEY_TWEET = "tweet_"; private static final String KEY_SOFTWARE_TWEET = "software_tweet_"; private static final String KEY_POST = "post_"; public static List<String> penddingTasks = new ArrayList<String>(); class PublicCommentResponseHandler extends OperationResponseHandler { public PublicCommentResponseHandler(Looper looper, Object... args) { super(looper, args); } @Override public void onSuccess(int code, ByteArrayInputStream is, Object[] args) throws Exception { PublicCommentTask task = (PublicCommentTask) args[0]; final int id = task.getId() * task.getUid(); ResultBean resB = XmlUtils.toBean(ResultBean.class, is); Result res = resB.getResult(); if (res.OK()) { final Comment comment = resB.getComment(); // UIHelper.sendBroadCastCommentChanged(ServerTaskService.this, // isBlog, task.getId(), task.getCatalog(), // Comment.OPT_ADD, comment); notifySimpleNotifycation(id, getString(R.string.comment_publish_success), getString(R.string.comment_blog), getString(R.string.comment_publish_success), false, true); removePenddingTask(KEY_COMMENT + id); } else { onFailure(100, res.getErrorMessage(), args); } } @Override public void onFailure(int code, String errorMessage, Object[] args) { PublicCommentTask task = (PublicCommentTask) args[0]; int id = task.getId() * task.getUid(); notifySimpleNotifycation(id, getString(R.string.comment_publish_faile), getString(R.string.comment_blog), code == 100 ? errorMessage : getString(R.string.comment_publish_faile), false, true); removePenddingTask(KEY_COMMENT + id); } @Override public void onFinish() { tryToStopServie(); } } class PublicTweetResponseHandler extends OperationResponseHandler { String key = null; public PublicTweetResponseHandler(Looper looper, Object... args) { super(looper, args); key = (String) args[1]; } @Override public void onSuccess(int code, ByteArrayInputStream is, Object[] args) throws Exception { Tweet tweet = (Tweet) args[0]; final int id = tweet.getId(); Result res = XmlUtils.toBean(ResultBean.class, is).getResult(); if (res.OK()) { notifySimpleNotifycation(id, getString(R.string.tweet_publish_success), getString(R.string.tweet_public), getString(R.string.tweet_publish_success), false, true); new Handler().postDelayed(new Runnable() { @Override public void run() { cancellNotification(id); } }, 3000); removePenddingTask(key + id); if (tweet.getImageFilePath() != null) { File imgFile = new File(tweet.getImageFilePath()); if (imgFile.exists()) { imgFile.delete(); } } } else { onFailure(100, res.getErrorMessage(), args); } } @Override public void onFailure(int code, String errorMessage, Object[] args) { Tweet tweet = (Tweet) args[0]; int id = tweet.getId(); notifySimpleNotifycation(id, getString(R.string.tweet_publish_faile), getString(R.string.tweet_public), code == 100 ? errorMessage : getString(R.string.tweet_publish_faile), false, true); removePenddingTask(key + id); } @Override public void onFinish() { tryToStopServie(); } } public ServerTaskService() { this(SERVICE_NAME); } private synchronized void tryToStopServie() { if (penddingTasks == null || penddingTasks.size() == 0) { stopSelf(); } } private synchronized void addPenddingTask(String key) { penddingTasks.add(key); } private synchronized void removePenddingTask(String key) { penddingTasks.remove(key); } public ServerTaskService(String name) { super(name); } @Override public void onCreate() { super.onCreate(); } @Override protected void onHandleIntent(Intent intent) { String action = intent.getAction(); if (ACTION_PUB_BLOG_COMMENT.equals(action)) { PublicCommentTask task = intent .getParcelableExtra(BUNDLE_PUB_COMMENT_TASK); if (task != null) { publicBlogComment(task); } } else if (ACTION_PUB_COMMENT.equals(action)) { PublicCommentTask task = intent .getParcelableExtra(BUNDLE_PUB_COMMENT_TASK); if (task != null) { publicComment(task); } } else if (ACTION_PUB_POST.equals(action)) { // Post post = intent.getParcelableExtra(BUNDLE_PUBLIC_POST_TASK); // if (post != null) { // publicPost(post); // } } else if (ACTION_PUB_TWEET.equals(action)) { Tweet tweet = intent.getParcelableExtra(BUNDLE_PUB_TWEET_TASK); if (tweet != null) { pubTweet(tweet); } } else if (ACTION_PUB_SOFTWARE_TWEET.equals(action)) { Tweet tweet = intent .getParcelableExtra(BUNDLE_PUB_SOFTWARE_TWEET_TASK); int softid = intent.getIntExtra(KEY_SOFTID, -1); if (tweet != null && softid != -1) { pubSoftWareTweet(tweet, softid); } } } private void publicBlogComment(final PublicCommentTask task) { int id = task.getId() * task.getUid(); addPenddingTask(KEY_COMMENT + id); notifySimpleNotifycation(id, getString(R.string.comment_publishing), getString(R.string.comment_blog), getString(R.string.comment_publishing), true, false); OSChinaApi.publicBlogComment(task.getId(), task.getUid(), task .getContent(), new PublicCommentResponseHandler( getMainLooper(), task, true)); } private void publicComment(final PublicCommentTask task) { int id = task.getId() * task.getUid(); addPenddingTask(KEY_COMMENT + id); notifySimpleNotifycation(id, getString(R.string.comment_publishing), getString(R.string.comment_blog), getString(R.string.comment_publishing), true, false); OSChinaApi.publicComment(task.getCatalog(), task.getId(), task.getUid(), task.getContent(), task.getIsPostToMyZone(), new PublicCommentResponseHandler(getMainLooper(), task, false)); } // private void publicPost(Post post) { // post.setId((int) System.currentTimeMillis()); // int id = post.getId(); // addPenddingTask(KEY_POST + id); // notifySimpleNotifycation(id, getString(R.string.post_publishing), // getString(R.string.post_public), // getString(R.string.post_publishing), true, false); // OSChinaApi.publicPost(post, new // PublicPostResponseHandler(getMainLooper(), // post)); // } // private void pubTweet(final Tweet tweet) { tweet.setId((int) System.currentTimeMillis()); int id = tweet.getId(); addPenddingTask(KEY_TWEET + id); notifySimpleNotifycation(id, getString(R.string.tweet_publishing), getString(R.string.tweet_public), getString(R.string.tweet_publishing), true, false); OSChinaApi.pubTweet(tweet, new PublicTweetResponseHandler( getMainLooper(), tweet, KEY_TWEET)); } private void pubSoftWareTweet(final Tweet tweet, int softid) { tweet.setId((int) System.currentTimeMillis()); int id = tweet.getId(); addPenddingTask(KEY_SOFTWARE_TWEET + id); notifySimpleNotifycation(id, getString(R.string.tweet_publishing), getString(R.string.tweet_public), getString(R.string.tweet_publishing), true, false); OSChinaApi.pubSoftWareTweet(tweet, softid, new PublicTweetResponseHandler(getMainLooper(), tweet, KEY_SOFTWARE_TWEET)); } private void notifySimpleNotifycation(int id, String ticker, String title, String content, boolean ongoing, boolean autoCancel) { NotificationCompat.Builder builder = new NotificationCompat.Builder( this) .setTicker(ticker) .setContentTitle(title) .setContentText(content) .setAutoCancel(true) .setOngoing(false) .setOnlyAlertOnce(true) .setContentIntent( PendingIntent.getActivity(this, 0, new Intent(), 0)) .setSmallIcon(R.drawable.ic_notification); // if (AppContext.isNotificationSoundEnable()) { // builder.setDefaults(Notification.DEFAULT_SOUND); // } Notification notification = builder.build(); NotificationManagerCompat.from(this).notify(id, notification); } private void cancellNotification(int id) { NotificationManagerCompat.from(this).cancel(id); } }
ServerTaskUtils.java
package net.oschina.app.service; import net.oschina.app.bean.Tweet; import android.content.Context; import android.content.Intent; import android.os.Bundle; public class ServerTaskUtils { public static void publicBlogComment(Context context, PublicCommentTask task) { Intent intent = new Intent(ServerTaskService.ACTION_PUB_BLOG_COMMENT); Bundle bundle = new Bundle(); bundle.putParcelable(ServerTaskService.BUNDLE_PUB_COMMENT_TASK, task); intent.putExtras(bundle); context.startService(intent); } public static void publicNewsComment(Context context, PublicCommentTask task) { Intent intent = new Intent(ServerTaskService.ACTION_PUB_COMMENT); Bundle bundle = new Bundle(); bundle.putParcelable(ServerTaskService.BUNDLE_PUB_COMMENT_TASK, task); intent.putExtras(bundle); context.startService(intent); } public static void pubTweet(Context context, Tweet tweet) { Intent intent = new Intent(ServerTaskService.ACTION_PUB_TWEET); Bundle bundle = new Bundle(); bundle.putParcelable(ServerTaskService.BUNDLE_PUB_TWEET_TASK, tweet); intent.putExtras(bundle); context.startService(intent); } public static void pubSoftWareTweet(Context context, Tweet tweet, int softid) { Intent intent = new Intent(ServerTaskService.ACTION_PUB_SOFTWARE_TWEET); Bundle bundle = new Bundle(); bundle.putParcelable(ServerTaskService.BUNDLE_PUB_SOFTWARE_TWEET_TASK, tweet); bundle.putInt(ServerTaskService.KEY_SOFTID, softid); intent.putExtras(bundle); context.startService(intent); } public static void pubTweetComment(Context context, PublicCommentTask task) { Intent intent = new Intent(ServerTaskService.ACTION_PUB_COMMENT); Bundle bundle = new Bundle(); bundle.putParcelable(ServerTaskService.BUNDLE_PUB_COMMENT_TASK, task); intent.putExtras(bundle); context.startService(intent); } }
DynamicAdapter.java
package net.oschina.app.team.adapter; import net.oschina.app.R; import net.oschina.app.base.ListBaseAdapter; import net.oschina.app.team.bean.TeamActive; import net.oschina.app.ui.ImagePreviewActivity; import net.oschina.app.util.StringUtils; import net.oschina.app.widget.AvatarView; import net.oschina.app.widget.TweetTextView; import org.kymjs.kjframe.KJBitmap; import org.kymjs.kjframe.bitmap.BitmapCallBack; import org.kymjs.kjframe.bitmap.BitmapHelper; import android.content.Context; import android.graphics.Bitmap; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; /** * Team动态界面ListView适配器 (kymjs123@gmail.com) * * @author kymjs (https://github.com/kymjs) * */ public class DynamicAdapter extends ListBaseAdapter<TeamActive> { private final Context context; private final KJBitmap kjb = new KJBitmap(); public DynamicAdapter(Context cxt) { this.context = cxt; } static class ViewHolder { AvatarView img_head; TextView tv_name; TweetTextView tv_content; TextView tv_client; TextView tv_date; TextView tv_commit; TextView tv_title; ImageView iv_pic; } @Override protected View getRealView(int position, View v, ViewGroup parent) { super.getRealView(position, v, parent); ViewHolder holder = null; TeamActive data = mDatas.get(position); if (v == null || v.getTag() == null) { v = View.inflate(context, R.layout.list_cell_team_active, null); holder = new ViewHolder(); holder.img_head = (AvatarView) v .findViewById(R.id.event_listitem_userface); holder.tv_name = (TextView) v .findViewById(R.id.event_listitem_username); holder.tv_title = (TextView) v.findViewById(R.id.title); holder.tv_content = (TweetTextView) v .findViewById(R.id.event_listitem_content); holder.tv_client = (TextView) v .findViewById(R.id.event_listitem_client); holder.iv_pic = (ImageView) v.findViewById(R.id.iv_pic); holder.tv_date = (TextView) v .findViewById(R.id.event_listitem_date); holder.tv_commit = (TextView) v.findViewById(R.id.tv_comment_count); v.setTag(holder); } else { holder = (ViewHolder) v.getTag(); } holder.img_head.setAvatarUrl(data.getAuthor().getPortrait()); holder.img_head.setUserInfo(data.getAuthor().getId(), data.getAuthor() .getName()); holder.tv_name.setText(data.getAuthor().getName()); setContent(holder.tv_content, stripTags(data.getBody().getTitle())); String date = StringUtils.friendly_time2(data.getCreateTime()); String preDate = ""; if (position > 0) { preDate = StringUtils.friendly_time2(mDatas.get(position - 1) .getCreateTime()); } if (preDate.equals(date)) { holder.tv_title.setVisibility(View.GONE); } else { holder.tv_title.setText(date); holder.tv_title.setVisibility(View.VISIBLE); } holder.tv_content.setMaxLines(3); holder.tv_date.setText(StringUtils.friendly_time(data.getCreateTime())); holder.tv_commit.setText(data.getReply()); String imgPath = data.getBody().getImage(); if (!StringUtils.isEmpty(imgPath)) { holder.iv_pic.setVisibility(View.VISIBLE); setTweetImage(holder.iv_pic, imgPath); } else { holder.iv_pic.setVisibility(View.GONE); } return v; } /** * 移除字符串中的Html标签 * * @author kymjs (https://github.com/kymjs) * @param pHTMLString * @return */ public static String stripTags(final String pHTMLString) { // String str = pHTMLString.replaceAll("\\<.*?>", ""); String str = pHTMLString.replaceAll("\\t", ""); str = str.replaceAll("<\\s*img\\s+([^>]*)\\s*>", "").trim(); return str; } @Override public TeamActive getItem(int arg0) { super.getItem(arg0); return mDatas.get(arg0); } /** * 动态设置图片显示样式 * * @author kymjs */ private void setTweetImage(final ImageView pic, final String url) { pic.setVisibility(View.VISIBLE); kjb.display(pic, url, R.drawable.pic_bg, 0, 0, new BitmapCallBack() { @Override public void onSuccess(Bitmap bitmap) { super.onSuccess(bitmap); if (bitmap != null) { bitmap = BitmapHelper.scaleWithXY(bitmap, 360 / bitmap.getHeight()); pic.setImageBitmap(bitmap); } } }); pic.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { ImagePreviewActivity.showImagePrivew(context, 0, new String[] { url }); } }); } }
DiaryPagerAdapter.java
package net.oschina.app.team.adapter; import net.oschina.app.util.StringUtils; import net.oschina.app.widget.DiaryPageContentView; import android.content.Context; import android.support.v4.view.PagerAdapter; import android.view.View; import android.view.ViewGroup; /** * 周报ViewPager适配器 * * @author kymjs (http://www.kymjs.com) */ public class DiaryPagerAdapter extends PagerAdapter { private final Context cxt; private final int currentYear; private final int teamId; public DiaryPagerAdapter(Context cxt, int currentYear, int teamId) { this.currentYear = currentYear; this.cxt = cxt; this.teamId = teamId; } @Override public int getCount() { return currentYear == 2015 ? StringUtils.getWeekOfYear() : 52; } @Override public boolean isViewFromObject(View arg0, Object arg1) { return arg0 == arg1; } @Override public void destroyItem(ViewGroup container, int position, Object object) { container.removeView((View) object); } @Override public Object instantiateItem(ViewGroup container, int position) { View pagerView = new DiaryPageContentView(cxt, teamId, currentYear, position + 1).getView(); (container).addView(pagerView); return pagerView; } }
TeamDiscussAdapter.java
package net.oschina.app.team.adapter; import net.oschina.app.AppContext; import net.oschina.app.R; import net.oschina.app.base.ListBaseAdapter; import net.oschina.app.team.bean.TeamDiscuss; import net.oschina.app.util.HTMLUtil; import net.oschina.app.util.StringUtils; import net.oschina.app.util.TypefaceUtils; import net.oschina.app.widget.AvatarView; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import butterknife.ButterKnife; import butterknife.InjectView; /** * team 讨论区帖子 * * @author FireAnt(http://my.oschina.net/LittleDY) * @created 2014年10月9日 下午6:22:54 * */ public class TeamDiscussAdapter extends ListBaseAdapter<TeamDiscuss> { static class ViewHolder { @InjectView(R.id.tv_title) TextView title; @InjectView(R.id.tv_description) TextView description; @InjectView(R.id.tv_author) TextView author; @InjectView(R.id.tv_date) TextView time; @InjectView(R.id.tv_count) TextView comment_count; @InjectView(R.id.tv_vote_up) TextView vote_up; @InjectView(R.id.iv_face) public AvatarView face; public ViewHolder(View view) { ButterKnife.inject(this, view); } } @Override protected View getRealView(int position, View convertView, ViewGroup parent) { ViewHolder vh = null; if (convertView == null || convertView.getTag() == null) { convertView = getLayoutInflater(parent.getContext()).inflate( R.layout.list_cell_team_discuss, null); vh = new ViewHolder(convertView); convertView.setTag(vh); } else { vh = (ViewHolder) convertView.getTag(); } TeamDiscuss item = mDatas.get(position); vh.face.setUserInfo(item.getAuthor().getId(), item.getAuthor() .getName()); vh.face.setAvatarUrl(item.getAuthor().getPortrait()); vh.title.setText(item.getTitle()); String body = item.getBody().trim(); vh.description.setVisibility(View.GONE); if (null != body || !StringUtils.isEmpty(body)) { vh.description.setVisibility(View.VISIBLE); vh.description.setText(HTMLUtil.replaceTag(item.getBody()).trim()); } TypefaceUtils.setTypeface(vh.author, item.getAuthor().getName()); String faTime = AppContext.getInstance().getResources().getString(R.string.fa_clock_o); TypefaceUtils.setTypeface(vh.time, faTime + " " + StringUtils.friendly_time(item.getCreateTime())); String faVoteUp = AppContext.getInstance().getResources().getString(R.string.fa_thumbs_o_up); TypefaceUtils.setTypeface(vh.vote_up, faVoteUp + " " + item.getVoteUp()); String commentCount = AppContext.getInstance().getResources().getString(R.string.fa_comment); TypefaceUtils.setTypeface(vh.comment_count, commentCount + " " + item.getAnswerCount()); return convertView; } }
MainActivity.java
package net.oschina.app.ui; import net.oschina.app.AppConfig; import net.oschina.app.AppContext; import net.oschina.app.AppManager; import net.oschina.app.R; import net.oschina.app.bean.Constants; import net.oschina.app.bean.Notice; import net.oschina.app.bean.SimpleBackPage; import net.oschina.app.cache.DataCleanManager; import net.oschina.app.fragment.MyInformationFragment; import net.oschina.app.interf.BaseViewInterface; import net.oschina.app.interf.OnTabReselectListener; import net.oschina.app.service.NoticeUtils; import net.oschina.app.util.UIHelper; import net.oschina.app.util.UpdateManager; import net.oschina.app.widget.BadgeView; import net.oschina.app.widget.MyFragmentTabHost; import android.annotation.SuppressLint; import android.annotation.TargetApi; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.graphics.drawable.Drawable; import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.support.v4.app.Fragment; import android.support.v4.widget.DrawerLayout; import android.support.v7.app.ActionBar; import android.support.v7.app.ActionBarActivity; import android.util.TypedValue; import android.view.Gravity; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; import android.view.MotionEvent; import android.view.View; import android.view.View.OnTouchListener; import android.widget.TabHost.OnTabChangeListener; import android.widget.TabHost.TabContentFactory; import android.widget.TabHost.TabSpec; import android.widget.TextView; import butterknife.ButterKnife; import butterknife.InjectView; import com.networkbench.agent.impl.NBSAppAgent; @SuppressLint("InflateParams") @TargetApi(Build.VERSION_CODES.HONEYCOMB) public class MainActivity extends ActionBarActivity implements NavigationDrawerFragment.NavigationDrawerCallbacks, OnTabChangeListener, BaseViewInterface, View.OnClickListener, OnTouchListener { private DoubleClickExitHelper mDoubleClickExit; /** * Fragment managing the behaviors, interactions and presentation of the * navigation drawer. */ private NavigationDrawerFragment mNavigationDrawerFragment; @InjectView(android.R.id.tabhost) public MyFragmentTabHost mTabHost; private BadgeView mBvNotice; public static Notice mNotice; private BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if (intent.getAction().equals(Constants.INTENT_ACTION_NOTICE)) { mNotice = (Notice) intent.getSerializableExtra("notice_bean"); int atmeCount = mNotice.getAtmeCount();// @我 int msgCount = mNotice.getMsgCount();// 留言 int reviewCount = mNotice.getReviewCount();// 评论 int newFansCount = mNotice.getNewFansCount();// 新粉丝 int newLikeCount = mNotice.getNewLikeCount();// 收到赞 int activeCount = atmeCount + reviewCount + msgCount + newFansCount + newLikeCount; Fragment fragment = getCurrentFragment(); if (fragment instanceof MyInformationFragment) { ((MyInformationFragment) fragment).setNotice(); } else { if (activeCount > 0) { mBvNotice.setText(activeCount + ""); mBvNotice.show(); } else { mBvNotice.hide(); mNotice = null; } } } else if (intent.getAction() .equals(Constants.INTENT_ACTION_LOGOUT)) { mBvNotice.hide(); mNotice = null; } } }; /** * Used to store the last screen title. For use in * {@link #restoreActionBar()}. */ private CharSequence mTitle; @InjectView(R.id.quick_option_iv) View mAddBt; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ButterKnife.inject(this); initView(); AppManager.getAppManager().addActivity(this); handleIntent(getIntent()); // 注册听云的检测分析 NBSAppAgent.setLicenseKey("0ed0cc66c5cb45c0a91c6fa932ca99ac") .withCrashReportEnabled(true).withLocationServiceEnabled(true) .start(this); } @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); handleIntent(intent); } /** * 处理传进来的intent * * @author 火蚁 2015-1-28 下午3:48:44 * * @return void * @param intent */ private void handleIntent(Intent intent) { if (intent == null) return; String action = intent.getAction(); if (action != null && action.equals(Intent.ACTION_VIEW)) { UIHelper.showUrlRedirect(this, intent.getDataString()); } else if (intent.getBooleanExtra("NOTICE", false)) { notifitcationBarClick(intent); } } /** * 从通知栏点击的时候相应 * * @param fromWhich */ private void notifitcationBarClick(Intent fromWhich) { if (fromWhich != null) { boolean fromNoticeBar = fromWhich.getBooleanExtra("NOTICE", false); if (fromNoticeBar) { Intent toMyInfor = new Intent(this, SimpleBackActivity.class); toMyInfor.putExtra(SimpleBackActivity.BUNDLE_KEY_PAGE, SimpleBackPage.MY_MES.getValue()); startActivity(toMyInfor); } } } @Override public void initView() { mDoubleClickExit = new DoubleClickExitHelper(this); mNavigationDrawerFragment = (NavigationDrawerFragment) getSupportFragmentManager() .findFragmentById(R.id.navigation_drawer); mTitle = getTitle(); // Set up the drawer. mNavigationDrawerFragment.setUp(R.id.navigation_drawer, (DrawerLayout) findViewById(R.id.drawer_layout)); mTabHost.setup(this, getSupportFragmentManager(), R.id.realtabcontent); if (android.os.Build.VERSION.SDK_INT > 10) { mTabHost.getTabWidget().setShowDividers(0); } initTabs(); // 中间按键图片触发 mAddBt.setOnClickListener(this); mTabHost.setCurrentTab(0); mTabHost.setOnTabChangedListener(this); IntentFilter filter = new IntentFilter(Constants.INTENT_ACTION_NOTICE); filter.addAction(Constants.INTENT_ACTION_LOGOUT); registerReceiver(mReceiver, filter); NoticeUtils.bindToService(this); if (AppContext.isFristStart()) { mNavigationDrawerFragment.openDrawerMenu(); DataCleanManager.cleanInternalCache(AppContext.getInstance()); AppContext.setFristStart(false); } checkUpdate(); } private void checkUpdate() { if (!AppContext.get(AppConfig.KEY_CHECK_UPDATE, true)) { return; } Handler handler = new Handler(); handler.postDelayed(new Runnable() { @Override public void run() { new UpdateManager(MainActivity.this, false).checkUpdate(); } }, 2000); } @Override protected void onDestroy() { super.onDestroy(); NoticeUtils.unbindFromService(this); unregisterReceiver(mReceiver); mReceiver = null; NoticeUtils.tryToShutDown(this); } @Override public void initData() { } private void initTabs() { MainTab[] tabs = MainTab.values(); final int size = tabs.length; for (int i = 0; i < size; i++) { MainTab mainTab = tabs[i]; TabSpec tab = mTabHost.newTabSpec(getString(mainTab.getResName())); View indicator = LayoutInflater.from(getApplicationContext()) .inflate(R.layout.tab_indicator, null); TextView title = (TextView) indicator.findViewById(R.id.tab_title); Drawable drawable = this.getResources().getDrawable( mainTab.getResIcon()); title.setCompoundDrawablesWithIntrinsicBounds(null, drawable, null, null); if (i == 2) { indicator.setVisibility(View.INVISIBLE); mTabHost.setNoTabChangedTag(getString(mainTab.getResName())); } title.setText(getString(mainTab.getResName())); tab.setIndicator(indicator); tab.setContent(new TabContentFactory() { @Override public View createTabContent(String tag) { return new View(MainActivity.this); } }); mTabHost.addTab(tab, mainTab.getClz(), null); if (mainTab.equals(MainTab.ME)) { View cn = indicator.findViewById(R.id.tab_mes); mBvNotice = new BadgeView(MainActivity.this, cn); mBvNotice.setBadgePosition(BadgeView.POSITION_TOP_RIGHT); mBvNotice.setTextSize(TypedValue.COMPLEX_UNIT_SP, 10); mBvNotice.setBackgroundResource(R.drawable.notification_bg); mBvNotice.setGravity(Gravity.CENTER); } mTabHost.getTabWidget().getChildAt(i).setOnTouchListener(this); } } @Override public void onNavigationDrawerItemSelected(int position) { // update the main content by replacing fragments } public void restoreActionBar() { ActionBar actionBar = getSupportActionBar(); actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD); actionBar.setDisplayShowTitleEnabled(true); actionBar.setTitle(mTitle); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.main_activity_menu, menu); if (!mNavigationDrawerFragment.isDrawerOpen()) { restoreActionBar(); return true; } return super.onCreateOptionsMenu(menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { int id = item.getItemId(); switch (id) { case R.id.search: UIHelper.showSimpleBack(this, SimpleBackPage.SEARCH); break; default: break; } return super.onOptionsItemSelected(item); } @Override public void onTabChanged(String tabId) { final int size = mTabHost.getTabWidget().getTabCount(); for (int i = 0; i < size; i++) { View v = mTabHost.getTabWidget().getChildAt(i); if (i == mTabHost.getCurrentTab()) { v.setSelected(true); } else { v.setSelected(false); } } if (tabId.equals(getString(MainTab.ME.getResName()))) { mBvNotice.setText(""); mBvNotice.hide(); } supportInvalidateOptionsMenu(); } @Override public void onClick(View v) { int id = v.getId(); switch (id) { // 点击了快速操作按钮 case R.id.quick_option_iv: showQuickOption(); break; default: break; } } // 显示快速操作界面 private void showQuickOption() { final QuickOptionDialog dialog = new QuickOptionDialog( MainActivity.this); dialog.setCancelable(true); dialog.setCanceledOnTouchOutside(true); dialog.show(); } @SuppressLint("ClickableViewAccessibility") @Override public boolean onTouch(View v, MotionEvent event) { super.onTouchEvent(event); boolean consumed = false; // use getTabHost().getCurrentTabView to decide if the current tab is // touched again if (event.getAction() == MotionEvent.ACTION_DOWN && v.equals(mTabHost.getCurrentTabView())) { // use getTabHost().getCurrentView() to get a handle to the view // which is displayed in the tab - and to get this views context Fragment currentFragment = getCurrentFragment(); if (currentFragment != null && currentFragment instanceof OnTabReselectListener) { OnTabReselectListener listener = (OnTabReselectListener) currentFragment; listener.onTabReselect(); consumed = true; } } return consumed; } private Fragment getCurrentFragment() { return getSupportFragmentManager().findFragmentByTag( mTabHost.getCurrentTabTag()); } /** * 监听返回--是否退出程序 */ @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK) { // 是否退出应用 if (AppContext.get(AppConfig.KEY_DOUBLE_CLICK_EXIT, true)) { return mDoubleClickExit.onKeyDown(keyCode, event); } } return super.onKeyDown(keyCode, event); } @Override protected void onSaveInstanceState(Bundle outState) { // TODO Auto-generated method stub // 当 API Level > 11 调用这个方法可能导致奔溃(android.os.Build.VERSION.SDK_INT > 11) } }
MainTab.java
package net.oschina.app.ui; import net.oschina.app.R; import net.oschina.app.fragment.ExploreFragment; import net.oschina.app.fragment.MyInformationFragment; import net.oschina.app.viewpagerfragment.NewsViewPagerFragment; import net.oschina.app.viewpagerfragment.TweetsViewPagerFragment; public enum MainTab { NEWS(0, R.string.main_tab_name_news, R.drawable.tab_icon_new, NewsViewPagerFragment.class), TWEET(1, R.string.main_tab_name_tweet, R.drawable.tab_icon_tweet, TweetsViewPagerFragment.class), QUICK(2, R.string.main_tab_name_quick, R.drawable.tab_icon_new, null), EXPLORE(3, R.string.main_tab_name_explore, R.drawable.tab_icon_explore, ExploreFragment.class), ME(4, R.string.main_tab_name_my, R.drawable.tab_icon_me, MyInformationFragment.class); private int idx; private int resName; private int resIcon; private Class<?> clz; private MainTab(int idx, int resName, int resIcon, Class<?> clz) { this.idx = idx; this.resName = resName; this.resIcon = resIcon; this.clz = clz; } public int getIdx() { return idx; } public void setIdx(int idx) { this.idx = idx; } public int getResName() { return resName; } public void setResName(int resName) { this.resName = resName; } public int getResIcon() { return resIcon; } public void setResIcon(int resIcon) { this.resIcon = resIcon; } public Class<?> getClz() { return clz; } public void setClz(Class<?> clz) { this.clz = clz; } }
DetailActivity.java
package net.oschina.app.ui; import net.oschina.app.R; import net.oschina.app.base.BaseActivity; import net.oschina.app.base.BaseDetailFragment; import net.oschina.app.base.BaseFragment; import net.oschina.app.emoji.KJEmojiFragment; import net.oschina.app.emoji.OnSendClickListener; import net.oschina.app.emoji.ToolbarFragment; import net.oschina.app.emoji.ToolbarFragment.OnActionClickListener; import net.oschina.app.emoji.ToolbarFragment.ToolAction; import net.oschina.app.fragment.BlogDetailFragment; import net.oschina.app.fragment.EventDetailFragment; import net.oschina.app.fragment.NewsDetailFragment; import net.oschina.app.fragment.PostDetailFragment; import net.oschina.app.fragment.SoftwareDetailFragment; import net.oschina.app.fragment.TweetDetailFragment; import net.oschina.app.team.fragment.TeamDiaryDetail; import net.oschina.app.team.fragment.TeamDiscussDetailFragment; import net.oschina.app.team.fragment.TeamIssueDetailFragment; import net.oschina.app.team.fragment.TeamTweetDetailFragment; import android.os.Bundle; import android.support.v4.app.FragmentTransaction; import android.text.Editable; import android.view.KeyEvent; import android.view.View; /** * 详情activity(包括:资讯、博客、软件、问答、动弹) * * @author FireAnt(http://my.oschina.net/LittleDY) * @created 2014年10月11日 上午11:18:41 * */ public class DetailActivity extends BaseActivity implements OnSendClickListener { public static final int DISPLAY_NEWS = 0; public static final int DISPLAY_BLOG = 1; public static final int DISPLAY_SOFTWARE = 2; public static final int DISPLAY_POST = 3; public static final int DISPLAY_TWEET = 4; public static final int DISPLAY_EVENT = 5; public static final int DISPLAY_TEAM_ISSUE_DETAIL = 6; public static final int DISPLAY_TEAM_DISCUSS_DETAIL = 7; public static final int DISPLAY_TEAM_TWEET_DETAIL = 8; public static final int DISPLAY_TEAM_DIARY = 9; public static final String BUNDLE_KEY_DISPLAY_TYPE = "BUNDLE_KEY_DISPLAY_TYPE"; private OnSendClickListener currentFragment; public KJEmojiFragment emojiFragment = new KJEmojiFragment(); public ToolbarFragment toolFragment = new ToolbarFragment(); @Override protected int getLayoutId() { return R.layout.activity_detail; } @Override protected boolean hasBackButton() { return true; } @Override protected int getActionBarTitle() { return R.string.actionbar_title_detail; } @Override protected void init(Bundle savedInstanceState) { super.init(savedInstanceState); int displayType = getIntent().getIntExtra(BUNDLE_KEY_DISPLAY_TYPE, DISPLAY_NEWS); BaseFragment fragment = null; int actionBarTitle = 0; switch (displayType) { case DISPLAY_NEWS: actionBarTitle = R.string.actionbar_title_news; fragment = new NewsDetailFragment(); break; case DISPLAY_BLOG: actionBarTitle = R.string.actionbar_title_blog; fragment = new BlogDetailFragment(); break; case DISPLAY_SOFTWARE: actionBarTitle = R.string.actionbar_title_software; fragment = new SoftwareDetailFragment(); break; case DISPLAY_POST: actionBarTitle = R.string.actionbar_title_question; fragment = new PostDetailFragment(); break; case DISPLAY_TWEET: actionBarTitle = R.string.actionbar_title_tweet; fragment = new TweetDetailFragment(); break; case DISPLAY_EVENT: actionBarTitle = R.string.actionbar_title_event_detail; fragment = new EventDetailFragment(); break; case DISPLAY_TEAM_ISSUE_DETAIL: actionBarTitle = R.string.team_issue_detail; fragment = new TeamIssueDetailFragment(); break; case DISPLAY_TEAM_DISCUSS_DETAIL: actionBarTitle = R.string.actionbar_title_question; fragment = new TeamDiscussDetailFragment(); break; case DISPLAY_TEAM_TWEET_DETAIL: actionBarTitle = R.string.actionbar_dynamic_detail; fragment = new TeamTweetDetailFragment(); break; case DISPLAY_TEAM_DIARY: actionBarTitle = R.string.team_diary_detail; fragment = new TeamDiaryDetail(); break; default: break; } setActionBarTitle(actionBarTitle); FragmentTransaction trans = getSupportFragmentManager() .beginTransaction(); trans.replace(R.id.container, fragment); trans.commitAllowingStateLoss(); if (fragment instanceof OnSendClickListener) { currentFragment = (OnSendClickListener) fragment; } else { currentFragment = new OnSendClickListener() { @Override public void onClickSendButton(Editable str) {} @Override public void onClickFlagButton() {} }; } } @Override public void onClick(View v) {} @Override public void initView() { if (currentFragment instanceof TweetDetailFragment || currentFragment instanceof TeamTweetDetailFragment || currentFragment instanceof TeamDiaryDetail || currentFragment instanceof TeamIssueDetailFragment || currentFragment instanceof TeamDiscussDetailFragment) { getSupportFragmentManager().beginTransaction() .replace(R.id.emoji_keyboard, emojiFragment).commit(); } else { getSupportFragmentManager().beginTransaction() .replace(R.id.emoji_keyboard, toolFragment).commit(); } toolFragment.setOnActionClickListener(new OnActionClickListener() { @Override public void onActionClick(ToolAction action) { switch (action) { case ACTION_CHANGE: case ACTION_WRITE_COMMENT: getSupportFragmentManager() .beginTransaction() .setCustomAnimations(R.anim.footer_menu_slide_in, R.anim.footer_menu_slide_out) .replace(R.id.emoji_keyboard, emojiFragment) .commit(); break; case ACTION_FAVORITE: ((BaseDetailFragment) currentFragment) .handleFavoriteOrNot(); break; case ACTION_REPORT: ((BaseDetailFragment) currentFragment).onReportMenuClick(); break; case ACTION_SHARE: ((BaseDetailFragment) currentFragment).handleShare(); break; case ACTION_VIEW_COMMENT: ((BaseDetailFragment) currentFragment) .onclickWriteComment(); break; default: break; } } }); } @Override public void initData() {} @Override public void onClickSendButton(Editable str) { currentFragment.onClickSendButton(str); } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK) { try { if (emojiFragment.isShowEmojiKeyBoard()) { emojiFragment.hideAllKeyBoard(); return true; } if (emojiFragment.getEditText().getTag() != null) { emojiFragment.getEditText().setTag(null); emojiFragment.getEditText().setHint("说点什么吧"); return true; } } catch (NullPointerException e) { } } return super.onKeyDown(keyCode, event); } public void setCommentCount(int count) { try { toolFragment.setCommentCount(count); } catch (Exception e) { } } @Override public void onClickFlagButton() { getSupportFragmentManager() .beginTransaction() .setCustomAnimations(R.anim.footer_menu_slide_in, R.anim.footer_menu_slide_out) .replace(R.id.emoji_keyboard, toolFragment).commit(); try { toolFragment.setCommentCount(((BaseDetailFragment) currentFragment) .getCommentCount()); } catch (Exception e) { } } }
DoubleClickExitHelper.java
package net.oschina.app.ui; import net.oschina.app.AppManager; import net.oschina.app.R; import android.app.Activity; import android.os.Handler; import android.os.Looper; import android.view.KeyEvent; import android.widget.Toast; /*** * 双击退出 * @author FireAnt(http://my.oschina.net/LittleDY) * @created 2015年1月5日 下午7:07:44 * */ public class DoubleClickExitHelper { private final Activity mActivity; private boolean isOnKeyBacking; private Handler mHandler; private Toast mBackToast; public DoubleClickExitHelper(Activity activity) { mActivity = activity; mHandler = new Handler(Looper.getMainLooper()); } /** * Activity onKeyDown事件 * */ public boolean onKeyDown(int keyCode, KeyEvent event) { if(keyCode != KeyEvent.KEYCODE_BACK) { return false; } if(isOnKeyBacking) { mHandler.removeCallbacks(onBackTimeRunnable); if(mBackToast != null){ mBackToast.cancel(); } // 退出 AppManager.getAppManager().AppExit(mActivity); return true; } else { isOnKeyBacking = true; if(mBackToast == null) { mBackToast = Toast.makeText(mActivity, R.string.tip_double_click_exit, 2000); } mBackToast.show(); mHandler.postDelayed(onBackTimeRunnable, 2000); return true; } } private Runnable onBackTimeRunnable = new Runnable() { @Override public void run() { isOnKeyBacking = false; if(mBackToast != null){ mBackToast.cancel(); } } }; }
EventLocationActivity.java
package net.oschina.app.ui; import net.oschina.app.AppContext; import net.oschina.app.R; import net.oschina.app.base.BaseActivity; import android.annotation.SuppressLint; import android.annotation.TargetApi; import android.content.Intent; import android.os.Build; import android.os.Bundle; import android.view.View; import android.widget.TextView; import com.baidu.location.BDLocation; import com.baidu.location.BDLocationListener; import com.baidu.location.LocationClient; import com.baidu.location.LocationClientOption; import com.baidu.mapapi.SDKInitializer; import com.baidu.mapapi.map.BaiduMap; import com.baidu.mapapi.map.BitmapDescriptorFactory; import com.baidu.mapapi.map.InfoWindow; import com.baidu.mapapi.map.InfoWindow.OnInfoWindowClickListener; import com.baidu.mapapi.map.MapStatusUpdate; import com.baidu.mapapi.map.MapStatusUpdateFactory; import com.baidu.mapapi.map.MapView; import com.baidu.mapapi.map.Marker; import com.baidu.mapapi.map.MarkerOptions; import com.baidu.mapapi.model.LatLng; import com.baidu.mapapi.navi.BaiduMapAppNotSupportNaviException; import com.baidu.mapapi.navi.BaiduMapNavigation; import com.baidu.mapapi.navi.NaviPara; import com.baidu.mapapi.search.core.SearchResult; import com.baidu.mapapi.search.geocode.GeoCodeOption; import com.baidu.mapapi.search.geocode.GeoCodeResult; import com.baidu.mapapi.search.geocode.GeoCoder; import com.baidu.mapapi.search.geocode.OnGetGeoCoderResultListener; import com.baidu.mapapi.search.geocode.ReverseGeoCodeResult; /** * 活动地图位置显示 * * @author FireAnt(http://my.oschina.net/LittleDY) * @created 2014年12月15日 下午1:28:28 * */ @SuppressLint("InflateParams") @TargetApi(Build.VERSION_CODES.HONEYCOMB) public class EventLocationActivity extends BaseActivity implements OnGetGeoCoderResultListener { GeoCoder mSearch = null; // 搜索模块,也可去掉地图模块独立使用 BaiduMap mBaiduMap = null; MapView mMapView = null; private String mCity; private String mLocation; @Override protected boolean hasBackButton() { return true; } @Override protected int getActionBarTitle() { return R.string.actionbar_title_event_location; } protected void onCreate(Bundle savedInstanceState) { SDKInitializer.initialize(getApplicationContext()); super.onCreate(savedInstanceState); } @Override protected int getLayoutId() { return R.layout.fragment_event_location; } @Override protected void onPause() { mMapView.onPause(); super.onPause(); } @Override protected void onResume() { mMapView.onResume(); super.onResume(); } @Override protected void onDestroy() { mMapView.onDestroy(); mSearch.destroy(); super.onDestroy(); } @Override public void onGetGeoCodeResult(GeoCodeResult result) { if (result == null || result.error != SearchResult.ERRORNO.NO_ERROR) { AppContext.showToast("抱歉,未能找到结果"); return; } mBaiduMap.clear(); final LatLng location = result.getLocation(); final Marker marker = (Marker) mBaiduMap .addOverlay(new MarkerOptions() .position(location) .icon(BitmapDescriptorFactory .fromResource(R.drawable.icon_gcoding)) .draggable(true)); mBaiduMap.setMapStatus(MapStatusUpdateFactory.newLatLng(result .getLocation())); MapStatusUpdate msu = MapStatusUpdateFactory.zoomTo(14.0f); mBaiduMap.setMapStatus(msu); View view = mInflater.inflate(R.layout.event_spot_pupwindow, null, false); TextView spot = (TextView) view.findViewById(R.id.tv_spot); spot.setText(mLocation); OnInfoWindowClickListener listener = new OnInfoWindowClickListener() { public void onInfoWindowClick() { onClickInfoWindow(location); } }; InfoWindow mInfoWindow = new InfoWindow( BitmapDescriptorFactory.fromView(view), location, -80, listener); mBaiduMap.showInfoWindow(mInfoWindow); } @Override public void onGetReverseGeoCodeResult(ReverseGeoCodeResult result) { if (result == null || result.error != SearchResult.ERRORNO.NO_ERROR) { return; } mBaiduMap.clear(); mBaiduMap.addOverlay(new MarkerOptions().position(result.getLocation()) .icon(BitmapDescriptorFactory .fromResource(R.drawable.icon_gcoding))); mBaiduMap.setMapStatus(MapStatusUpdateFactory.newLatLng(result .getLocation())); } @Override public void onClick(View v) { } private void onClickInfoWindow(final LatLng location) { // 开启定位图层 mBaiduMap.setMyLocationEnabled(true); // 定位初始化 final LocationClient mLocClient = new LocationClient( EventLocationActivity.this); mLocClient.registerLocationListener(new BDLocationListener() { @Override public void onReceivePoi(BDLocation arg0) { } @Override public void onReceiveLocation(BDLocation arg0) { mLocClient.stop(); LatLng start = new LatLng(arg0.getLatitude(), arg0 .getLongitude()); startNavi(start, location); } }); LocationClientOption option = new LocationClientOption(); option.setOpenGps(true);// 打开gps option.setCoorType("bd09ll"); // 设置坐标类型 option.setScanSpan(1000); mLocClient.setLocOption(option); mLocClient.start(); } /** * 开始导航 * * @param view */ private void startNavi(LatLng pt1, LatLng pt2) { // 构建 导航参数 NaviPara para = new NaviPara(); para.startPoint = pt1; para.endPoint = pt2; try { BaiduMapNavigation.openBaiduMapNavi(para, this); } catch (BaiduMapAppNotSupportNaviException e) { AppContext.showToast("抱歉,你的百度地图暂不支持打开导航"); } } @Override public void initView() { // 地图初始化 mMapView = (MapView) findViewById(R.id.bmapView); mBaiduMap = mMapView.getMap(); // 初始化搜索模块,注册事件监听 mSearch = GeoCoder.newInstance(); mSearch.setOnGetGeoCodeResultListener(this); Intent intent = getIntent(); mCity = intent.getStringExtra("city"); mLocation = intent.getStringExtra("location"); // Geo搜索 mSearch.geocode(new GeoCodeOption().city(mCity).address(mLocation)); } @Override public void initData() { } }
package net.oschina.app.ui; import net.oschina.app.AppConfig; import net.oschina.app.AppContext; import net.oschina.app.R; import net.oschina.app.adapter.RecyclingPagerAdapter; import net.oschina.app.base.BaseActivity; import net.oschina.app.bean.SimpleBackPage; import net.oschina.app.fragment.TweetPubFragment; import net.oschina.app.ui.dialog.ImageMenuDialog; import net.oschina.app.ui.dialog.ImageMenuDialog.OnMenuClickListener; import net.oschina.app.util.TDevice; import net.oschina.app.util.UIHelper; import net.oschina.app.widget.HackyViewPager; import org.kymjs.kjframe.KJBitmap; import org.kymjs.kjframe.bitmap.BitmapCallBack; import uk.co.senab.photoview.PhotoView; import uk.co.senab.photoview.PhotoViewAttacher.OnPhotoTapListener; import android.annotation.SuppressLint; import android.content.Context; import android.content.Intent; import android.graphics.drawable.ColorDrawable; import android.os.Bundle; import android.support.v4.view.ViewPager.OnPageChangeListener; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.ProgressBar; import android.widget.TextView; /** * 图片预览界面 * * @author kymjs */ public class ImagePreviewActivity extends BaseActivity implements OnPageChangeListener { public static final String BUNDLE_KEY_IMAGES = "bundle_key_images"; private static final String BUNDLE_KEY_INDEX = "bundle_key_index"; private HackyViewPager mViewPager; private SamplePagerAdapter mAdapter; private TextView mTvImgIndex; private ImageView mIvMore; private int mCurrentPostion = 0; private String[] mImageUrls; private KJBitmap kjb; public static void showImagePrivew(Context context, int index, String[] images) { Intent intent = new Intent(context, ImagePreviewActivity.class); intent.putExtra(BUNDLE_KEY_IMAGES, images); intent.putExtra(BUNDLE_KEY_INDEX, index); context.startActivity(intent); } @Override protected boolean hasActionBar() { getActionBar().hide(); return true; } @Override protected int getLayoutId() { return R.layout.activity_image_preview; } @Override protected void init(Bundle savedInstanceState) { super.init(savedInstanceState); kjb = new KJBitmap(); mViewPager = (HackyViewPager) findViewById(R.id.view_pager); mImageUrls = getIntent().getStringArrayExtra(BUNDLE_KEY_IMAGES); int index = getIntent().getIntExtra(BUNDLE_KEY_INDEX, 0); mAdapter = new SamplePagerAdapter(mImageUrls); mViewPager.setAdapter(mAdapter); mViewPager.setOnPageChangeListener(this); mViewPager.setCurrentItem(index); mTvImgIndex = (TextView) findViewById(R.id.tv_img_index); mIvMore = (ImageView) findViewById(R.id.iv_more); mIvMore.setOnClickListener(this); onPageSelected(index); } @Override public void onClick(View v) { int id = v.getId(); switch (id) { case R.id.iv_more: showOptionMenu(); break; default: break; } } @Override public void initView() {} @Override public void initData() {} private void showOptionMenu() { final ImageMenuDialog dialog = new ImageMenuDialog(this); dialog.show(); dialog.setCancelable(true); dialog.setOnMenuClickListener(new OnMenuClickListener() { @Override public void onClick(TextView menuItem) { if (menuItem.getId() == R.id.menu1) { saveImg(); } else if (menuItem.getId() == R.id.menu2) { sendTweet(); } else if (menuItem.getId() == R.id.menu3) { copyUrl(); } dialog.dismiss(); } }); } /** * 复制链接 */ private void copyUrl() { String content = null; if (mAdapter != null && mAdapter.getCount() > 0) { content = mAdapter.getItem(mCurrentPostion); TDevice.copyTextToBoard(content); AppContext.showToastShort("已复制到剪贴板"); } } /** * 发送到动弹 */ private void sendTweet() { if (mAdapter != null && mAdapter.getCount() > 0) { String imgUrl = mAdapter.getItem(mCurrentPostion); Bundle bundle = new Bundle(); bundle.putString(TweetPubFragment.FROM_IMAGEPAGE_KEY, imgUrl); UIHelper.showSimpleBack(this, SimpleBackPage.TWEET_PUB, bundle); finish(); } } /** * 保存图片 */ private void saveImg() { if (mAdapter != null && mAdapter.getCount() > 0) { final String imgUrl = mAdapter.getItem(mCurrentPostion); final String filePath = AppConfig.DEFAULT_SAVE_IMAGE_PATH + getFileName(imgUrl); kjb.saveImage(this, imgUrl, filePath); AppContext.showToastShort(getString(R.string.tip_save_image_suc, filePath)); } else { AppContext.showToastShort(R.string.tip_save_image_faile); } } private String getFileName(String imgUrl) { int index = imgUrl.lastIndexOf('/') + 1; if (index == -1) { return System.currentTimeMillis() + ".jpeg"; } return imgUrl.substring(index); } @Override public void onPageScrollStateChanged(int arg0) {} @Override public void onPageScrolled(int arg0, float arg1, int arg2) {} @Override public void onPageSelected(int idx) { mCurrentPostion = idx; if (mImageUrls != null && mImageUrls.length > 1) { if (mTvImgIndex != null) { mTvImgIndex.setText((mCurrentPostion + 1) + "/" + mImageUrls.length); } } } class SamplePagerAdapter extends RecyclingPagerAdapter { private String[] images = new String[] {}; SamplePagerAdapter(String[] images) { this.images = images; } public String getItem(int position) { return images[position]; } @Override public int getCount() { return images.length; } @Override @SuppressLint("InflateParams") public View getView(int position, View convertView, ViewGroup container) { ViewHolder vh = null; if (convertView == null) { convertView = LayoutInflater.from(container.getContext()) .inflate(R.layout.image_preview_item, null); vh = new ViewHolder(convertView); convertView.setTag(vh); } else { vh = (ViewHolder) convertView.getTag(); } vh.image.setOnFinishListener(new OnPhotoTapListener() { @Override public void onPhotoTap(View view, float x, float y) { ImagePreviewActivity.this.finish(); } }); final ProgressBar bar = vh.progress; KJBitmap kjbitmap = new KJBitmap(); kjbitmap.displayWithDefWH(vh.image, images[position], new ColorDrawable(0x000000), new ColorDrawable(0x000000), new BitmapCallBack() { @Override public void onPreLoad() { super.onPreLoad(); bar.setVisibility(View.VISIBLE); } @Override public void onFinish() { super.onFinish(); bar.setVisibility(View.GONE); } @Override public void onFailure(Exception arg0) { AppContext.showToast(R.string.tip_load_image_faile); } }); return convertView; } } static class ViewHolder { PhotoView image; ProgressBar progress; ViewHolder(View view) { image = (PhotoView) view.findViewById(R.id.photoview); progress = (ProgressBar) view.findViewById(R.id.progress); } } }
package net.oschina.app.ui; import java.io.ByteArrayInputStream; import net.oschina.app.AppConfig; import net.oschina.app.AppContext; import net.oschina.app.R; import net.oschina.app.api.ApiHttpClient; import net.oschina.app.api.remote.OSChinaApi; import net.oschina.app.base.BaseActivity; import net.oschina.app.bean.Constants; import net.oschina.app.bean.LoginUserBean; import net.oschina.app.bean.Result; import net.oschina.app.util.CyptoUtils; import net.oschina.app.util.SimpleTextWatcher; import net.oschina.app.util.StringUtils; import net.oschina.app.util.TDevice; import net.oschina.app.util.TLog; import net.oschina.app.util.XmlUtils; import org.apache.http.Header; import org.apache.http.client.CookieStore; import org.apache.http.client.protocol.ClientContext; import org.apache.http.cookie.Cookie; import org.apache.http.protocol.HttpContext; import org.kymjs.kjframe.http.HttpConfig; import org.kymjs.kjframe.utils.KJLoger; import android.content.Intent; import android.text.TextUtils; import android.text.TextWatcher; import android.view.View; import android.widget.Button; import android.widget.EditText; import butterknife.InjectView; import com.loopj.android.http.AsyncHttpClient; import com.loopj.android.http.AsyncHttpResponseHandler; import com.tencent.tauth.IUiListener; import com.tencent.tauth.Tencent; import com.tencent.tauth.UiError; /** * 用户登录界面 * * @author kymjs (http://www.kymjs.com/) */ public class LoginActivity extends BaseActivity { public static final int REQUEST_CODE_INIT = 0; private static final String BUNDLE_KEY_REQUEST_CODE = "BUNDLE_KEY_REQUEST_CODE"; protected static final String TAG = LoginActivity.class.getSimpleName(); @InjectView(R.id.et_username) EditText mEtUserName; @InjectView(R.id.et_password) EditText mEtPassword; @InjectView(R.id.iv_clear_username) View mIvClearUserName; @InjectView(R.id.iv_clear_password) View mIvClearPassword; @InjectView(R.id.btn_login) Button mBtnLogin; @InjectView(R.id.qq_login) Button mBtnQQLogin; private final int requestCode = REQUEST_CODE_INIT; private String mUserName; private String mPassword; private Tencent mTencent; private final TextWatcher mUserNameWatcher = new SimpleTextWatcher() { @Override public void onTextChanged(CharSequence s, int start, int before, int count) { mIvClearUserName .setVisibility(TextUtils.isEmpty(s) ? View.INVISIBLE : View.VISIBLE); } }; private final TextWatcher mPassswordWatcher = new SimpleTextWatcher() { @Override public void onTextChanged(CharSequence s, int start, int before, int count) { mIvClearPassword .setVisibility(TextUtils.isEmpty(s) ? View.INVISIBLE : View.VISIBLE); } }; @Override protected int getLayoutId() { return R.layout.activity_login; } @Override protected boolean hasBackButton() { return true; } @Override protected int getActionBarTitle() { return R.string.login; } @Override public void onClick(View v) { int id = v.getId(); switch (id) { case R.id.iv_clear_username: mEtUserName.getText().clear(); mEtUserName.requestFocus(); break; case R.id.iv_clear_password: mEtPassword.getText().clear(); mEtPassword.requestFocus(); break; case R.id.btn_login: handleLogin(); break; case R.id.qq_login: qqLogin(); break; default: break; } } private void handleLogin() { if (!prepareForLogin()) { return; } // if the data has ready mUserName = mEtUserName.getText().toString(); mPassword = mEtPassword.getText().toString(); showWaitDialog(R.string.progress_login); OSChinaApi.login(mUserName, mPassword, mHandler); } private final AsyncHttpResponseHandler mHandler = new AsyncHttpResponseHandler() { @Override public void onSuccess(int arg0, Header[] arg1, byte[] arg2) { try { AsyncHttpClient client = ApiHttpClient.getHttpClient(); HttpContext httpContext = client.getHttpContext(); CookieStore cookies = (CookieStore) httpContext .getAttribute(ClientContext.COOKIE_STORE); if (cookies != null) { String tmpcookies = ""; for (Cookie c : cookies.getCookies()) { TLog.log(TAG, "cookie:" + c.getName() + " " + c.getValue()); tmpcookies += (c.getName() + "=" + c.getValue()) + ";"; } TLog.log(TAG, "cookies:" + tmpcookies); AppContext.getInstance().setProperty(AppConfig.CONF_COOKIE, tmpcookies); ApiHttpClient.setCookie(ApiHttpClient.getCookie(AppContext .getInstance())); HttpConfig.sCookie = tmpcookies; } LoginUserBean user = XmlUtils.toBean(LoginUserBean.class, new ByteArrayInputStream(arg2)); Result res = user.getResult(); if (res.OK()) { // 保存登录信息 user.getUser().setAccount(mUserName); user.getUser().setPwd(mPassword); user.getUser().setRememberMe(true); AppContext.getInstance().saveUserInfo(user.getUser()); hideWaitDialog(); handleLoginSuccess(); } else { AppContext.getInstance().cleanLoginInfo(); hideWaitDialog(); AppContext.showToast(res.getErrorMessage()); } } catch (Exception e) { e.printStackTrace(); onFailure(arg0, arg1, arg2, e); } } @Override public void onFailure(int arg0, Header[] arg1, byte[] arg2, Throwable arg3) { hideWaitDialog(); AppContext.showToast(R.string.tip_login_error_for_network); } }; private void handleLoginSuccess() { Intent data = new Intent(); data.putExtra(BUNDLE_KEY_REQUEST_CODE, requestCode); setResult(RESULT_OK, data); this.sendBroadcast(new Intent(Constants.INTENT_ACTION_USER_CHANGE)); finish(); } private boolean prepareForLogin() { if (!TDevice.hasInternet()) { AppContext.showToastShort(R.string.tip_no_internet); return false; } String uName = mEtUserName.getText().toString(); if (StringUtils.isEmpty(uName)) { AppContext.showToastShort(R.string.tip_please_input_username); mEtUserName.requestFocus(); return false; } // 去除邮箱正确性检测 // if (!StringUtils.isEmail(uName)) { // AppContext.showToastShort(R.string.tip_illegal_email); // mEtUserName.requestFocus(); // return false; // } String pwd = mEtPassword.getText().toString(); if (StringUtils.isEmpty(pwd)) { AppContext.showToastShort(R.string.tip_please_input_password); mEtPassword.requestFocus(); return false; } return true; } @Override public void initView() { mIvClearUserName.setOnClickListener(this); mIvClearPassword.setOnClickListener(this); mBtnLogin.setOnClickListener(this); mBtnQQLogin.setOnClickListener(this); mEtUserName.addTextChangedListener(mUserNameWatcher); mEtPassword.addTextChangedListener(mPassswordWatcher); } @Override public void initData() { mTencent = Tencent.createInstance(AppConfig.APP_QQ_KEY, this.getApplicationContext()); mEtUserName.setText(AppContext.getInstance() .getProperty("user.account")); mEtPassword.setText(CyptoUtils.decode("oschinaApp", AppContext .getInstance().getProperty("user.pwd"))); } /** * QQ登陆 */ private void qqLogin() { if (!mTencent.isSessionValid()) { mTencent.login(this, "all", new AuthorListener()); } } // /** // * 封装并返回QQ登陆数据 // */ // private User packQQLoginBean(User user, JSONObject obj) { // user.setLoginType(QQ_LOGIN); // if (obj.has("openid")) { // user.setUserId(obj.optString("openid")); // } else { // user.setUserName(obj.optString("nickname")); // user.setSex("男".equals(obj.optString("gender")) ? 1 : 2); // user.setHeadUrl(obj.optString("figureurl_qq_1")); // user.setPwd(user.getUserId()); // } // return user; // } class AuthorListener implements IUiListener { @Override public void onCancel() { KJLoger.debug(getClass().getName() + "用户取消登陆"); } @Override public void onComplete(Object arg0) { // packQQLoginBean(user, obj); AppContext.showToast("成功"); // 服务器端暂无 } @Override public void onError(UiError error) { KJLoger.debug(getClass().getName() + "登陆失败" + error.errorDetail); } } }
package net.oschina.app.ui; import net.oschina.app.AppContext; import net.oschina.app.R; import net.oschina.app.util.QrCodeUtils; import org.kymjs.kjframe.utils.FileUtils; import android.annotation.SuppressLint; import android.app.Dialog; import android.content.Context; import android.graphics.Bitmap; import android.os.Bundle; import android.view.Gravity; import android.view.View; import android.view.View.OnLongClickListener; import android.view.Window; import android.widget.ImageView; import com.google.zxing.WriterException; public class MyQrodeDialog extends Dialog { private ImageView mIvCode; private Bitmap bitmap; private MyQrodeDialog(Context context, boolean flag, OnCancelListener listener) { super(context, flag, listener); } @SuppressLint("InflateParams") private MyQrodeDialog(Context context, int defStyle) { super(context, defStyle); View contentView = getLayoutInflater().inflate( R.layout.dialog_my_qr_code, null); mIvCode = (ImageView) contentView.findViewById(R.id.iv_qr_code); try { bitmap = QrCodeUtils.Create2DCode(String.format( "http://my.oschina.net/u/%s", AppContext.getInstance() .getLoginUid())); mIvCode.setImageBitmap(bitmap); } catch (WriterException e) { e.printStackTrace(); } requestWindowFeature(Window.FEATURE_NO_TITLE); contentView.setOnLongClickListener(new OnLongClickListener() { @Override public boolean onLongClick(View v) { dismiss(); if (FileUtils.bitmapToFile(bitmap, FileUtils.getSavePath("OSChina") + "/myqrcode.png")) { AppContext.showToast("二维码已保存到oschina文件夹下"); } else { AppContext.showToast("SD卡不可写,二维码保存失败"); } return false; } }); super.setContentView(contentView); } public MyQrodeDialog(Context context) { this(context, R.style.quick_option_dialog); } @Override protected void onCreate(Bundle bundle) { super.onCreate(bundle); getWindow().setGravity(Gravity.CENTER); } }
package net.oschina.app.ui; import net.oschina.app.AppManager; import net.oschina.app.R; import net.oschina.app.base.BaseFragment; import net.oschina.app.bean.SimpleBackPage; import net.oschina.app.util.TDevice; import net.oschina.app.util.UIHelper; import net.oschina.app.widget.ActionBarDrawerToggle; import net.oschina.app.widget.DrawerArrowDrawable; import android.app.Activity; import android.content.res.Configuration; import android.os.Bundle; import android.support.v4.view.GravityCompat; import android.support.v4.widget.DrawerLayout; import android.support.v7.app.ActionBar; import android.support.v7.app.ActionBarActivity; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import butterknife.ButterKnife; import butterknife.InjectView; /** * 侧滑菜单界面 * * @author FireAnt(http://my.oschina.net/LittleDY) * @created 2014年9月25日 下午6:00:05 * */ public class NavigationDrawerFragment extends BaseFragment implements OnClickListener { /** * Remember the position of the selected item. */ private static final String STATE_SELECTED_POSITION = "selected_navigation_drawer_position"; /** * A pointer to the current callbacks instance (the Activity). */ private NavigationDrawerCallbacks mCallbacks; /** * Helper component that ties the action bar to the navigation drawer. */ private ActionBarDrawerToggle mDrawerToggle; private DrawerArrowDrawable drawerArrow; private DrawerLayout mDrawerLayout; private View mDrawerListView; private View mFragmentContainerView; private int mCurrentSelectedPosition = 0; private boolean mFromSavedInstanceState; @InjectView(R.id.menu_item_quests) View mMenu_item_quests; @InjectView(R.id.menu_item_opensoft) View mMenu_item_opensoft; @InjectView(R.id.menu_item_blog) View mMenu_item_blog; @InjectView(R.id.menu_item_gitapp) View mMenu_item_gitapp; @InjectView(R.id.menu_item_rss) View mMenu_item_rss; @InjectView(R.id.menu_item_setting) View mMenu_item_setting; @InjectView(R.id.menu_item_exit) View mMenu_item_exit; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (savedInstanceState != null) { mCurrentSelectedPosition = savedInstanceState .getInt(STATE_SELECTED_POSITION); mFromSavedInstanceState = true; } selectItem(mCurrentSelectedPosition); } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); setHasOptionsMenu(true); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { mDrawerListView = inflater.inflate(R.layout.fragment_navigation_drawer, container, false); mDrawerListView.setOnClickListener(this); ButterKnife.inject(this, mDrawerListView); initView(mDrawerListView); initData(); return mDrawerListView; } @Override public void onClick(View v) { int id = v.getId(); switch (id) { case R.id.menu_item_quests: UIHelper.showSimpleBack(getActivity(), SimpleBackPage.QUEST); break; case R.id.menu_item_opensoft: UIHelper.showSimpleBack(getActivity(), SimpleBackPage.OPENSOURCE_SOFTWARE); break; case R.id.menu_item_blog: UIHelper.showSimpleBack(getActivity(), SimpleBackPage.BLOG); break; case R.id.menu_item_gitapp: boolean res = TDevice.openAppActivity(getActivity(), "net.oschina.gitapp", "net.oschina.gitapp.WelcomePage"); if (!res) { if (!TDevice.isHaveMarket(getActivity())) { UIHelper.openSysBrowser(getActivity(), "http://git.oschina.net/appclient"); } else { TDevice.gotoMarket(getActivity(), "net.oschina.gitapp"); } } break; case R.id.menu_item_rss: break; case R.id.menu_item_setting: UIHelper.showSetting(getActivity()); break; case R.id.menu_item_exit: AppManager.getAppManager().AppExit(getActivity()); break; default: break; } mDrawerLayout.postDelayed(new Runnable() { @Override public void run() { mDrawerLayout.closeDrawers(); } }, 800); } @Override public void initView(View view) { mMenu_item_rss.setOnClickListener(this); mMenu_item_opensoft.setOnClickListener(this); mMenu_item_blog.setOnClickListener(this); mMenu_item_quests.setOnClickListener(this); mMenu_item_setting.setOnClickListener(this); mMenu_item_exit.setOnClickListener(this); mMenu_item_gitapp.setOnClickListener(this); } @Override public void initData() { } public boolean isDrawerOpen() { return mDrawerLayout != null && mDrawerLayout.isDrawerOpen(mFragmentContainerView); } /** * Users of this fragment must call this method to set up the navigation * drawer interactions. * * @param fragmentId * The android:id of this fragment in its activity's layout. * @param drawerLayout * The DrawerLayout containing this fragment's UI. */ public void setUp(int fragmentId, DrawerLayout drawerLayout) { mFragmentContainerView = getActivity().findViewById(fragmentId); mDrawerLayout = drawerLayout; // set a custom shadow that overlays the main content when the drawer // opens mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START); // set up the drawer's list view with items and click listener ActionBar actionBar = getActionBar(); actionBar.setDisplayHomeAsUpEnabled(true); actionBar.setHomeButtonEnabled(true); drawerArrow = new DrawerArrowDrawable(getActivity()) { @Override public boolean isLayoutRtl() { return false; } }; mDrawerToggle = new ActionBarDrawerToggle(getActivity(), mDrawerLayout, drawerArrow, R.string.navigation_drawer_open, R.string.navigation_drawer_close) { public void onDrawerClosed(View view) { super.onDrawerClosed(view); getActivity().invalidateOptionsMenu(); } public void onDrawerOpened(View drawerView) { super.onDrawerOpened(drawerView); getActivity().invalidateOptionsMenu(); } }; mDrawerLayout.post(new Runnable() { @Override public void run() { mDrawerToggle.syncState(); } }); mDrawerLayout.setDrawerListener(mDrawerToggle); } public void openDrawerMenu() { mDrawerLayout.openDrawer(mFragmentContainerView); } private void selectItem(int position) { mCurrentSelectedPosition = position; if (mDrawerLayout != null) { mDrawerLayout.closeDrawer(mFragmentContainerView); } if (mCallbacks != null) { mCallbacks.onNavigationDrawerItemSelected(position); } } @Override public void onAttach(Activity activity) { super.onAttach(activity); try { mCallbacks = (NavigationDrawerCallbacks) activity; } catch (ClassCastException e) { throw new ClassCastException( "Activity must implement NavigationDrawerCallbacks."); } } @Override public void onDetach() { super.onDetach(); mCallbacks = null; } @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putInt(STATE_SELECTED_POSITION, mCurrentSelectedPosition); } @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); mDrawerToggle.onConfigurationChanged(newConfig); } @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { super.onCreateOptionsMenu(menu, inflater); } @Override public boolean onOptionsItemSelected(MenuItem item) { if (mDrawerToggle.onOptionsItemSelected(item)) { return true; } return super.onOptionsItemSelected(item); } private ActionBar getActionBar() { return ((ActionBarActivity) getActivity()).getSupportActionBar(); } public static interface NavigationDrawerCallbacks { void onNavigationDrawerItemSelected(int position); } }
package net.oschina.app.ui; import net.oschina.app.R; import net.oschina.app.bean.SimpleBackPage; import net.oschina.app.fragment.TweetPubFragment; import net.oschina.app.team.fragment.NoteEditFragment; import net.oschina.app.util.UIHelper; import android.annotation.SuppressLint; import android.app.Dialog; import android.content.Context; import android.os.Bundle; import android.view.Display; import android.view.Gravity; import android.view.MotionEvent; import android.view.View; import android.view.Window; import android.view.WindowManager; import android.view.animation.Animation; import android.view.animation.AnimationUtils; import android.view.animation.LinearInterpolator; import android.widget.ImageView; public class QuickOptionDialog extends Dialog implements android.view.View.OnClickListener { private ImageView mClose; public interface OnQuickOptionformClick { void onQuickOptionClick(int id); } private OnQuickOptionformClick mListener; private QuickOptionDialog(Context context, boolean flag, OnCancelListener listener) { super(context, flag, listener); } @SuppressLint("InflateParams") private QuickOptionDialog(Context context, int defStyle) { super(context, defStyle); View contentView = getLayoutInflater().inflate( R.layout.dialog_quick_option, null); contentView.findViewById(R.id.ly_quick_option_text).setOnClickListener( this); contentView.findViewById(R.id.ly_quick_option_album) .setOnClickListener(this); contentView.findViewById(R.id.ly_quick_option_photo) .setOnClickListener(this); contentView.findViewById(R.id.ly_quick_option_voice) .setOnClickListener(this); contentView.findViewById(R.id.ly_quick_option_scan).setOnClickListener( this); contentView.findViewById(R.id.ly_quick_option_note).setOnClickListener( this); mClose = (ImageView) contentView.findViewById(R.id.iv_close); Animation operatingAnim = AnimationUtils.loadAnimation(getContext(), R.anim.quick_option_close); LinearInterpolator lin = new LinearInterpolator(); operatingAnim.setInterpolator(lin); mClose.startAnimation(operatingAnim); mClose.setOnClickListener(this); requestWindowFeature(Window.FEATURE_NO_TITLE); contentView.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { QuickOptionDialog.this.dismiss(); return true; } }); super.setContentView(contentView); } public QuickOptionDialog(Context context) { this(context, R.style.quick_option_dialog); } @SuppressWarnings("deprecation") @Override protected void onCreate(Bundle bundle) { super.onCreate(bundle); getWindow().setGravity(Gravity.BOTTOM); WindowManager m = getWindow().getWindowManager(); Display d = m.getDefaultDisplay(); WindowManager.LayoutParams p = getWindow().getAttributes(); p.width = d.getWidth(); getWindow().setAttributes(p); } public void setOnQuickOptionformClickListener(OnQuickOptionformClick lis) { mListener = lis; } @Override public void onClick(View v) { final int id = v.getId(); switch (id) { case R.id.iv_close: dismiss(); break; case R.id.ly_quick_option_text: onClickTweetPub(R.id.ly_quick_option_text); break; case R.id.ly_quick_option_album: onClickTweetPub(R.id.ly_quick_option_album); break; case R.id.ly_quick_option_photo: onClickTweetPub(R.id.ly_quick_option_photo); break; case R.id.ly_quick_option_voice: UIHelper.showSimpleBack(getContext(), SimpleBackPage.RECORD); break; case R.id.ly_quick_option_scan: UIHelper.showScanActivity(getContext()); break; case R.id.ly_quick_option_note: // UIHelper.showSimpleBack(getContext(), SimpleBackPage.FIND_USER); onClickNote(); //UIHelper.showSimpleBack(getContext(), SimpleBackPage.FIND_USER); // onClickNote(); break; default: break; } if (mListener != null) { mListener.onQuickOptionClick(id); } dismiss(); } private void onClickTweetPub(int id) { Bundle bundle = new Bundle(); int type = -1; switch (id) { case R.id.ly_quick_option_album: type = TweetPubFragment.ACTION_TYPE_ALBUM; break; case R.id.ly_quick_option_photo: type = TweetPubFragment.ACTION_TYPE_PHOTO; break; default: break; } bundle.putInt(TweetPubFragment.ACTION_TYPE, type); UIHelper.showTweetActivity(getContext(), SimpleBackPage.TWEET_PUB, bundle); } private void onClickNote() { Bundle bundle = new Bundle(); bundle.putInt(NoteEditFragment.NOTE_FROMWHERE_KEY, NoteEditFragment.QUICK_DIALOG); UIHelper.showSimpleBack(getContext(), SimpleBackPage.NOTE_EDIT, bundle); } }
package net.oschina.app.ui; import net.oschina.app.R; import net.oschina.app.bean.Report; import net.oschina.app.ui.dialog.CommonDialog; import net.oschina.app.ui.dialog.DialogHelper; import net.oschina.app.util.TDevice; import android.annotation.SuppressLint; import android.content.Context; import android.view.View; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.EditText; import android.widget.TextView; public class ReportDialog extends CommonDialog implements android.view.View.OnClickListener { private static final int MAX_CONTENT_LENGTH = 250; private TextView mTvReason; private TextView mTvLink; private EditText mEtContent; private String[] reasons; private String mLink; private int mReportId; public ReportDialog(Context context, String link, int reportId) { this(context, R.style.dialog_common, link, reportId); } private ReportDialog(Context context, int defStyle, String link, int reportId) { super(context, defStyle); mLink = link; mReportId = reportId; initViews(context); } private ReportDialog(Context context, boolean flag, OnCancelListener listener) { super(context, flag, listener); } @SuppressLint("InflateParams") private void initViews(Context context) { reasons = getContext().getResources().getStringArray( R.array.report_reason); View view = getLayoutInflater() .inflate(R.layout.dialog_report, null); mTvReason = (TextView) view.findViewById(R.id.tv_reason); mTvReason.setOnClickListener(this); mTvReason.setText(reasons[0]); mTvLink = (TextView) view.findViewById(R.id.tv_link); mTvLink.setText(mLink); mEtContent = (EditText) view.findViewById(R.id.et_content); super.setContent(view, 0); } @Override public void onClick(View v) { if (v.getId() == R.id.tv_reason) { selectReason(); } } private void selectReason() { String reason = mTvReason.getText().toString(); int idx = 0; for (int i = 0; i < reasons.length; i++) { if (reasons[i].equals(reason)) { idx = i; break; } } final CommonDialog dialog = DialogHelper .getPinterestDialogCancelable(getContext()); dialog.setTitle(R.string.report_reson); dialog.setItems(reasons, idx, new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { dialog.dismiss(); mTvReason.setText(reasons[position]); } }); dialog.setNegativeButton(R.string.cancle, null); dialog.show(); } public Report getReport() { String text = mEtContent.getText().toString(); TDevice.hideSoftKeyboard(mEtContent); Report report = new Report(); report.setReportId(mReportId); report.setLinkAddress(mLink); report.setReason(mTvReason.getText().toString()); report.setOtherReason(text); return report; } }
package net.oschina.app.ui; import net.oschina.app.R; import net.oschina.app.ui.dialog.CommonDialog; import android.annotation.SuppressLint; import android.content.Context; import android.os.Bundle; import android.view.Display; import android.view.Gravity; import android.view.View; import android.view.WindowManager; /** * 分享界面dialog * * @author kymjs * */ public class ShareDialog extends CommonDialog implements android.view.View.OnClickListener { public interface OnSharePlatformClick { void onPlatformClick(int id); } private OnSharePlatformClick mListener; private ShareDialog(Context context, boolean flag, OnCancelListener listener) { super(context, flag, listener); } @SuppressLint("InflateParams") private ShareDialog(Context context, int defStyle) { super(context, defStyle); View shareView = getLayoutInflater().inflate( R.layout.dialog_cotent_share, null); shareView.findViewById(R.id.ly_share_qq).setOnClickListener(this); shareView.findViewById(R.id.ly_share_copy_link) .setOnClickListener(this); shareView.findViewById(R.id.ly_share_more_option).setOnClickListener( this); shareView.findViewById(R.id.ly_share_sina_weibo).setOnClickListener( this); shareView.findViewById(R.id.ly_share_weichat).setOnClickListener(this); shareView.findViewById(R.id.ly_share_weichat_circle) .setOnClickListener(this); setContent(shareView, 0); } public ShareDialog(Context context) { this(context, R.style.dialog_bottom); } @SuppressWarnings("deprecation") @Override protected void onCreate(Bundle bundle) { super.onCreate(bundle); getWindow().setGravity(Gravity.BOTTOM); WindowManager m = getWindow().getWindowManager(); Display d = m.getDefaultDisplay(); WindowManager.LayoutParams p = getWindow().getAttributes(); p.width = d.getWidth(); getWindow().setAttributes(p); } public void setOnPlatformClickListener(OnSharePlatformClick lis) { mListener = lis; } @Override public void onClick(View v) { final int id = v.getId(); if (mListener != null) { mListener.onPlatformClick(id); } } }
package net.oschina.app.ui; import java.util.ArrayList; import net.oschina.app.bean.SimpleBackPage; import net.oschina.app.fragment.TweetPubFragment; import android.content.Intent; import android.database.Cursor; import android.net.Uri; import android.os.Bundle; import android.provider.MediaStore; /** * 对动弹界面的一个封装,用于相应系统分享 * * @author kymjs (https://github.com/kymjs) * */ public class TweetActivity extends SimpleBackActivity { private TweetPubFragment currentFragment; public static String FROM_KEY = "image_shared_key"; @Override protected void onCreate(Bundle savedInstanceState) { Intent intent = getIntent(); if (intent.getIntExtra(FROM_KEY, -1) != 1) { mPageValue = SimpleBackPage.TWEET_PUB.getValue(); } super.onCreate(savedInstanceState); respondExternal(intent); } /** * 响应从图片分享进入的事件 * * @param intent */ private void respondExternal(Intent intent) { currentFragment = (TweetPubFragment) mFragment.get(); String action = intent.getAction(); String type = intent.getType(); if (Intent.ACTION_SEND.equals(action) && type != null) { if ("text/plain".equals(type)) { handleSendText(intent); // Handle text being sent } else if (type.startsWith("image/")) { handleSendImage(intent); // Handle single image being sent } } else if (Intent.ACTION_SEND_MULTIPLE.equals(action) && type != null) { if (type.startsWith("image/")) { handleSendMultipleImages(intent); // Handle multiple images // being sent } } else { // Handle other intents, such as being started from the home screen } } void handleSendText(Intent intent) { String sharedText = intent.getStringExtra(Intent.EXTRA_TEXT); String sharedTitle = intent.getStringExtra(Intent.EXTRA_TITLE); if (sharedText != null) { currentFragment.setContentText(sharedText); } } void handleSendImage(Intent intent) { Uri imageUri = (Uri) intent.getParcelableExtra(Intent.EXTRA_STREAM); if (imageUri != null) { currentFragment.setContentImage(getAbsoluteImagePath(imageUri)); } } void handleSendMultipleImages(Intent intent) { ArrayList<Uri> imageUris = intent .getParcelableArrayListExtra(Intent.EXTRA_STREAM); if (imageUris != null) { currentFragment.setContentImage(getAbsoluteImagePath(imageUris .get(0))); } } protected String getAbsoluteImagePath(Uri uri) { // can post image String[] proj = { MediaStore.Images.Media.DATA }; Cursor cursor = managedQuery(uri, proj, // Which columns to return null, // WHERE clause; which rows to return (all rows) null, // WHERE clause selection arguments (none) null); // Order-by clause (ascending by name) if (cursor != null) { int column_index = cursor .getColumnIndexOrThrow(MediaStore.Images.Media.DATA); cursor.moveToFirst(); return cursor.getString(column_index); } else { // 如果游标为空说明获取的已经是绝对路径了 return uri.getPath(); } } }
package net.oschina.app.ui.dialog; import net.oschina.app.R; import net.oschina.app.util.TDevice; import android.annotation.SuppressLint; import android.annotation.TargetApi; import android.app.Dialog; import android.content.Context; import android.content.DialogInterface; import android.os.Build; import android.os.Bundle; import android.text.Html; import android.text.Spanned; import android.text.TextUtils; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup.LayoutParams; import android.view.Window; import android.view.WindowManager; import android.widget.AdapterView; import android.widget.BaseAdapter; import android.widget.Button; import android.widget.FrameLayout; import android.widget.ListView; import android.widget.ScrollView; import android.widget.TextView; public class CommonDialog extends Dialog { public DialogInterface.OnClickListener listener; protected View barDivider; protected View buttonDivider; protected FrameLayout container; protected View content; private final int contentPadding; protected DialogTitleView headerVw; protected Button negativeBt; protected Button positiveBt; protected DialogInterface.OnClickListener dismissClick = new OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); } }; public CommonDialog(Context context) { this(context, R.style.dialog_common); } public CommonDialog(Context context, int defStyle) { super(context, defStyle); contentPadding = (int) getContext().getResources().getDimension( R.dimen.global_dialog_padding); init(context); } protected CommonDialog(Context context, boolean flag, DialogInterface.OnCancelListener listener) { super(context, flag, listener); contentPadding = (int) getContext().getResources().getDimension( R.dimen.global_dialog_padding); init(context); } @SuppressLint("InflateParams") @TargetApi(Build.VERSION_CODES.HONEYCOMB) protected void init(final Context context) { setCancelable(false); requestWindowFeature(Window.FEATURE_NO_TITLE); content = LayoutInflater.from(context).inflate( R.layout.dialog_common, null); headerVw = (DialogTitleView) content.findViewById(R.id.dialog_header); container = (FrameLayout) content.findViewById(R.id.content_container); barDivider = content.findViewById(R.id.button_bar_divider); buttonDivider = content.findViewById(R.id.button_divder); positiveBt = (Button) content.findViewById(R.id.positive_bt); negativeBt = (Button) content.findViewById(R.id.negative_bt); if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) { // TODO Check content view height and change height } else { // content.addOnLayoutChangeListener(new OnLayoutChangeListener() { // // @Override // public void onLayoutChange(View v, int left, int top, // int right, int bottom, int oldLeft, int oldTop, // int oldRight, int oldBottom) { // int height = v.getHeight(); // int contentHeight = container.getHeight(); // int winHeight = BaseApplication.getDisplaySize()[1]; // int needHeight = height - winHeight * 8 / 10; // if (needHeight > 0) { // container // .setLayoutParams(new LinearLayout.LayoutParams( // LayoutParams.MATCH_PARENT, // contentHeight - needHeight)); // } // } // }); } super.setContentView(content); } public TextView getTitleTextView() { return headerVw.titleTv; } @Override protected void onCreate(Bundle bundle) { super.onCreate(bundle); if (TDevice.isTablet()) { int maxWidth = (int) TDevice.dpToPixel(360f); if (maxWidth < TDevice.getScreenWidth()) { WindowManager.LayoutParams params = getWindow().getAttributes(); params.width = maxWidth; getWindow().setAttributes(params); } } } @Override public void onBackPressed() { super.onBackPressed(); this.dismiss(); } public void setContent(View view) { setContent(view, contentPadding); } public void setContent(View view, int padding) { container.removeAllViews(); container.setPadding(padding, padding, padding, padding); FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams( FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT); container.addView(view, lp); } @Override public void setContentView(int i) { setContent(null); } @Override public void setContentView(View view) { setContentView(null, null); } @Override public void setContentView(View view, android.view.ViewGroup.LayoutParams layoutparams) { throw new Error("Dialog: User setContent (View view) instead!"); } public void setItems(BaseAdapter adapter, AdapterView.OnItemClickListener onItemClickListener) { ListView listview = new ListView(content.getContext()); listview.setLayoutParams(new FrameLayout.LayoutParams(-1, -2)); listview.setDivider(null); listview.setAdapter(adapter); listview.setOnItemClickListener(onItemClickListener); setContent(listview, 0); } public void setItems(CharSequence[] items, AdapterView.OnItemClickListener onItemClickListener) { ListView listview = new ListView(content.getContext()); listview.setLayoutParams(new FrameLayout.LayoutParams(-1, -2)); listview.setAdapter(new DialogAdapter(items)); listview.setDivider(null); listview.setOnItemClickListener(onItemClickListener); setContent(listview, 0); } public void setItemsWithoutChk(CharSequence[] items, AdapterView.OnItemClickListener onItemClickListener) { ListView listview = new ListView(content.getContext()); listview.setLayoutParams(new FrameLayout.LayoutParams(-1, -2)); DialogAdapter adapter = new DialogAdapter(items); adapter.setShowChk(false); listview.setDivider(null); listview.setAdapter(adapter); listview.setOnItemClickListener(onItemClickListener); setContent(listview, 0); } public void setItems(CharSequence[] items, int index, AdapterView.OnItemClickListener onItemClickListener) { ListView listview = new ListView(content.getContext()); listview.setCacheColorHint(0); listview.setDivider(null); listview.setLayoutParams(new FrameLayout.LayoutParams( LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)); listview.setAdapter(new DialogAdapter(items, index)); listview.setOnItemClickListener(onItemClickListener); setContent(listview, 0); } public void setMessage(int resId) { setMessage(getContext().getResources().getString(resId)); } public void setMessage(Spanned spanned) { ScrollView scrollView = new ScrollView(getContext()); scrollView.setLayoutParams(new FrameLayout.LayoutParams( FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.WRAP_CONTENT)); TextView tvMessage = new TextView(getContext(), null, R.style.dialog_pinterest_text); tvMessage.setLayoutParams(new FrameLayout.LayoutParams( FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.WRAP_CONTENT)); tvMessage.setPadding(contentPadding, contentPadding, contentPadding, contentPadding); tvMessage.setLineSpacing(0.0F, 1.3F); tvMessage.setText(spanned); tvMessage.setTextColor(getContext().getResources().getColor( R.color.black)); ScrollView.LayoutParams lp = new ScrollView.LayoutParams( ScrollView.LayoutParams.MATCH_PARENT, ScrollView.LayoutParams.WRAP_CONTENT); scrollView.addView(tvMessage, lp); setContent(scrollView, 0); } public void setMessage(String message) { setMessage(Html.fromHtml(message)); } public void setNegativeButton(int negative, DialogInterface.OnClickListener listener) { setNegativeButton(getContext().getString(negative), listener); } public void setNegativeButton(String text, final DialogInterface.OnClickListener listener) { if (!TextUtils.isEmpty(text)) { negativeBt.setText(text); negativeBt.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { if (listener != null) listener.onClick(CommonDialog.this, 0); else dismissClick.onClick(CommonDialog.this, 0); } }); negativeBt.setVisibility(View.VISIBLE); if (positiveBt.getVisibility() == View.VISIBLE) buttonDivider.setVisibility(View.VISIBLE); } else { negativeBt.setVisibility(View.GONE); buttonDivider.setVisibility(View.GONE); } if (positiveBt.getVisibility() == View.VISIBLE || negativeBt.getVisibility() == View.VISIBLE) barDivider.setVisibility(View.VISIBLE); else barDivider.setVisibility(View.GONE); } public void setPositiveButton(int positive, DialogInterface.OnClickListener listener) { setPositiveButton(getContext().getString(positive), listener); } public void setPositiveButton(String positive, final DialogInterface.OnClickListener listener) { if (!TextUtils.isEmpty(positive)) { positiveBt.setText(positive); positiveBt.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { if (listener != null) listener.onClick(CommonDialog.this, 0); else dismissClick.onClick(CommonDialog.this, 0); } }); positiveBt.setVisibility(View.VISIBLE); if (negativeBt.getVisibility() == View.VISIBLE) buttonDivider.setVisibility(View.VISIBLE); } else { positiveBt.setVisibility(View.GONE); buttonDivider.setVisibility(View.GONE); } if (positiveBt.getVisibility() == View.VISIBLE || negativeBt.getVisibility() == View.VISIBLE) barDivider.setVisibility(View.VISIBLE); else barDivider.setVisibility(View.GONE); } public void setSubTitle(int i) { setSubTitle((getContext().getResources().getString(i))); } public void setSubTitle(CharSequence subtitle) { if (subtitle != null && subtitle.length() > 0) { headerVw.subTitleTv.setText(subtitle); headerVw.subTitleTv.setVisibility(View.VISIBLE); } else { headerVw.subTitleTv.setVisibility(View.GONE); } } @Override public void setTitle(int title) { setTitle((getContext().getResources().getString(title))); } @Override public void setTitle(CharSequence title) { if (title != null && title.length() > 0) { headerVw.titleTv.setText(title); headerVw.setVisibility(View.VISIBLE); } else { headerVw.setVisibility(View.GONE); } } }
package net.oschina.app.ui.dialog; import net.oschina.app.R; import net.oschina.app.util.TDevice; import net.oschina.app.util.TLog; import android.animation.Animator; import android.animation.Animator.AnimatorListener; import android.animation.ObjectAnimator; import android.annotation.TargetApi; import android.app.Activity; import android.content.Context; import android.os.Build; import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.ViewGroup; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.TextView; @TargetApi(Build.VERSION_CODES.HONEYCOMB) public class CommonToast { public static final long DURATION_LONG = 5000L; public static final long DURATION_MEDIUM = 3500L; public static final long DURATION_SHORT = 2500L; private long _duration = 3500l; private ToastView _toastVw; public CommonToast(Activity activity) { init(activity); } public CommonToast(Activity activity, String message, int icon, String action, int actionIcon, long l) { _duration = l; init(activity); setMessage(message); setMessageIc(icon); setAction(action); setActionIc(actionIcon); } private void init(Activity activity) { _toastVw = new ToastView(activity); setLayoutGravity(81); } public long getDuration() { return _duration; } public void setAction(String s) { _toastVw.actionTv.setText(s); } public void setActionIc(int i) { _toastVw.actionIv.setImageResource(i); } public void setDuration(long l) { _duration = l; } public void setLayoutGravity(int i) { if (i != 0) { FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(-2, -2); params.gravity = i; int j = (int) TDevice.dpToPixel(16F); params.setMargins(j, j, j, j); _toastVw.setLayoutParams(params); } } public void setMessage(String s) { _toastVw.messageTv.setText(s); } public void setMessageIc(int i) { _toastVw.messageIc.setImageResource(i); } public void show() { final ViewGroup content = (ViewGroup) ((Activity) _toastVw.getContext()) .findViewById(android.R.id.content); if (content != null) { ObjectAnimator.ofFloat(_toastVw, "alpha", 0.0F).setDuration(0L) .start(); content.addView(_toastVw); ObjectAnimator.ofFloat(_toastVw, "alpha", 0.0F, 1.0F) .setDuration(167L).start(); _toastVw.postDelayed(new Runnable() { @Override public void run() { ObjectAnimator animator = ObjectAnimator.ofFloat(_toastVw, "alpha", 1.0F, 0.0F); animator.setDuration(100L); animator.addListener(new AnimatorListener() { @Override public void onAnimationStart(Animator animation) { // TODO Auto-generated method stub } @Override public void onAnimationRepeat(Animator animation) { // TODO Auto-generated method stub } @Override public void onAnimationEnd(Animator animation) { content.removeView(_toastVw); } @Override public void onAnimationCancel(Animator animation) { } }); animator.start(); } }, _duration); } else { TLog.error("Toast not shown! Content view is null!"); } } private class ToastView extends FrameLayout { public ImageView actionIv; public TextView actionTv; public ImageView messageIc; public TextView messageTv; public ToastView(Context context) { this(context, null); } public ToastView(Context context, AttributeSet attributeset) { this(context, attributeset, 0); } public ToastView(Context context, AttributeSet attributeset, int i) { super(context, attributeset, i); init(); } private void init() { LayoutInflater.from(getContext()).inflate( R.layout.view_base_toast, this, true); messageTv = (TextView) findViewById(R.id.title_tv); messageIc = (ImageView) findViewById(R.id.icon_iv); actionTv = (TextView) findViewById(R.id.title_tv); actionIv = (ImageView) findViewById(R.id.icon_iv); } } }
package net.oschina.app.ui.dialog; import net.oschina.app.R; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.RadioButton; import android.widget.TextView; public class DialogAdapter extends BaseAdapter { private CharSequence[] _items; private int select; private boolean showChk = true; public DialogAdapter(CharSequence[] items, int selectIdx) { _items = items; this.select = selectIdx; } public DialogAdapter(CharSequence[] items) { _items = items; } @Override public int getCount() { return _items.length; } @Override public String getItem(int i) { return _items[i].toString();// super.getItem(i); } @Override public long getItemId(int i) { return i; } @Override public View getView(int i, View view, ViewGroup viewgroup) { DialogHolder vh = null; if (view == null) { vh = new DialogHolder(); view = LayoutInflater.from(viewgroup.getContext()).inflate( R.layout.list_cell_dialog, null, false); vh.titleTv = (TextView) view.findViewById(R.id.title_tv); vh.divider = view.findViewById(R.id.list_divider); vh.checkIv = (RadioButton) view.findViewById(R.id.rb_select); view.setTag(vh); } else { vh = (DialogHolder) view.getTag(); } vh.titleTv.setText(getItem(i)); if (i == -1 + getCount()) { vh.divider.setVisibility(View.GONE); } else { vh.divider.setVisibility(View.VISIBLE); } if(showChk) { vh.checkIv.setVisibility(View.VISIBLE); if (select == i) { vh.checkIv.setChecked(true); } else { vh.checkIv.setChecked(false); } } else{ vh.checkIv.setVisibility(View.GONE); } return view; } public boolean isShowChk() { return showChk; } public void setShowChk(boolean showChk) { this.showChk = showChk; } private class DialogHolder { public View divider; public TextView titleTv; public RadioButton checkIv; } }
package net.oschina.app.ui.dialog; public interface DialogControl { public abstract void hideWaitDialog(); public abstract WaitDialog showWaitDialog(); public abstract WaitDialog showWaitDialog(int resid); public abstract WaitDialog showWaitDialog(String text); }
package net.oschina.app.ui.dialog; import net.oschina.app.R; import android.app.Activity; import android.content.Context; public class DialogHelper { public static CommonDialog getPinterestDialog(Context context) { return new CommonDialog(context, R.style.dialog_common); } public static CommonDialog getPinterestDialogCancelable(Context context) { CommonDialog dialog = new CommonDialog(context, R.style.dialog_common); dialog.setCanceledOnTouchOutside(true); return dialog; } public static WaitDialog getWaitDialog(Activity activity, int message) { WaitDialog dialog = null; try { dialog = new WaitDialog(activity, R.style.dialog_waiting); dialog.setMessage(message); } catch (Exception e) { e.printStackTrace(); } return dialog; } public static WaitDialog getWaitDialog(Activity activity, String message) { WaitDialog dialog = null; try { dialog = new WaitDialog(activity, R.style.dialog_waiting); dialog.setMessage(message); } catch (Exception ex) { ex.printStackTrace(); } return dialog; } public static WaitDialog getCancelableWaitDialog(Activity activity, String message) { WaitDialog dialog = null; try { dialog = new WaitDialog(activity, R.style.dialog_waiting); dialog.setMessage(message); dialog.setCancelable(true); } catch (Exception ex) { ex.printStackTrace(); } return dialog; } }
package net.oschina.app.ui.dialog; import net.oschina.app.R; import net.oschina.app.util.TDevice; import android.app.Dialog; import android.content.Context; import android.content.DialogInterface; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.Window; import android.view.WindowManager; import android.widget.TextView; public class WaitDialog extends Dialog { private TextView _messageTv; public WaitDialog(Context context) { super(context); init(context); } public WaitDialog(Context context, int defStyle) { super(context, defStyle); init(context); } protected WaitDialog(Context context, boolean cancelable,DialogInterface.OnCancelListener listener) { super(context, cancelable, listener); init(context); } public static boolean dismiss(WaitDialog dialog) { if (dialog != null) { dialog.dismiss(); return false; } else { return true; } } @Override public void onBackPressed() { super.onBackPressed(); this.dismiss(); } public static void hide(Context context) { if (context instanceof DialogControl) ((DialogControl) context).hideWaitDialog(); } public static boolean hide(WaitDialog dialog) { if (dialog != null) { dialog.hide(); return false; } else { return true; } } private void init(Context context) { setCancelable(false); requestWindowFeature(Window.FEATURE_NO_TITLE); View view = LayoutInflater.from(context).inflate(R.layout.dialog_wait, null); _messageTv = (TextView) view.findViewById(R.id.waiting_tv); setContentView(view); } public static void show(Context context) { if (context instanceof DialogControl) ((DialogControl) context).showWaitDialog(); } public static boolean show(WaitDialog waitdialog) { boolean flag; if (waitdialog != null) { waitdialog.show(); flag = false; } else { flag = true; } return flag; } @Override protected void onCreate(Bundle bundle) { super.onCreate(bundle); if (TDevice.isTablet()) { int i = (int) TDevice.dpToPixel(360F); if (i < TDevice.getScreenWidth()) { WindowManager.LayoutParams params = getWindow() .getAttributes(); params.width = i; getWindow().setAttributes(params); } } } public void setMessage(int message) { _messageTv.setText(message); } public void setMessage(String message) { _messageTv.setText(message); } public void hideMessage() { _messageTv.setVisibility(View.GONE); } }
相关推荐
【oschina-app】是中国开源社区OSChina.net...通过研究oschina-app的源码,开发者可以学习到如何在Android平台上构建一个功能完备的应用,同时掌握各种最佳实践和技术,这对于提升个人技能和解决实际问题非常有帮助。
通过深入学习和分析OSChina Android客户端的源码,你不仅能掌握Android开发的基本技巧,还能了解到一些高级特性和最佳实践,对于提升自己的Android开发能力大有裨益。在实际操作中,你可以模仿并运用这些知识到自己...
【oschina android 客户端源码】是一个公开的项目,旨在为开发者提供一个学习和研究Android应用开发的优秀实例。这个源码库包含了OSChina.net Android客户端的完整源代码,展示了一个成熟、功能完善的移动应用是如何...
【描述】"oschina android app code" 指的是该应用的源码,对于开发者而言,这是一个学习和研究Android应用开发的宝贵资源。通过分析源码,开发者可以深入理解如何在Android平台上构建一个完整的社交网络应用,包括...
【Android OSChina-Android-App源码分析】 这个压缩包文件"android oschina-android-app源码.rar"包含的是OSChina Android应用的源代码,OSChina是中国知名的开源技术社区,其官方Android应用集成了最新的开源技术...
【标题】"OSChina Android 客户端源码"揭示了这是一个开源项目,专注于为OSChina网站构建Android应用的客户端程序。OSChina是中国最大的开源技术社区,提供最新的开源资讯、项目托管服务以及丰富的技术交流平台。这...
【oschina的Android客户端源码】是一份针对中国开源社区OSChina.net的移动应用的源代码,主要面向Android操作系统。这份源代码对于开发者而言是一份宝贵的资源,它提供了深入理解Android应用开发、学习最佳实践以及...
总的来说,"oschina-android-app(开源中国)"是一个全面展示Android应用开发的实例,通过对源码的研究,开发者不仅可以掌握Android开发的基本技能,还能了解到实际项目中的最佳实践,对个人能力提升大有裨益。
【Android应用源码之oschina-android-app(开源中国)】是一个专门为Android开发者提供的学习资源,它包含了开源中国官方Android应用程序的源代码。这个项目对于深入理解Android应用开发、熟悉开源中国的功能实现...
【Android源码——oschina-android-app(开源中国)】是一个包含开源中国Android应用程序的源代码压缩包。这个项目是开源的,允许开发者深入研究和学习Android应用开发的实践技巧和最佳实践。通过分析这个项目的源...
《安卓Android源码解析——oschina-app》 在移动开发领域,Android系统因其开源特性而备受开发者喜爱。本文将深入探讨“oschina-android-app”这一特定的安卓应用源码,帮助开发者理解其背后的架构设计、功能实现...
首先,我们要明确的是,"oschina"是知名的中文开源技术平台,其Android客户端旨在为用户提供便捷的开源资讯浏览、项目管理和讨论交流等功能。源码的开放,让我们得以窥见一个成熟应用的内部运作机制。 在源码中,...
【Android应用源码之oschina-android-app(开源中国)】是一个专门为IT计算机专业学生和开发者提供的毕业设计资源,它包含了开源中国(OSChina)的Android应用程序的源代码。这个项目对于那些想要深入理解Android...
oschina开源中国Android源码v2.71
本篇将详细介绍“oschina-android-app”这一开源项目的相关知识点。 一、Android应用开发基础 在Android平台上开发应用,首先需要掌握Java或Kotlin编程语言。开源中国Android应用是用Java编写的,因此对Java基础有...
"安卓Android源码——oschina-android-app(开源中国).zip" 这个标题表明我们讨论的是一个关于安卓应用的源代码,具体是开源中国的Android客户端应用的源码。开源中国是一个知名的社区,专注于分享和交流开源技术,...
"oschina-android-app"是一个专为开源中国(oschina.net)设计和开发的Android手机客户端应用。这个项目展示了如何将一个在线社区的众多功能适配到移动设备上,为用户提供便捷的开源技术资讯、代码分享、博客阅读以及...