记录Android开发过程中遇到的问题以及解决方案
doInBackground
方法不能运行的问题突然发现AsyncTask().execute();不能执行了。
原因:由于Android不同的版本中AsyncTask的行为不一致造成的。
Donut (Android:1.6 API:4) 以前task是串行执行的,Donut 到**Gingerbread (Android:2.3 API:9)**版本之间task是并行执行的。从 **Honeycomb (Android:3.0 API:11)**开始,task又改回了串行执行,不过SDK提供了一个新的用于并行执行的方法AsyncTask().executeOnExecutor(Executor)
解决方法:根据不同的版本选择不同的执行方法
AsyncTask myTask = new AsyncTask() { ... };
if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.HONEYCOMB)
myTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
else
myTask.execute();
问题:使用Glide设置图片的ImageView不能设置Tag,报You must not call setTag() on a view Glide is targeting 的错误
解决方法:
在 src/main/values/目录中新建一个 ids.xml 文件,添加一条 id数据:
然后在App中的onCreate方法中
public class App extends Application {
@Override
public void onCreate() {
super.onCreate();
ViewTarget.setTagId(R.id.glide_tag);
}
}
问题:当包含fragment的Activity 由于各种原因被系统回收后,打开此页面出现奔溃问题
原因:当FragmentActivity
被系统回收时,其会调用onSaveInstanceState
保存Fragment对象。在系统重新创建FragmentActivity
时系统会恢复保存的Fragment
,但是如果我们在FragmentActivity
重新执行生命周期的时候重新生成Fragment
对象附加到该FragmentActivity
,系统恢复的Fragment
和Activity
失去关联,所以出错。
解决方法:
第一种:在fragment
中重写onSaveInstanceState
方法,不做实现,阻止系统自动保存.
@Override
public void onSaveInstanceState(Bundle outState)
{
//此重写不对此fragment做保存,防止恢复时候出现的崩溃
}
第二种:在Activity
重新创建时,移除保存的fragment
对象
static final String FRAGMENTS_TAG = "android:support:fragments";
@Override
protected void onCreate(Bundle savedInstanceState) {
if (savedInstanceState != null) {
savedInstanceState.putParcelable(FRAGMENTS_TAG, null);
}
super.onCreate(savedInstanceState);
}
第三种:自己保存fragment
的变量,然后在恢复时候重新手动恢复
问题:需要达到手指轻拨页面实现翻页
解决方法:
通过查看viewpager的源码,找到如下方法。此方法在onTouchEvent
事件中的MotionEvent.ACTION_UP
时执行,作用是决定要翻到的页面。如if滑动距离mFlingDistance
与滑动速度mMinimumVelocity
共同决定了快速拨动页面是否翻页的逻辑。我们只需要调节这两个参数即可。else是当慢慢滑动页面触发翻页的逻辑,如代码所示此种情况,需要滑动页面的0.6倍以上,放手页面即可翻转。
private int determineTargetPage(int currentPage, float pageOffset, int velocity, int deltaX) {
int targetPage;
if (Math.abs(deltaX) > mFlingDistance && Math.abs(velocity) > mMinimumVelocity) {
targetPage = velocity > 0 ? currentPage : currentPage + 1;
} else {
final float truncator = currentPage >= mCurItem ? 0.4f : 0.6f;
targetPage = currentPage + (int) (pageOffset + truncator);
}
if (mItems.size() > 0) {
final ItemInfo firstItem = mItems.get(0);
final ItemInfo lastItem = mItems.get(mItems.size() - 1);
// Only let the user target pages we have items for
targetPage = Math.max(firstItem.position, Math.min(targetPage, lastItem.position));
}
return targetPage;
}
滑动距离mFlingDistance
与滑动速度mMinimumVelocity
是 私有字段,我们可以使用反射的方式来改变其值,这两个值都只在 void initViewPager()
中设置,而这个函数是在ViewPager
的构造函数中调用的。
所以我们可以定义个扩展至ViewPager
的类,在构造函数中设置这两个值
public MyViewPager(Context context, AttributeSet attrs)
{
super(context, attrs);
final float density = context.getResources().getDisplayMetrics().density;
try {
//修改滑动灵敏度
Field minVelocity = ViewPager.class.getDeclaredField("mMinimumVelocity");
minVelocity.setAccessible(true);
minVelocity.setInt(this,(int)(20*density));
Field minDistance = ViewPager.class.getDeclaredField("mFlingDistance");
minDistance.setAccessible(true);
minDistance.setInt(this,(int)(5*density));
} catch (Exception e) {
e.printStackTrace();
}
}
如果觉得灵敏度仍然不够,可以以同样的方法来设置viewpager的滑动阈值mTouchSlop
try
{
Field field = ViewPager.class.getDeclaredField("mTouchSlop");
field.setAccessible(true);
field.setInt(this, 6);
} catch (NoSuchFieldException e)
{
e.printStackTrace();
} catch (IllegalAccessException e)
{
e.printStackTrace();
} catch (Exception e)
{
e.printStackTrace();
}
问题:在ScrollView
包裹的LinearLayout
中动态插入了一个View后,ScrollView
自动滚动到了底部,而我们希望ScrollView
仍然位于顶部
解决方法:
给ScrollView
包裹的View
设置上以下两个属性
android:focusable="true"
android:focusableInTouchMode="true"
例如
...
由于Android7.0加强了文件的安全性,所以我们需要使用到FileProvider
。
第一步:在AndroidManifest.xml文件中加入权限
第二步:在AndroidManifest.xml文件中加入自己的FileProvider
在main->res->xml目录下创建一个xml文件rc_file_path.xml
,文件内容为:
在AndroidManifest
文件中加入provider
第三步:安装
public void installAPK(File file, Activity mAct) {
String authority = "ss007.top.downloadwithretrofit.FileProvider";
mAct.startActivity(getInstallAppIntent(file, authority, true));
}
private Intent getInstallAppIntent(final File file,
final String authority,
final boolean isNewTask) {
if (file == null) return null;
Intent intent = new Intent(Intent.ACTION_VIEW);
Uri data;
String type = "application/vnd.android.package-archive";
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
data = Uri.fromFile(file);
} else {
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
data = FileProvider.getUriForFile(MainActivity.this, authority, file);
}
intent.setDataAndType(data, type);
return getIntent(intent, isNewTask);
}
private Intent getIntent(final Intent intent, final boolean isNewTask) {
return isNewTask ? intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) : intent;
}
当我们不希望第三方库声明在AndroidMenifest.xml文件中的某个权限合并到我们App里时,可以使用
tools:node=”remove”
压制它,如下所示