文檔格式(1.標題格式:標題2;2.字體格式:arial;3.字體大小:正文-中)
1. 代碼中爲textView設置drawableleft
a. 在佈局文件中設置:
<span style="font-size:18px;">android:drawableLeft="@drawable/icon"</span>
b.代碼中設置
<span style="font-size:18px;">Drawable drawable= getResources().getDrawable(R.drawable.drawable);
/// 這一步必須要做,否則不會顯示.
drawable.setBounds(0, 0, drawable.getMinimumWidth(), drawable.getMinimumHeight());
myTextview.setCompoundDrawables(drawable,null,null,null);</span>
c.代碼中使用textView的函數
<span style="font-size:18px;">public void setCompoundDrawablesWithIntrinsicBounds (Drawable left,
Drawable top, Drawable right, Drawable bottom)</span>
2. 佈局文件設置textView超過行數後滾動顯示
設置你的TextView的屬性:
<span style="font-size:18px;">android:maxLines = "AN_INTEGER"
android:scrollbars = "vertical"</span>
然後在你的代碼中用:
yourTextView.setMovementMethod(new ScrollingMovementMethod())
它可以自由的滾動了。
3. 更新模塊的實現(摘自:http://android.chinatarena.com/xxzl/1578.html)
我們看到很多Android應用都具有自動更新功能,用戶一鍵就可以完成軟件的升級更新。得益於Android系統的軟件包管理和安裝機制,這一功能實現起來相當簡單,下面我們就來實踐一下。首先給出界面效果:1. 準備知識
在AndroidManifest.xml裏定義了每個Android apk的版本標識:
<span style="font-size:18px;"><manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.myapp"
android:versionCode="1"
android:versionName="1.0.0"></span>
其中,android:versionCode和android:versionName兩個字段分別表示版本代碼,版本名稱。versionCode是整型數字,versionName是字符串。由於version是給用戶看的,不太容易比較大小,升級檢查時,可以以檢查versionCode爲主,方便比較出版本的前後大小。
那麼,在應用中如何讀取AndroidManifest.xml中的versionCode和versionName呢?可以使用PackageManager的API,參考以下代碼:
<span style="font-size:18px;"> public static int getVerCode(Context context) {
int verCode = -1;
try {
verCode = context.getPackageManager()
.getPackageInfo("com.myapp", 0).versionCode;
} catch (NameNotFoundException e) {
Log.e(TAG, e.getMessage());
}
return verCode;
}
public static String getVerName(Context context) {
String verName = "";
try {
verName = context.getPackageManager()
.getPackageInfo("com.myapp", 0).versionName;
} catch (NameNotFoundException e) {
Log.e(TAG, e.getMessage());
}
return verName;
}</span>
或者在AndroidManifest中將android:versionName="1.2.0"寫成android:versionName="@string/app_versionName",然後在values/strings.xml中添加對應字符串,這樣實現之後,就可以使用如下代碼獲得版本名稱:
<span style="font-size:18px;">public static String getVerName(Context context) {
String verName = context.getResources()
.getText(R.string.app_versionName).toString();
return verName;
}</span>
同理,apk的應用名稱可以這樣獲得:
<span style="font-size:18px;">public static String getAppName(Context context) {
String verName = context.getResources().getText(R.string.app_name)
.toString();
return verName;
}</span>
2. 版本檢查
在服務端放置最新版本的apk文件,如:http://localhost/myapp/myapp.apk
同時,在服務端放置對應此apk的版本信息調用接口或者文件,如:http://localhost/myapp/ver.json
ver.json中的內容爲:
<span style="font-size:18px;">{
"appname": "jtapp12",
"apkname": "jtapp-12-updateapksamples.apk",
"verName": 1.0.1,
"verCode": 2
}</span>
然後,在手機客戶端上進行版本讀取和檢查:
<span style="font-size:18px;">private boolean getServerVer() {
try {
String verjson = NetworkTool.getContent(Config.UPDATE_SERVER
+ Config.UPDATE_VERJSON);
JSONArray array = new JSONArray(verjson);
if (array.length() > 0) {
JSONObject obj = array.getJSONObject(0);
try {
newVerCode = Integer.parseInt(obj.getString("verCode"));
newVerName = obj.getString("verName");
} catch (Exception e) {
newVerCode = -1;
newVerName = "";
return false;
}
}
} catch (Exception e) {
Log.e(TAG, e.getMessage());
return false;
}
return true;
}</span>
比較服務器和客戶端的版本,並進行更新操作。
<span style="font-size:18px;">if (getServerVerCode()) {
int vercode = Config.getVerCode(this); // 用到前面第一節寫的方法
if (newVerCode > vercode) {
doNewVersionUpdate(); // 更新新版本
} else {
notNewVersionShow(); // 提示當前爲最新版本
}
}</span>
詳細方法:
<span style="font-size:18px;">private void notNewVersionShow() {
int verCode = Config.getVerCode(this);
String verName = Config.getVerName(this);
StringBuffer sb = new StringBuffer();
sb.append("當前版本:");
sb.append(verName);
sb.append(" Code:");
sb.append(verCode);
sb.append(",/n已是最新版,無需更新!");
Dialog dialog = new AlertDialog.Builder(Update.this).setTitle("軟件更新")
.setMessage(sb.toString())// 設置內容
.setPositiveButton("確定",// 設置確定按鈕
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog,
int which) {
finish();
}
}).create();// 創建
// 顯示對話框
dialog.show();
}
private void doNewVersionUpdate() {
int verCode = Config.getVerCode(this);
String verName = Config.getVerName(this);
StringBuffer sb = new StringBuffer();
sb.append("當前版本:");
sb.append(verName);
sb.append(" Code:");
sb.append(verCode);
sb.append(", 發現新版本:");
sb.append(newVerName);
sb.append(" Code:");
sb.append(newVerCode);
sb.append(", 是否更新?");
Dialog dialog = new AlertDialog.Builder(Update.this)
.setTitle("軟件更新")
.setMessage(sb.toString())
// 設置內容
.setPositiveButton("更新",// 設置確定按鈕
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog,
int which) {
pBar = new ProgressDialog(Update.this);
pBar.setTitle("正在下載");
pBar.setMessage("請稍候...");
pBar.setProgressStyle(ProgressDialog.STYLE_SPINNER);
downFile(Config.UPDATE_SERVER
+ Config.UPDATE_APKNAME);
}
})
.setNegativeButton("暫不更新",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,
int whichButton) {
// 點擊"取消"按鈕之後退出程序
finish();
}
}).create();// 創建
// 顯示對話框
dialog.show();
}</span>
4. 下載模塊
注,本部分參考了前人的相關實現(http://www.apkbus.com/android-14576-1-1.html)
<span style="font-size:18px;">public void download() {
mNotifyManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mBuilder = new NotificationCompat.Builder(this);
String appName = getString(getApplicationInfo().labelRes);
int iconId = getApplicationInfo().icon;
mBuilder.setContentTitle(appName).setSmallIcon(iconId);
String urlStr = intent.getStringExtra(APK_DOWNLOAD_URL);
InputStream in = null;
FileOutputStream out = null;
try {
URL url = new URL(urlStr);
HttpURLConnection urlConnection = (HttpURLConnection) url
.openConnection();
urlConnection.setRequestMethod("GET");
urlConnection.setDoOutput(false);
urlConnection.setConnectTimeout(10 * 1000);
urlConnection.setReadTimeout(10 * 1000);
urlConnection.setRequestProperty("Connection", "Keep-Alive");
urlConnection.setRequestProperty("Charset", "UTF-8");
urlConnection
.setRequestProperty("Accept-Encoding", "gzip, deflate");
urlConnection.connect();
long bytetotal = urlConnection.getContentLength();
long bytesum = 0;
int byteread = 0;
in = urlConnection.getInputStream();
File dir = StorageUtils.getCacheDirectory(this);
String apkName = urlStr.substring(urlStr.lastIndexOf("/") + 1,
urlStr.length());
File apkFile = new File(dir, apkName);
out = new FileOutputStream(apkFile);
byte[] buffer = new byte[BUFFER_SIZE];
int oldProgress = 0;
while ((byteread = in.read(buffer)) != -1) {
bytesum += byteread;
out.write(buffer, 0, byteread);
int progress = (int) (bytesum * 100L / bytetotal);
// 如果進度與之�?進度相等,則�?更新,如果更新太頻�?,�?�則會�?�?界�?��?�頓
if (progress != oldProgress) {
updateProgress(progress);
// updateProgressByBroadCast(progress,apkFile.getAbsolutePath());
}
oldProgress = progress;
}
// 下載完�?
mBuilder.setContentText("下載完成").setProgress(0, 0, false);
Intent installAPKIntent = new Intent(Intent.ACTION_VIEW);
// 如果沒有設置SDCard寫�?��?,或者沒有sdcard,apk文件�?存在內存中,�?��?授予�?��?�?能安�?
String[] command = { "chmod", "777", apkFile.toString() };
ProcessBuilder builder = new ProcessBuilder(command);
builder.start();
installAPKIntent.setDataAndType(Uri.fromFile(apkFile),
"application/vnd.android.package-archive");
// installAPKIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// installAPKIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
// installAPKIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
installAPKIntent, PendingIntent.FLAG_UPDATE_CURRENT);
mBuilder.setContentIntent(pendingIntent);
Notification noti = mBuilder.build();
noti.flags = android.app.Notification.FLAG_AUTO_CANCEL;
mNotifyManager.notify(0, noti);
Intent installBroadCast = new Intent(
InstallApkReceiver.ACTION_INSTALL_APK);
installBroadCast.putExtra(InstallApkReceiver.EXTRA_APKPATH,
apkFile.getAbsolutePath());
sendBroadcast(installBroadCast);
} catch (Exception e) {
Log.e(TAG, "download apk file error", e);
} finally {
if (out != null) {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (in != null) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}</span>
4.登陸時記住密碼和自動登陸
首次登陸時,如果用戶勾選中記住密碼和自動登陸,則使用sharedpreference保存當前用戶輸入的信息,在保存密碼時使用md5加密方式進行加密,以保證用戶信息不被泄露,下次登陸時從sharedpreference中獲取之前的賬戶信息。項目工程地址(http://download.csdn.net/detail/u012049463/9427137)<span style="font-size:18px;">//判斷記住密碼多選框的狀態
SharedPreferences sp = this.getSharedPreferences("userInfo", Context.MODE_WORLD_READABLE);
if(sp.getBoolean("ISCHECK", false))
{
//設置默認是記錄密碼狀態
rem_pw.setChecked(true);
userName.setText(sp.getString("USER_NAME", ""));
password.setText(sp.getString("PASSWORD", ""));
//判斷自動登陸多選框狀態
if(sp.getBoolean("AUTO_ISCHECK", false))
{
//設置默認是自動登錄狀態
auto_login.setChecked(true);
//do loginTask
doLoginTask();
//跳轉界面
Intent intent = new Intent(LoginActivity.this,LogoActivity.class);
LoginActivity.this.startActivity(intent);
}
}
// 登錄監聽事件 現在默認爲用戶名爲:liu 密碼:123
btn_login.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
userNameValue = userName.getText().toString();
passwordValue = password.getText().toString();
if(userNameValue.equals("liu")&&passwordValue.equals("123"))
{
Toast.makeText(LoginActivity.this,"登錄成功", Toast.LENGTH_SHORT).show();
//登錄成功和記住密碼框爲選中狀態才保存用戶信息
if(rem_pw.isChecked())
{
//記住用戶名、密碼、
Editor editor = sp.edit();
editor.putString("USER_NAME", userNameValue);
editor.putString("PASSWORD",passwordValue);
editor.commit();
}
//跳轉界面
Intent intent = new Intent(LoginActivity.this,LogoActivity.class);
LoginActivity.this.startActivity(intent);
//finish();
}else{
Toast.makeText(LoginActivity.this,"用戶名或密碼錯誤,請重新登錄", Toast.LENGTH_LONG).show();
}
}
});
//監聽記住密碼多選框按鈕事件
rem_pw.setOnCheckedChangeListener(new OnCheckedChangeListener() {
public void onCheckedChanged(CompoundButton buttonView,boolean isChecked) {
if (rem_pw.isChecked()) {
System.out.println("記住密碼已選中");
sp.edit().putBoolean("ISCHECK", true).commit();
}else {
System.out.println("記住密碼沒有選中");
sp.edit().putBoolean("ISCHECK", false).commit();
}
}
});
//監聽自動登錄多選框事件
auto_login.setOnCheckedChangeListener(new OnCheckedChangeListener() {
public void onCheckedChanged(CompoundButton buttonView,boolean isChecked) {
if (auto_login.isChecked()) {
System.out.println("自動登錄已選中");
sp.edit().putBoolean("AUTO_ISCHECK", true).commit();
} else {
System.out.println("自動登錄沒有選中");
sp.edit().putBoolean("AUTO_ISCHECK", false).commit();
}
}
});</span>
5.使用開源框架universal-imageLoader
知識儲備(http://www.2cto.com/kf/201412/361295.html#SOHUCS)
使用該第三方加載圖片的框架需要的步驟:
1.下載universal-imageLoader的jar包或源碼,放到libs目錄或引入到需要使用的項目中。
2.在manifest.xml文件中設置需要的權限
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.INTERNET"/>
3.在應用中配置ImageConfiguration參數。
imageLoader = ImageLoader.getInstance();
imageLoader.init(configuration);
4.使用,由於我們將其再次簡單的封裝成了一個方便使用的util類,在使用時我們調用如下代碼即可:
ImageLoaderUtil.getInstance(ActMediaShow.this).displayImg(
imageUrl, mediaTypeImageView,ImageLoaderUtil.getOptions(),null);
SimpleImageLoadingListener imgLoadListener = new SimpleImageLoadingListener() {
@Override
public void onLoadingStarted(String imageUri, View view) {
spinner.setVisibility(View.VISIBLE);
}
@Override
public void onLoadingFailed(String imageUri, View view,
FailReason failReason) {
String message = null;
switch (failReason.getType()) {
case IO_ERROR:
message = "Input/Output error";
break;
case DECODING_ERROR:
message = "Image can't be decoded";
break;
case NETWORK_DENIED:
message = "Downloads are denied";
break;
case OUT_OF_MEMORY:
message = "Out Of Memory error";
break;
case UNKNOWN:
message = "Unknown error";
break;
}
Toast.makeText(ActMediaShow.this, message,
Toast.LENGTH_SHORT).show();
spinner.setVisibility(View.GONE);
}
@Override
public void onLoadingComplete(String imageUri,
View view, Bitmap loadedImage) {
spinner.setVisibility(View.GONE);
}
};
ImageLoaderUtil.getInstance(ActMediaShow.this).displayImg(
medias.get(position).getImgTypeUri(), mediaTypeImageView,ImageLoaderUtil.getOptions(),null);
下面是我簡單封裝的一個調用的util
package com.zondy.jinfeng.util;
import java.io.File;
import android.content.Context;
import android.view.View;
import android.widget.ImageView;
import android.widget.Toast;
import com.nostra13.universalimageloader.cache.disc.impl.UnlimitedDiskCache;
import com.nostra13.universalimageloader.cache.disc.naming.Md5FileNameGenerator;
import com.nostra13.universalimageloader.cache.memory.impl.UsingFreqLimitedMemoryCache;
import com.nostra13.universalimageloader.core.DisplayImageOptions;
import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;
import com.nostra13.universalimageloader.core.assist.ImageScaleType;
import com.nostra13.universalimageloader.core.assist.QueueProcessingType;
import com.nostra13.universalimageloader.core.download.BaseImageDownloader;
import com.nostra13.universalimageloader.core.listener.ImageLoadingListener;
import com.nostra13.universalimageloader.utils.StorageUtils;
import com.zondy.jinfeng.R;
public class ImageLoaderUtil {
ImageLoader imageLoader;
File cacheDir;// 緩存文件路徑
ImageLoaderConfiguration configuration;
private static ImageLoaderUtil instance = null;
private ImageLoaderUtil(Context context) {
cacheDir = StorageUtils.getOwnCacheDirectory(context,
"FreeMeso/imageCache");
configuration = new ImageLoaderConfiguration.Builder(context)
.memoryCacheExtraOptions(1000, 1000)
// max width, max height,即保存的每個緩存文件的最大長寬
.threadPoolSize(3)
// 線程池內加載的數量
.threadPriority(Thread.NORM_PRIORITY - 2)
// 下載圖片的線程優先級
.denyCacheImageMultipleSizesInMemory()
.diskCacheFileNameGenerator(new Md5FileNameGenerator())
// 將保存的時候的URI名稱用MD5 加密
.memoryCache(new UsingFreqLimitedMemoryCache(2 * 1024 * 1024))
// You can pass your own memory cache
// implementation/你可以通過自己的內存緩存實現
.memoryCacheSize(2 * 1024 * 1024)
// 內存緩存的最大值
.diskCacheSize(50 * 1024 * 1024)
// 50 Mb sd卡(本地)緩存的最大值
.tasksProcessingOrder(QueueProcessingType.LIFO)
// 由原先的discCache -> diskCache
.diskCache(new UnlimitedDiskCache(cacheDir))
// 自定義緩存路徑
.imageDownloader(
new BaseImageDownloader(context, 5 * 1000, 30 * 1000))
.writeDebugLogs() // Remove for release app
.build();
// Initialize ImageLoader with configuration.
imageLoader = ImageLoader.getInstance();
imageLoader.init(configuration);
}
/**
* 單例獲取ImageLoader實例
*
* @param context
* @return
*/
public static ImageLoaderUtil getInstance(Context context) {
if (instance == null) {
instance = new ImageLoaderUtil(context);
}
return instance;
}
/**
* displayImg
*
* @param uri
* @param imageView
* @param options
* @param imageLoaderListener
*/
public void displayImg(String uri, ImageView imageView,
DisplayImageOptions options,
ImageLoadingListener imageLoaderListener) {
if (options != null && imageLoaderListener != null) {
imageLoader.displayImage(uri, imageView, options,
imageLoaderListener);
} else if (options != null) {
imageLoader.displayImage(uri, imageView, options, null);
} else if (imageLoaderListener != null) {
imageLoader.displayImage(uri, imageView, null, imageLoaderListener);
} else {
imageLoader.displayImage(uri, imageView, null, null);
}
}
/**
* image display options
*
* @return
*/
public static DisplayImageOptions getOptions() {
DisplayImageOptions options = new DisplayImageOptions.Builder()
.showImageOnLoading(R.drawable.ic_empty_img) // 設置圖片下載期間顯示的圖片
.showImageForEmptyUri(R.drawable.ic_empty_img) // 設置圖片Uri爲空或是錯誤的時候顯示的圖片
.showImageOnFail(R.drawable.ic_empty_img) // 設置圖片加載或解碼過程中發生錯誤顯示的圖片
.imageScaleType(ImageScaleType.EXACTLY)//設置 圖片的縮放方式 縮放類型
.cacheInMemory(true) // 設置下載的圖片是否緩存在內存中
.cacheOnDisk(true) // 設置下載的圖片是否緩存在SD卡中
// .displayer(new RoundedBitmapDisplayer(5)) // 設置成圓角圖片,在有的手機裏面會報錯,所以先註釋掉
.build();
return options;
}
public void clearImageCache() {
imageLoader.clearMemoryCache(); // 清除內存緩存
imageLoader.clearDiskCache(); // 清除本地緩存
}
}