<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">
</span>
<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">1.启动APP时闪退,日志错误显示为 </span>
<span style="font-size:14px;">java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.ImageButton.setOnClickListener(android.view.View$OnClickListener)' on a null object reference</span>
最终在StackOverFlow中找到原因及解决办法,原因是我在主Activity中设置点击事件的这个ImageButton是在我的ListView的单独的Item布局文件中,即ListView和Item是两个Layout的xml,而主Activity中 setContentView(R.layout.activity_phone_list); 是设置ListView所在的布局文件为Activity的显示界面,所以其实主Activity是获取不到Item布局文件中定义的那个ImageButton的引用的,自然当设置监听事件时会报null object reference。
下图为StackOverFlow 中的回答,箭头部分表示要从接收该布局文件的Activity中获得该组件。
还有另一位博主的一篇文章讲为ListView每个Item上面的按钮添加事件,地址为 为ListView每个Item上面的按钮添加事件,其中的第二种方法值得借鉴。
2.ListView的Item无法响应点击事件(不能获得焦点can't take focus),因为我在Item布局文件中加入了一个ImageButton,而它默认会主动获得焦点
“ 通常,我们会自定义 ListView Item 的 Layout,当自定义的 Item Layout 含有主动获得焦点的控件时(例如 Button, ImageButton 等),那么我们就没办法点击 ListView Item 自己的点击事件。
解决办法很简单,只要在Item Layout 的根布局中加上 android:descendantFocusability = "blocksDescendants"属性即可。如下方的 Item 布局文件所示:
Java
这里再说说 descendantFocusability 这个属性的作用。
根据 官方说明 ,descendantFocusability 定义了 ViewGroup 和子控件的在获取焦点时的关系。
有下面三种取值:
- beforeDescendants,ViewGroup 会在所有子控件之前获得焦点
- afterDescendants,ViewGroup 会在所有子控件都不需要焦点时获得焦点
- blocksDescendants,ViewGroup会阻断子控件获得焦点。
通常,我们只要把 descendantFocusability 设置为 blocksDescendants,即可解决由于 Item 里的 Button 抢夺焦点导致 Item 本身无法点击的问题。”
以上是网搜到的Item抢占焦点的办法,,然而这样我Item中的ImageButton也不能点击了,我想的是每个item一个点击事件,Item中的ImageButton(Button也适用)有自己单独的点击事件,实现不同的功能,而不是只能点击整个Item一个事件,还没解决,未完待续……
接上面的问题,我看到别人关于item和item中点击事件都生效的一篇文章在Activity中响应ListView内部按钮的点击事件,其中介绍了使用接口回调和使用抽象类回调两种方法,我试了一下抽象类回调然后加上之前的descendantFocusability 设置为 blocksDescendants,成功解决了Item和Item中控件不同的点击响应。
3.如何变相地改变启动页以避免用户每次启动APP时都要登录,有一种解决办法是将用户名密码保存在SharedPreferences里面,然后将加载界面设置为启动页,在加载的时候验证SharedPreferences中用户名密码是否存在并且正确,如果正确则在加载后启动登录后的界面,不是则加载后进入登录界面。
4.loading(加载)页中用线程做一个ImageView的Alpha渐变动画效果然后设置一段时间延迟启动其他界面,如
launch.postDelayed(new Runlaunch(),2500);//设置2.5秒钟延迟执行Runlaunch线程,launch是新建的Handler对象
我直接贴自己的代码吧
private ImageView ivstart1,ivstart2;
static int image_alpha1=255;//第一段动画Alpha值
static int image_alpha2=0;//第二段动画Alpha值
Handler launch;
boolean isrun1=true;//线程是否执行第一段动画
boolean isrun2=false;//线程是否执行第二段动画
private int runtime=0;//用以判断该轮到哪段动画了,变量递增,递增到100时换第二段动画
static boolean isLogin=false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_launch);
init();
ivstart2.setAlpha(image_alpha2);
new Thread(new Runnable() {
@Override
public void run() {
while(isrun1){
try {
Thread.sleep(70);//每次线程睡眠时间70ms
updateAlpha();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
while(isrun2){
try {
Thread.sleep(100);
updateAlpha();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
//接收消息之后更新imageview视图
launch=new Handler(){
public void handleMessage(Message msg){
super.handleMessage(msg);
ivstart1.setAlpha(image_alpha1);
ivstart2.setAlpha(image_alpha2);
ivstart1.invalidate();//刷新视图
ivstart2.invalidate();
}
};
launch.postDelayed(new Runlaunch(),2500);//设置2.5秒钟延迟执行Runlaunch线程
}
private void updateAlpha() {
while(runtime<100){
if (image_alpha1 > 120) {
image_alpha1-=14;
}else{
image_alpha1=0;
isrun1=false;
image_alpha2=100;
}
runtime+=10;
break;
}
while(runtime>=100){
isrun2=true;
if(image_alpha2<200){
image_alpha2+=10;
}else{
image_alpha2=255;
isrun2=false;
}
runtime+=10;
break;
}
launch.sendMessage(launch.obtainMessage()); // 发送需要更新imageview视图的消息-->这里是发给主线程
}
class Runlaunch implements Runnable{
@Override
public void run() {
startActivity(new Intent(LaunchActivity.this,LoginActivity.class));
LaunchActivity.this.finish();
}
}
我这里
是设置了两段渐变动画,就用自己定义的一个runtime变量区分,runtime为0~100时第一段Alpha动画,递增到100时换成第二段Alpha动画。过程是这样的,线程每次先判断布尔值isrun是否为真,是则执行改变Alpha的方法updateAlpha(),方法中每次改变Alpha值时,都要发送需要更新ImageView视图的消息给Handler对象launch,然后launch设置Alpha值并且刷新视图,这样通过每次短时间间隔的刷新ImageView的Alpha值看上去就好像是一个持续的渐变动画了。
5.Android获取系统当前时间
一:
import java.text.SimpleDateFormat;
SimpleDateFormat formatter = new SimpleDateFormat ("yyyy年MM月dd日 HH:mm:ss "); //这部分格式可以自己改,比如<pre name="code" class="java" style="font-size: 14px; line-height: 25.2px;">"yyyy-MM-dd HH时mm分" 这样,在其中插入换行符这些也可以
Date curDate = new Date(System.currentTimeMillis());//获取当前时间 String str = formatter.format(curDate);
二:用android中的Time类
import android.text.format.Time;
Time t=new Time();
t.setToNow();//取得系统时间
String year=t.year+"年"+t.month+"月"+t.monthDay+"日"+" "+t.hour+":"+t.minute+":"+t.second;
如何获取系统时间是12小时制还是24小时制?
ContentResolver cv = getContentResolver();
String strTimeFormat =android.provider.Settings.System.getString(cv,
android.provider.Settings.System.TIME_12_24); //android是小写!
if(strTimeFormat.equals("24"))
{
Log.i("timeformat","24");
}else Log.i("timeformat","12");
6.报错
java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare();
原因及解决办法:
Android basically works on two thread types namely UI thread and background thread. According to android documentation -
Do not access the Android UI toolkit from outside the UI thread to fix this problem, Android offers several ways to access the UI thread from other threads. Here is a list of methods that can help:
Activity.runOnUiThread(Runnable)
View.post(Runnable)
View.postDelayed(Runnable, long)
Now there are various methods to solve this problem. I will explain it by code sample
runOnUiThread
new Thread()
{
public void run()
{
myactivity.this.runOnUiThread(new runnable()
{
public void run()
{
//Do your UI operations like dialog opening or Toast here
}
});
}
}.start();
LOOPER
Class used to run a message loop for a thread. Threads by default do not have a message loop associated with them; to create one, call prepare() in the thread that is to run the loop, and then loop() to have it process messages until the loop is stopped.
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
Looper.loop();
}
AsyncTask
AsyncTask allows you to perform asynchronous work on your user interface. It performs the blocking operations in a worker thread and then publishes the results on the UI thread, without requiring you to handle threads and/or handlers yourself.
public void onClick(View v) {
new CustomTask().execute((Void[])null);
}
private class CustomTask extends AsyncTask<Void, Void, Void> {
protected Void doInBackground(Void... param) {
//Do some work
return null;
}
protected void onPostExecute(Void param) {
//Print Toast or open dialog
}
}
Handler
A Handler allows you to send and process Message and Runnable objects associated with a thread's MessageQueue.
Message msg = new Message();
new Thread()
{
public void run()
{
msg.arg1=1;
handler.sendMessage(msg);
}
}.start();
Handler handler = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
if(msg.arg1==1)
{
//Print Toast or open dialog
}
return false;
}
});
7.报错
android.content.res.Resources android.content.Context.getResources()' on a null object reference
解决办法:为在出错的地方为context处加上上下文,可以是onCreate方法里面构造的时候添加MainActivity.this等Context内容
Bitmap bitmap=downloadImage();
BitmapDrawable bd=new BitmapDrawable(context.getResources(),bitmap);//Create drawable from a bitmap, setting initial target density based on
8.LinearLayout分开布局
我们知道LinearLayout是按照指定的朝向(orientation)顺序地摆放组件的,所以有一种推荐的分开布局方法是在其中加入一个看不见的View,如水平布局中想要左右分开布局,使控件分别在左右两端可以这样
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orietation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="start"
android:text="zzz"/>
<!--加入“隐形”View达到LinearLayout左右布局的目的-->
<View
android:layout_width="0dp"
android:layout_weight="1.0"
android:layout_height="0dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="right"
android:text="yyy" />
</LinearLayout>
看不见的View填充了中间的空白部分。