* 修正金沙中文網搜尋後資料無法開啟的問題
> 如果已經加入書籤者, 請移除後再加入.
Google Play: 小說閱讀器 v1.3.5
java.lang.IllegalStateException: The content of the adapter has changed but ListView did not receive a notification.
Make sure the content of your adapter is not modified from a background thread,
but only from the UI thread. [in ListView(16908298, class android.widget.ListView)
with Adapter(class android.widget.HeaderViewListAdapter)]
} else if (mItemCount != mAdapter.getCount()) {
throw new IllegalStateException("The content of the adapter has changed but "
+ "ListView did not receive a notification. Make sure the content of "
+ "your adapter is not modified from a background thread, but only "
+ "from the UI thread. [in ListView(" + getId() + ", " + getClass()
+ ") with Adapter(" + mAdapter.getClass() + ")]");
}
public void add(T object) {
synchronized (mLock) {
if (mOriginalValues != null) {
mOriginalValues.add(object);
} else {
mObjects.add(object);
}
}
if (mNotifyOnChange) notifyDataSetChanged();
}
import android.content.Context; import android.widget.ArrayAdapter; import java.util.List; public class MyArrayAdapterextends ArrayAdapter { private List mObjects; private int count = 0; private boolean mNotifyOnChange = true; public MyArrayAdapter(Context context, int textViewResourceId, List objects) { super(context, textViewResourceId, objects); mObjects = objects; count = objects.size(); } final public void beginTrans() { setNotifyOnChange(false); mNotifyOnChange = false; } final public void endTrans() { setNotifyOnChange(true); notifyDataSetChanged(); } @Override final public int getCount() { return count; } @Override final public void notifyDataSetChanged() { count = mObjects.size(); mNotifyOnChange = true; super.notifyDataSetChanged(); } @Override final public T getItem(int position) { if (position >= getCount()) { return null; } if (position >= mObjects.size()) { return null; } return super.getItem(position); } }
git tag -d v1.1.1 git push origin :refs/tags/v1.1.1
task('readPasswordFromInput') << {
def console = System.console()
ext.keystorePassword = console.readLine('\n\n\n> Enter keystore password: ')
android.signingConfigs.release.storePassword = ext.keystorePassword
android.signingConfigs.release.keyPassword = ext.keystorePassword
}
tasks.whenTaskAdded { task ->
if (task.name.matches("validateReleaseSigning")) {
task.dependsOn('readPasswordFromInput')
}
}
signingConfigs {
debug {
storeFile file("my-debug-key.keystore")
}
release {
storeFile file("my-release-key.keystore")
storePassword ""
keyAlias "release_key"
keyPassword ""
}
}

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <GridView android:id="@+id/gridview" android:layout_width="match_parent" android:layout_height="wrap_content" android:drawSelectorOnTop="true" android:alwaysDrawnWithCache="false" android:fadeScrollbars="true" android:cacheColorHint="@android:color/transparent" android:numColumns="3" android:columnWidth="160dp"/> </RelativeLayout>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <ImageView android:id="@+id/imageview" android:layout_width="160dp" android:layout_height="240dp" android:layout_centerInParent="true" android:scaleType="centerInside" android:contentDescription="@null"/> </RelativeLayout>
package tw.clotai.picassoexample;
import android.content.Context;
import android.net.Uri;
import android.os.Environment;
import android.util.Log;
import com.squareup.picasso.Loader;
import java.io.*;
import java.math.BigInteger;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
/**
* A {@link com.squareup.picasso.Loader} which uses {@link java.net.HttpURLConnection} to chapter_main images. A disk cache of 10MB
* will automatically be installed in the application's cache directory, when available.
*/
public class MyURLConnectionLoader implements Loader {
private static final String HASH_ALGORITHM = "MD5";
private static final int RADIX = 10 + 26;
private final Context context;
public MyURLConnectionLoader(Context context) {
this.context = context.getApplicationContext();
}
protected HttpURLConnection openConnection(String path) throws IOException {
return (HttpURLConnection) new URL(path).openConnection();
}
@Override
public Response load(Uri uri, boolean b) throws IOException {
Response res = null;
String cacahePath = PicassoHelper.getCachePath(context);
if (cacahePath == null) {
return res;
}
String url = uri.toString();
if (url == null) {
return res;
}
String key = generateUniqueID(url);
if (key == null) {
return res;
}
if (!url.startsWith("http")) {
File f = new File(url);
if (f.exists()) {
FileInputStream fin = new FileInputStream(f);
res = new Response(fin, true);
}
return res;
}
File f = new File(cacahePath, key);
if (f.exists()) {
FileInputStream fin = new FileInputStream(f);
res = new Response(fin, true);
} else {
InputStream in = null;
try {
HttpURLConnection connection = openConnection(url);
connection.setRequestProperty("User-Agent",
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.91 Safari/537.11");
connection.setRequestProperty("Accept-Language", "en-US,en;q=0.8");
connection.setUseCaches(true);
connection.setDoInput(true);
connection.setConnectTimeout(30000);
connection.setReadTimeout(30000);
connection.setRequestMethod("GET");
connection.connect();
in = connection.getInputStream();
copyToFile(in, f);
} finally {
if (in != null) {
in.close();
}
}
if (f.exists()) {
FileInputStream fin = new FileInputStream(f);
res = new Response(fin, false);
}
}
return res;
}
private String generateUniqueID(String url) {
StringBuilder sb = new StringBuilder();
byte[] md5;
BigInteger bi = null;
try {
MessageDigest digest = MessageDigest.getInstance(HASH_ALGORITHM);
digest.update(url.getBytes());
md5 = digest.digest();
bi = new BigInteger(md5).abs();
} catch (NoSuchAlgorithmException e) {
}
if (bi == null) {
return null;
}
sb.append(bi.toString(RADIX));
return sb.toString();
}
private void copyToFile(InputStream in, File dest) throws IOException {
FileOutputStream fos = null;
BufferedInputStream bin = null;
BufferedOutputStream bout = null;
try {
fos = new FileOutputStream(dest);
bin = new BufferedInputStream(in, 8192);
bout = new BufferedOutputStream(fos, 8192);
byte[] rdata = new byte[8192];
int count = 0;
while ((count = bin.read(rdata)) != -1) {
bout.write(rdata, 0, count);
}
bout.flush();
} finally {
if (bin != null) {
bin.close();
}
if (fos != null) {
if (fos.getFD() != null) {
fos.getFD().sync();
}
}
if (bout != null) {
bout.close();
}
if (fos != null) {
fos.close();
}
}
}
}
public static PicassoHelper getInstance(Context c) {
if (helper == null) {
if (c == null) {
return null;
}
synchronized (PicassoHelper.class) {
if (helper == null) {
helper = new PicassoHelper(c);
}
}
}
return helper;
}
private PicassoHelper(Context c) {
mContext = c.getApplicationContext();
Picasso.Builder builder = new Picasso.Builder(c);
builder.loader(new MyURLConnectionLoader(c));
mPicasso = builder.build();
mPicasso.setDebugging(false);
PicassoHelper.getCachePath(mContext);
}
public void load(String url, ImageView v) {
v.setImageResource(R.drawable.ic_launcher);
if (url == null) {
return;
}
mPicasso.load(url)
.resize(160, 240)
.error(R.drawable.ic_launcher)
.centerCrop()
.into(v);
}
